GraphQL スキーマの変更を検知し、TypeScript の型定義を自動的に生成する仕組み

Ayumi Tamai
10 min readJan 29, 2021

--

2021年更新版(Kaigi on Rails スポンサートーク資料):GraphQL Schema から TypeScript の型定義を継続的に生成する
English version: Continuously generate TypeScript typings from GraphQL schema across multiple repositories 🚀

GraphQLと TypeScript を使用したアプリケーションを開発するとき、 GraphQL Code Generator (graphql-codegen) はとても役に立ちます。 GraphQL と TypeScript を併用する場合、 TypeScript で使用する型定義を GraphQL スキーマに基づいて宣言する必要がありますが、 graphql-codegen はこの型定義を自動で行ってくれます。

graphql-codegen は便利ですが、 GraphQL API と TypeScript 製のアプリケーションとを別々の GitHub リポジトリ上で開発しているとき、スキーマと型定義との整合性をとるのが難しくなります。 そこで、スキーマと型定義とをリポジトリを跨いで(ほぼ)同期する方法を考えてみます。

graphql-codegen の基本的な使い方

最小限の設定ファイルは例えばこうなります。

schema フィールドには、 1) GraphQL API のエンドポイントのURL、 2) *.graphql または JSON 形式のローカルスキーマファイル、 3) GitHub リポジトリ上の *.graphql ファイルなどを指定することができます。

詳細は GraphQL Code Generator の公式ドキュメンテーション を参照してください。

準備

次のセクションに進む前に、以下が用意されていることを確認してください。

1. GraphQL API のプロジェクトと、それを管理している GitHub リポジトリ

私のプロジェクトは Rails アプリケーションで、 graphql-ruby gem を使用しています。 アプリケーションは cont-codegen-sandbox-api と名付けました。

2. TypeScript を使用したプロジェクトと、それを管理している GitHub リポジトリ

私のプロジェクトは cont-codegen-sandbox-client と名付けました。

3. GraphQL スキーマ定義ファイルを生成するスクリプト

GraphQL API の実装を元に、 schema.graphql のような GraphQL スキーマ定義ファイルを生成するスクリプトです。 私の例では lib/graphql/rake_task.rb (rake graphql:schema:idl) を使用します。

schema.graphql は、 git の pre-commit hook や GitHub アプリケーションを用いて自動で生成することをおすすめします。

4. GitHub personal access token

リポジトリの Secrets に、 GitHub アカウントの Personal Access Token を設定する必要があります。 私の例では、この secret に PERSONAL_ACCESS_TOKEN という名前をつけます。

トークンは、 repo scope の権限を持っている必要があります。

リポジトリが Public か Private かを問わず、 graphql-codegen と GitHub Action がこのトークンを使用します。

リポジトリを跨いで型定義ファイルを生成する

GraphQL のプロジェクトと TypeScript のプロジェクトが同じディレクトリまたは GitHub リポジトリにある場合、上で紹介した基本的な設定を行うだけで、 GraphQL スキーマに基づいて TypeScript 型定義を作成することができます。 一方で、プロジェクトが別々のリポジトリで管理されている場合はもう少し設定が必要です。

graphql-codegen の便利な機能のおかげで、GitHub 上の schema.graphql ファイルを schema フィールドに指定することができます。 Private リポジトリにも対応しています!✨ codegen.yml は次のような構文をとります。

graphql-codegen がリポジトリにアクセスするために、 token フィールドが必要となります。(このことは公式ドキュメンテーションに書かれていません。 2021年1月現在、リポジトリが Public だとしても token が必要なようです。 これが不具合なのか仕様なのかは分かりません。)

dotenv を使っている場合、型定義を生成するコマンドは graphql-codegen -r dotenv/config のようになります。

以下が私の codegen.yml です:

さて、これで yarn graphql-codegen -r dotenv/config コマンドによって型定義ファイルを生成することができるようになりました 🔥

