GraphQL に入門する
作業用リポジトリ作った
GraphQL とは
- API 用のクエリ言語。
- 一般的な REST API では複数の URL から読み込みが必要になるが、GraphQL を使用すると、1回のリクエストで多くのリソースを取得できる。
- 単一のエンドポイントからデータの全機能にアクセスできる。
- 既存のクエリに影響を与えず、GraphQL API に新しいフィールドとタイプを追加できる。
チュートリアルを進めている
バッチ処理やキャッシュなどの複雑な機能を扱う Relay のようなクライアントが存在するが、graphql-http
を使えば、HTTP POST リクエストを送るだけで GraphQL クエリを実行できる。
Relay のセットアップには時間がかかるが、アプリケーションが成長するにつれてより多くの機能を活用する価値がある。最初は HTTP リクエストを使い、アプリケーションが複雑になるに従って、より高度なクライアントへの移行を検討するのが良い。
GraphQLスキーマでは、デフォルトで null を許容するが、型に !
を付けると null を許容しなくなる。たとえば、Float!
型のフィールドに null を返すと型エラーが発生する。
var schema = buildSchema(`
type Query {
random: Float!
}
`)
var root = {
random() {
// return Math.random()
return null
},
}
この状態でクエリを実行すると、以下のようなエラーが返される。
> curl -X POST -H "Content-Type: application/json" -d '{"query": "{ random }"}' http://localhost:4000/graphql
{"errors":[{"message":"Cannot return null for non-nullable field Query.random.","locations":[{"line":1,"column":3}],"path":["random"]}],"data":null}%
スキーマで引数を受け取れる。
type Query {
rollDice(numDice: Int!, numSides: Int): [Int]
}
次のようにリクエストが送信できる。
> curl -X POST -H "Content-Type: application/json" -d '{"query": "{ rollDice(numDice: 3, numSides: 6) }"}' http://localhost:4000/graphql
{"data":{"rollDice":[3,1,2]}}%
> curl -X POST -H "Content-Type: application/json" -d '{"query": "{ rollDice(numDice: 10, numSides: 6) }"}' http://localhost:4000/graphql
{"data":{"rollDice":[4,3,3,6,5,4,4,6,1,2]}}%
オブジェクトタイプを定義することで、複数のフィールドやメソッドを持つオブジェクトを返すことができる。例えば、サイコロを振る RandomDie オブジェクトを定義し、これを使って一度のクエリで複数の情報を取得できる。
データの作成や更新する API エンドポイントは、Mutation
として定義する。
type Mutation {
setMessage(message: String): String
}
データを作成・更新する際に同じ入力パラメータが必要な場合、input
タイプを使ってスキーマを簡潔にすることができる。
input MessageInput {
content: String
author: String
}
type Mutation {
createMessage(input: MessageInput): Message
updateMessage(id: ID!, input: MessageInput): Message
}
1つのリクエストでデータの作成や更新を行い、その結果をクライアントが受け取ることができる。
ミドルウェアを使って GraphQL サーバーに追加機能を持たせることができる。例えば、IPアドレスのログ記録や認証処理をミドルウェアで行い、リクエストオブジェクトを GraphQL リゾルバ内で利用することが可能。
function loggingMiddleware(req, res, next) {
console.log("ip:", req.ip);
next();
}
var root = {
ip(args, context) {
return context.ip;
},
};
app.use(loggingMiddleware);
app.all(
"/graphql",
createHandler({
schema: schema,
rootValue: root,
context: (req) => ({
ip: req.raw.ip,
}),
})
);
Apollo の docs を読む
Suspense
使うときは useQuery
の代わりに useSuspenseQuery
使うのか