らこらこブログ

唐揚げとアニメとプログラミングが大好きです

GraphQL Schemaをファイル分割してドキュメンテーションする

GraphQLのSchemaから静的なドキュメンテーションページを生成するツールとして、graphdocというものがあります。

github.com

GraphQL Schemaを渡すと、こんな感じのHTMLを生成してくれます。 これはGraphQL公式のサンプルにもあるStar Wars APIの例。

https://2fd.github.io/graphdoc/star-wars/

f:id:lacolaco:20180213222120p:plain

このドキュメンテーションを 複数の*.gqlファイルからなるSchemaから生成するために少し小細工が必要だったので紹介します。

GraphQL Schema Language

今回はGraphQL Schema Languageを.gqlという拡張子のファイル(便宜的に以降 gqlファイル と呼びます)で管理します。 TypeScriptやJavaScriptファイル中でテンプレートリテラルとして管理するよりも余計なコードがなくて見やすく、エディタによっては入力支援も得られます。

gqlファイルの欠点は、GraphQL Schema Languageに外部ファイルの参照の仕様がないことです。 JSON Schemaでいう$refに相当するものが定義されていないので、エントリポイントとなるSchemaから分割された型定義などを参照できません。

graphdocでgqlファイルをドキュメンテーションする

graphdocはいくつかの方法でSchemaを読み込めます。 代表的なものはエンドポイントURLを渡してHTTP経由でドキュメンテーションを生成する機能ですが、 gqlファイルを渡すこともできます。 しかしgqlファイルを渡す場合は先述の理由により単一ファイルにすべてのSchemaが記述されている必要があるので、 大きなAPI仕様になると管理が大変です。

複数のgqlファイルからなるSchemaをgraphdocで読み込むためには、JavaScript読み込み機能を使います。 graphdocのschemaFileとして.jsファイルを渡すと、CommonJSとして読み込まれ、exports.defaultの値をSchemaとして使用します。 そしてこのとき、エクスポートするのはSchemaの配列なので、複数のgqlファイルを読み込んで文字列として渡してあげれば目的を達成できます。

手順

npmパッケージを揃える

必要なのは@2fd/graphdocglobの2つです

> yarn add --dev @2fd/graphdoc glob

schema.jsファイルを記述する

複数のgqlファイルを読み込んで文字列として渡してあげるためのJavaScriptファイルを用意します。 globfsを使ってファイルを読み込むだけですが、同期的にエクスポートする必要があるのに注意します。

const glob = require('glob');
const fs = require('fs');
const path = require('path');

function loadSchemas() {
  const files = glob.sync('schema/**/*.{gql,graphql}');

  return files.map(file =>
    fs.readFileSync(path.resolve(file), { encoding: 'utf8' })
  );
}

const schemas = loadSchemas();
exports.default = schemas;

npm scriptを追加する

graphdocコマンドを実行するnpmスクリプトを追加します

  "scripts": {
    "build": "graphdoc -s schema.js -o docs -f"
  },

schemaディレクトリにgqlファイルを配置する

あとはひたすらSchemaを書いていくだけです。

実際にStaw Wars APIのSchemaを分割してgraphdocにしたリポジトリを用意したので、詳細はそちらを参照してください。

github.com

docsディレクトリに出力しているので、GitHub Pagesで簡単にAPIドキュメントをホストできます。

https://lacolaco.github.io/graphdoc-example/

課題

  • gqlファイルに外部参照の仕組みがないので、分割すると参照が途切れる(リネームとかできない)

サーバーサイドの実装に依存しないAPI仕様Centricな開発をしたいのだけど、 Open API Specificationみたいな感じでGraphQL Schemaを使う文化はあまり育っていないようで、苦労しそうな感じがあります。

結局のところひとつのgqlファイルにドカドカ型定義書いていくほうが楽なのかもしれないけど、しばらく分割管理を試してみてから考えましょう。