graphql-jsを利用してGraphQL形式のAPIを実装してみます。「Queryによるデータ取得」「リゾルバの設定」「スキーマ定義」「ネストしたデータの設定」「Mutationによる生成、削除」を実装して動作確認します。
目次
インストール
今回利用するパッケージをインストールします。
$ npm install graphql express express-graphql --save
例1
( クエリ言語, リゾルバ )
コード
const express = require('express')
const express_graphql = require('express-graphql')
const { buildSchema } = require('graphql')
const app = express()
app.use('/graphql', express_graphql({
schema: buildSchema('type Query { wakuwaku: String }'),
// Resolver
rootValue: {
wakuwaku: () => 'Hello World!'
},
graphiql: true
}))
app.listen(5000, () => console.log('Example app listening on port 5000!'))
起動
$ node index.js
Example app listening on port 5000!
リクエスト実行
起動後、 http://localhost:5000/graphql
にアクセスすると、GraphiQLの画面が開きます。ここでクエリの動作確認をすることができます。
リクエスト結果です。
curl
でも確認できます。
$ curl -X POST \
> -H "Content-Type: application/json" \
> -d '{"query": "{ wakuwaku }"}' \
> http://localhost:5000/graphql
{"data":{"wakuwaku":"Hello World!"}}
例2
( スキーマ定義, 引数の受け取り )
コード
const express = require('express')
const express_graphql = require('express-graphql')
const { buildSchema } = require('graphql')
const schema = buildSchema(`
type Query {
post(id: Int!): Post
posts: [Post]
}
type Post {
id: Int
title: String
author: String
content: String
message: Message
}
`)
const dummyPosts = [
{ id: 1, title: 'titleXXXX', author: 'yamada', content: 'abcdefg' },
{ id: 2, title: 'titleYYYY', author: 'suzuki', content: '1234567' },
{ id: 3, title: 'titleZZZZ', author: 'tanaka', content: 'ABCDEFG' }
]
const root = {
post: args => {
const id = args.id
return dummyPosts.filter(post => post.id == id)[0]
},
posts: () => dummyPosts
}
const app = express()
app.use('/graphql', express_graphql({
schema: schema,
rootValue: root,
graphiql: true
}))
app.listen(5000, () => console.log('Example app listening on port 5000!'))
- スキーマ言語( SDL )でリソース単位のtype(
type Post
)を指定しています。 - リゾルバで引数を受け取れるようにしています。
リクエスト実行(1件取得)
query getSinglePost($postID: Int!) {
post(id: $postID) {
title
author
}
}
{
"postID": 3
}
指定Postの「title」「author」を取得してます。
リクエスト実行(1件取得 curl利用)
curlでリクエストする場合、以下のようになります。
$ curl -XPOST -H "Content-Type:application/graphql" -d '
> query getSinglePost {
> post(id: 3) {
> title
> author
> }
> }' http://localhost:5000/graphql
{"data":{"post":{"title":"titleZZZZ","author":"tanaka"}}}
リクエスト実行(複数取得)
{
posts {
id
title
}
}
全postを取得してます。
例3
( ネストしたデータ )
コード
const express = require('express')
const express_graphql = require('express-graphql')
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLNonNull,
GraphQLList
} = require('graphql')
const dummyPosts = [
{ id: 1, title: 'titleXXXX', content: 'abcdefg' },
{ id: 2, title: 'titleYYYY', content: '1234567' },
{ id: 3, title: 'titleZZZZ', content: 'ABCDEFG' }
]
const dummyComments = [
{ id: 1, postId: 1, author: 'authorXXXX', body: 'aaaaaaaaaaaa' },
{ id: 2, postId: 2, author: 'authorYYYY', body: 'bbbbbbbbbbbb' },
{ id: 3, postId: 1, author: 'authorZZZZ', body: 'cccccccccccc' },
{ id: 4, postId: 3, author: 'authorYYYY', body: 'dddddddddddd' }
]
const CommentType = new GraphQLObjectType({
name: 'CommentType',
fields: {
id: {
type: GraphQLInt
},
postId: {
type: GraphQLInt
},
author: {
type: GraphQLString
},
body: {
type: GraphQLString
}
}
})
const PostType = new GraphQLObjectType({
name: 'PostType',
fields: {
id: {
type: GraphQLInt
},
title: {
type: GraphQLString
},
content: {
type: GraphQLString
},
comments: {
type: new GraphQLList(CommentType),
resolve(parent, args) {
const postId = parent.id
return dummyComments.filter(comment => comment.postId == postId)
}
}
}
})
const RootType = new GraphQLObjectType({
name: 'RootType',
fields: {
posts: {
type: new GraphQLList(PostType),
resolve() {
return dummyPosts
}
},
post: {
type: PostType,
args: {
id: {
type: new GraphQLNonNull(GraphQLInt)
}
},
resolve(parent, args) {
const id = args.id
return dummyPosts.filter(post => post.id == id)[0]
}
}
}
})
const schema = new GraphQLSchema({
query: RootType
})
const app = express()
app.use('/graphql', express_graphql({
schema: schema,
graphiql: true
}))
app.listen(5000, () => console.log('Example app listening on port 5000!'))
buildSchema
ではなく、GraphQLSchema
でスキーマ定義しています。
リクエスト実行
{
posts {
id
title
comments {
id
body
}
}
}
Postに紐づくCommentを取得できました。
例4
( Mutation )
コード
const express = require('express')
const express_graphql = require('express-graphql')
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLInputObjectType,
GraphQLString,
GraphQLInt,
GraphQLNonNull,
GraphQLList
} = require('graphql')
let dummyPosts = [
{ id: 1, title: 'titleXXXX', content: 'abcdefg' },
{ id: 2, title: 'titleYYYY', content: '1234567' },
{ id: 3, title: 'titleZZZZ', content: 'ABCDEFG' }
]
const PostType = new GraphQLObjectType({
name: 'PostType',
fields: {
id: { type: GraphQLInt },
title: { type: GraphQLString },
content: { type: GraphQLString }
}
})
const PostInputType = new GraphQLInputObjectType({
name: 'PostInput',
fields: () => ({
id: { type: GraphQLInt },
title: { type: GraphQLString },
content: { type: GraphQLString }
})
})
const RootType = new GraphQLObjectType({
name: 'RootType',
fields: {
posts: {
type: new GraphQLList(PostType),
resolve() {
return dummyPosts
}
},
post: {
type: PostType,
args: { id: { type: new GraphQLNonNull(GraphQLInt) } },
resolve(parent, args) {
const id = args.id
return dummyPosts.filter(post => post.id == id)[0]
}
}
}
})
const MutationType = new GraphQLObjectType({
name: 'Mutations',
fields: () => ({
createPost: {
type: PostType,
args: { post: { type: PostInputType } },
resolve: (value, args) => {
const post = args.post
dummyPosts.push(post)
return post
}
},
deletePost: {
type: new GraphQLList(PostType),
args: { id: { type: new GraphQLNonNull(GraphQLInt) } },
resolve: (value, args) => {
const id = args.id
dummyPosts = dummyPosts.filter(post => post.id != id)
return dummyPosts
}
}
})
})
const schema = new GraphQLSchema({
query: RootType,
mutation: MutationType
})
const app = express()
app.use('/graphql', express_graphql({ schema: schema, graphiql: true }))
app.listen(5000, () => console.log('Example app listening on port 5000!'))
リクエスト実行(create)
mutation createPost {
createPost(post: {id: 4, title: "xyz", content: "xyxyxyxy"}) {
id
title
content
}
}
レスポンスでは、今回生成したデータを返してます。
リクエスト実行(delete)
mutation deletePost {
deletePost(id: 2) {
id
title
}
}
レスポンスでは、削除後のデータ一覧を返してます。今回指定したデータ(id: 2)が削除されています。
[補足] GraphQLの概要
今回動作確認する上で、最低限知っておきたいGraphQLの概要です。
特長・利点
- エンドポイントが1つ。
REST API
の場合、複数リクエスト
で取得してたのが、GraphQL
の場合、1リクエスト
で取得できるケースがある。REST API
の場合、フロントのニーズに合わせてAPIの改修も必要だったのが、GraphQL
の場合、改修不要でフロントのニーズに対応できるケースがある。
作り方
GraphQLスキーマ
を定義して、対応するリゾルバ関数
の処理を書く。- クエリ言語
- Query
- データ取得
- Mutation
- データ生成、更新、削除
- Subscription
- サーバーサイドからのイベント通知
- Query
type Query {
allPersons(last: Int): [Person!]!
allPosts(last: Int): [Post!]!
}
type Mutation {
createPerson(name: String!, age: Int!): Person!
updatePerson(id: ID!, name: String!, age: Int!): Person!
deletePerson(id: ID!): Person!
createPost(title: String!): Post!
updatePost(id: ID!, title: String!): Post!
deletePost(id: ID!): Post!
}
type Person {
name: String!
age: Int!
posts: [Post!]!
}
type Post {
title: String!
author: Person!
}
表示 | 概要 |
---|---|
String | String型 or Null |
String! | String型 |
[Post] | [ [ Post型 or Null ]の配列 ] or Null |
[Post!]! | Post型の配列 |