リポジトリを跨いで、継続的に型定義ファイルを生成する

前のセクションでは、 GraphQL API と TypeScript 製のアプリケーションが別々のリポジトリで管理されている場合の graphql-codegen の設定方法を説明しました。 この段階では、型定義ファイルを作成するために毎度コマンドを叩く必要があります。 この作業を自動化しましょう。

型定義ファイル生成の自動化には、 GitHub Action を使うのがよいでしょう。 GitHub Action を使用する場合、これら3つの workflow を定義します:

  1. GraphQL スキーマの更新を、GraphQL プロジェクトのリポジトリから TypeScript プロジェクトのリポジトリに通知する
  2. graphql-codegen を実行し、 Pull Request を作成する
  3. Pull Request を自動でマージする(任意)

1. GraphQL スキーマの更新を、TypeScript プロジェクトのリポジトリに通知する

GraphQL スキーマから TypeScript 用の型定義を(ほぼ)同期的に生成するには、スキーマの更新時に GraphQL API のリポジトリから TypeScript プロジェクトのリポジトリに通知する必要があります。

以下の設定によって、 リポジトリがもう一方のリポジトリの repository_dispatch イベントを発火させることができるようになります。 このイベントは、 コミットが main ブランチに push され、なおかつ schema.graphql に差分があったときにのみトリガーされます。

ここで注意すべきことがあります。 3つ目のステップ(Dispatch update-graphql-schema)では、必ず Personal Access Token を指定する必要があります。 これは、 GITHUB_TOKENrepository_dispatch イベントをトリガーできないためです。

GraphQL API のリポジトリでの設定ファイル .github/workflows/dispatch_graphql_schema_update.yml はこのようになりました:

2. graphql-codegen を実行し、 Pull Request を作成する

repository_dispatch イベントが TypeScript プロジェクトのリポジトリで発火したときに、 graphql-codegen が最新の GraphQL スキーマを参照して TypeScript の型定義を生成するようにします。

graphql-codegen の Pull Request が作成されたとき、ある人はそのPRを目視で確認したいかもしれません。 またある人は、そのPRが勝手にマージされてほしいと思うでしょう。 私は後者の方法が好みです。 そこで、 pascalgn/automerge-action を使用するための設定をいくつか行います。

ここでも気をつけるべきことがあります。 もし自動マージを行いたい場合、4つ目のステップ(Create Pull Request) では、 Personal Access Token を使用する必要があります。自動マージを行わなくていい場合、 GITHUB_TOKEN を指定すれば十分です。

TypeScript プロジェクトのリポジトリでの設定ファイル .github/workflows/graphql_schema_updated.yml は、このようになりました:

3. Pull Request を自動でマージする(任意)

Pull Request を自動でマージしたい場合、 pascalgn/automerge-action が便利です。 この GitHub Action を使用すると、 automerge というラベルがついたPRが自動でマージされるようになります。

上で説明した2つ目の workflow は Pull Request を作成して automerge ラベルをつけますが、そのラベルが付けられた瞬間にこの3つ目の workflow がトリガーされます。

TypeScript プロジェクトのリポジトリでの設定ファイル .github/workflows/automerge.yml はこのようになります:

動作するサンプル

これでようやく、 継続的にGraphQL スキーマの変更を検知して TypeScript 用の型定義を生成する仕組みが出来上がりました!🚀

正しく設定できていれば、 workflow の画面はこのようになっているはずです。

graphql-codegen と workflow 設定ファイルへのリンク

実際に作成された Pull Request へのリンク

上の設定で実際に動かした結果作成されたPRがこれです ayumitamai97/cont-codegen-sandbox-client#36

Create Pull Request のステップで GITHUB_TOKEN を使用した場合、コミットの author は自分の GitHub アカウントではなく "github-actions (bot)" になります。

この投稿が役に立ったり、あるいはアドバイスがあれば、ぜひコメントを書いてください。 ここまで読んでくださり、ありがとうございました 👾

--

--