きみはねこみたいなにゃんにゃんなまほう

ねこもスクリプトをかくなり

GraphQL の色々なスキーマ表現について - GraphQL Schema Language や schema.json

(=˘ ꒳ ˘=) GraphQL のスキーマ表現いろいろ多すぎ...

で Introspection について眺めたら GraphQL のスキーマ表現について整理できてきたのでまとめてみます。

GraphQL のスキーマ表現

GraphQL Schema Language

type Query {
  hello: String!
}

のようなDSLのことを指します。GraphQL SDL(Schema Definition Language) とも呼ばれています。 人が一番読みやすい形式といったらこれですね。 GraphQL.js の buildSchema に渡されたり graphql-tools の makeExecutableSchematypeDefs として渡されます。

GraphQL.js の GraphQLSchema

import { GraphQLSchema, GraphQLObjectType } from 'graphql'

const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'rootQuery',
    fields: {
      hello: {
        type: GraphQLString,
      },
    },
  }),

のような GraphQLSchema インスタンスを直接コンストラクトする表現。 resolve 定義など何でもできますが、手作業では書きたくないですね。 ある程度 GraphQL に慣れていてもそう思いますし、そうでないならなおさらだと思います。

Introspection Result

apollo-codegen のようなツールが schema.json のように出力するファイルの中身がこれにあたります。 実態はリソースとなるAPIに対する Introspection の結果が書き出されたものです。 この Introspection に用いるクエリはintrospectionQuery として定義されています。 定義内容はとても長いので手作業では書きたくないですね。

簡単なコードでこのクエリを実行してみます。

import { graphql, buildSchema, introspectionQuery } from 'graphql'

const schema = buildSchema(`
  type Query {
    hello: String!
  }
`)

graphql(schema, introspectionQuery).then(console.log)

これを実行すると schema.json の中身としてよく見かける

{ data:
   { __schema:
      { queryType: [Object],
        mutationType: null,
        subscriptionType: null,
        types: [Array],
        directives: [Array] } } }

という値が得られます。

AST Schema

GraphQL Schema Language をパースしたAST(抽象構文木)です。 ライブラリ利用者としてはあまり利用する機会はありませんが、何気なく console.log した結果によく出てくる気がします。

import { parse, buildASTSchema } from 'graphql'

const typeDefs = `
type Query {
  hello: String!
}
`

const ast = parse(typeDefs)

を実行すると

{ kind: 'Document',
  definitions:
   [ { kind: 'ObjectTypeDefinition',
       description: undefined,
       name: [Object],
       interfaces: [],
       directives: [],
       fields: [Array],
       loc: [Object] } ],
  loc: { start: 0, end: 33 } }

という AST Schema が得られます。

スキーマ表現間の変換

これらのスキーマ表現は graphql と graphql-tools の各種ユーティリティである程度の変換が可能となっています。

  • graphql
    • buildClientSchema: Introspection Result → GraphQLSchema
    • buildSchema: GraphQL Schema Language → GraphQLSchema
    • printSchema: GraphQLSchema → GraphQL Schema Language
    • parse: GraphQL Schema Language → AST Schema
    • buildASTSchema: AST Schema → GraphQLSchema
  • graphql-tools
    • makeExecutableSchema: GraphQL Schema Language + resolve/subscribe 実装 → GraphQLSchema
      • この GraphQLSchema には resolve/subscribe が含まれる

なので resolve など実行時用の定義を除けば、これらの表現は相互変換可能、ということになります。

早見表

output \ source Schema Language Introspection Result GraphQLSchema Instance AST
Schema Language printSchema
Introspection Result (*)
GraphQLSchema Instance buildSchema, makeExecutableSchema buildClientSchema buildASTSchema
AST parse

(*) graphql(schema, introspectionQuery) で取得可能

こうしてみると GraphQLSchema インスタンスへの変換が一番充実していることがわかりますね。直接変換できなくても、例えば

printSchema(buildClientSchema(introspectionResult))

のようにすると Introspection Result から GraphQL Schema Language が得られるように、複数組み合わせれば大体の場合は相互変換ができそうですね。