REST APIと同様に、GraphQL APIでもエンドポイントに引数を渡すことが一般的です。スキーマ言語で引数を定義することで、型チェックが自動的に行われます。各引数には名前と型を指定する必要があります。例えば、基本的な型に関するドキュメントでは、rollThreeDice
というエンドポイントがありました。
type Query { rollThreeDice: [Int]}
「three」をハードコーディングする代わりに、numDice
個のサイコロを、それぞれnumSides
面で振る、より一般的な関数を作成したい場合があります。GraphQL スキーマ言語に引数を追加するには、次のようにします。
type Query { rollDice(numDice: Int!, numSides: Int): [Int]}
Int!
の感嘆符は、numDice
がnullでないことを示しています。つまり、サーバーコードを簡素化するために、検証ロジックの一部を省略できます。numSides
をnullにすることができ、デフォルトではサイコロは6面であると仮定します。
これまでのところ、リゾルバー関数は引数を受け取っていませんでした。リゾルバーが引数を受け取る場合、それらは1つの「args」オブジェクトとして、関数の最初の引数として渡されます。そのため、rollDice
は次のように実装できます。
var root = { rollDice: args => { var output = [] for (var i = 0; i < args.numDice; i++) { output.push(1 + Math.floor(Math.random() * (args.numSides || 6))) } return output },}
ES6のデストラクチャリング代入を使用すると、これらのパラメーターのフォーマットがわかっているので便利です。そのため、rollDice
は次のように記述することもできます。
var root = { rollDice: ({ numDice, numSides }) => { var output = [] for (var i = 0; i < numDice; i++) { output.push(1 + Math.floor(Math.random() * (numSides || 6))) } return output },}
デストラクチャリングに慣れているなら、これは少し見やすいでしょう。なぜなら、rollDice
が定義されているコード行で、引数が何かがわかるからです。
このrollDice
APIをホストするサーバーの全コードは次のとおりです。
var express = require("express")var { createHandler } = require("graphql-http/lib/use/express")var { buildSchema } = require("graphql")
// Construct a schema, using GraphQL schema languagevar schema = buildSchema(` type Query { rollDice(numDice: Int!, numSides: Int): [Int] }`)
// The root provides a resolver function for each API endpointvar root = { rollDice: ({ numDice, numSides }) => { var output = [] for (var i = 0; i < numDice; i++) { output.push(1 + Math.floor(Math.random() * (numSides || 6))) } return output },}
var app = express()app.all( "/graphql", createHandler({ schema: schema, rootValue: root, }))app.listen(4000)console.log("Running a GraphQL API server at localhost:4000/graphql")
このAPIを呼び出す際には、各引数を名前で渡す必要があります。上記のサーバーの場合、6面サイコロを3個振るには、次のGraphQLクエリを実行できます。
{ rollDice(numDice: 3, numSides: 6)}
node server.js
でこのコードを実行し、http://localhost:4000/graphqlにアクセスすると、このAPIを試すことができます。
コードで引数を渡す場合、クエリ文字列全体を自分で構築するのを避ける方が一般的です。代わりに、$
構文を使用してクエリで変数を定義し、変数を別々のマップとして渡すことができます。
例えば、上記のサーバーを呼び出すJavaScriptコードの一部は次のとおりです。
var dice = 3var sides = 6var query = `query RollDice($dice: Int!, $sides: Int) { rollDice(numDice: $dice, numSides: $sides)}`
fetch("/graphql", { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify({ query, variables: { dice, sides }, }),}) .then(r => r.json()) .then(data => console.log("data returned:", data))
GraphQLで$dice
と$sides
を変数として使用することで、クライアント側でのエスケープ処理について心配する必要がなくなります。
基本的な型と引数の渡し方を使用すれば、REST APIで実装できるものは何でも実装できます。しかし、GraphQLはさらに強力なクエリをサポートしています。独自のオブジェクト型を定義する方法を学習すれば、複数のAPI呼び出しを1つのAPI呼び出しに置き換えることができます。