GraphQL requestは未検査の文字列をそのまま実行するものではありません。serverはdocumentをtokenとabstract syntax tree(AST)へparseし、schemaに照らしてvalidationし、選択されたoperationを実行します。GraphQL Specificationは言語と実行規則を、別のGraphQL over HTTP作業draftはHTTP transportを説明します。

ASTはdocumentの構造を表す

query { user(id: "7") { name posts { title } } }では、field、argument、入れ子のselectionが構造化されたnodeになります。parse後のvalidationでuserがschemaに存在するか、argument typeが適切か、object fieldに必要なsubfieldが選ばれているかを確認できます。parseできたことは実行可能である証明ではありません。ASTが自動的にdatabase queryや最適化済みexecution planになるわけでもなく、resolverの呼び出し方はserver実装によります。

validation後にresolverが動く

serverはoperationを選び、variable値を処理し、各fieldのresolverを呼んでresponseを組み立てます。GraphQL specはqueryの最上位selectionを並行化できます。一方mutationの最上位fieldは副作用の順序を保つため直列実行すべきとされています。これは同じmutation文書内の順序であり、別clientからのrequest全体を直列化する規則ではありません。

userとpostsを取り、その各postのauthorも読むと、同じ種類のbackend lookupが繰り返されることがあります。DataLoaderのbatch functionなら一回の実行区間で要求された複数keyをまとめて取得できます。返すarrayの位置が元のkey順に対応することも必要です。これはdata access層の最適化で、GraphQL必須機能ではありません。

POST専用ではなくGETもあり得る

GraphQL言語仕様はHTTPをtransportとして必須にしません。現在のGraphQL over HTTP working draftではserverはPOSTをサポートし、GETなどもサポートできます。GETではparameterをURL queryにencodeしますが、mutationの実行には使えません。URL長の制限やvariableがURL・logに残る可能性も考慮します。利用するAPIのtransport仕様を確認してください。

typeやintrospectionは認可ではない

schema typeはdataの形や入力制約を表しますが、利用者が特定recordやfieldを見てよいかは自動判定しません。認証済みprincipalと対象resourceの関係をresolverまたはservice層で認可します。Apollo GraphOS Routerのauthorization directiveはその製品の機能例であり、GraphQL言語共通のdirectiveではありません。

introspectionはschema構造を調べる標準機能です。productionで無効にする構成もありますが、すべてのserverで必ず無効化するというspec規則はありません。GraphQLの公式guideは、introspection制限をauthentication・authorization、operation safelist、depth・breadth制限、cost controlなど広い対策の一部として扱います。公開・非公開だけでAPI安全性を判断しないでください。

実行コストとcache範囲を管理する

深いselectionやalias、繰り返す関連fieldはresolver負荷を増やします。実際のschemaでdepth、alias数、complexity、timeoutを計測して制限を決めます。userごとのdataをmemoizeするDataLoaderはrequestごとに作ってcontextへ渡します。project READMEは、見えるdataが異なるuser間でloader instanceを共有しないよう案内しています。これはDataLoaderの使い方であり、GraphQL自体が保証する安全機能ではありません。

参考資料