🏗️

graphql-rubyのスキーマ変更をGraphQL Inspectorで自動チェックする

2024/05/01に公開

モチベーション

GraphQL API の改修をする際はスキーマの変更に注意する必要があります。
特に破壊的変更はクライアントに影響が出る可能性があります。そうであると気づかずにリリースしてしまうと障害になりかねません。
通常はコードレビューまでの過程で気がつくケースが多いと思いますが、CI でチェックしたほうが漏れを減らせそうです。

この記事では、graphql-ruby を用いた GraphQL API 開発におけるスキーマの変更を、GraphQL Inspector を使って CI で自動的にチェックする方法について説明します。

実装

graphql-ruby でスキーマファイルを生成する

スキーマ変更をチェックするためには、まずスキーマファイルを生成する必要があります。
graphql-ruby では、デフォルトでスキーマファイルが生成されないため、インストール後に設定が必要です。
幸いにも、graphql-ruby にはGraphQL::RakeTaskクラスが用意されており、次のようなファイルを作成することで、スキーマファイルを生成する Rake タスクを利用できます。

lib/tasks/dump_graphql_schema.rake
require 'graphql/rake_task'

# app/graphql/myapp_schema.rbにMyappSchemaが定義されているとする
GraphQL::RakeTask.new(schema_name: 'MyappSchema', directory: 'app/graphql', idl_outfile: 'myapp_schema.graphql')

次のコマンドでスキーマファイルを作成できます。

$ bundle exec rake graphql:schema:idl

Schema IDL dumped into app/graphql/myapp_schema.graphqlと表示されたら成功です。

生成されたスキーマファイルは次のような内容になります。

app/graphql/myapp_schema.graphql
"""
An ISO 8601-encoded datetime
"""
scalar ISO8601DateTime @specifiedBy(url: "https://tools.ietf.org/html/rfc3339")

type Mutation

type Post {
  body: String
  createdAt: ISO8601DateTime!
  id: ID!
  title: String!
  updatedAt: ISO8601DateTime!
}

type Query {
  post(id: ID!): Post!
}

スキーマファイルが更新されていることを担保するテスト

スキーマ変更を伴うコードの変更をした場合は、スキーマファイルを更新する必要があります。
更新漏れを検知するために、スキーマファイルが現在のコードの状態と一致しているかをチェックする Rspec を書きます。
なお、CI や pre-commit hooks で自動更新されるようにすると、手動でタスクを実行する手間が省けて良いと思いますが、この記事では省略します。

spec/graphql/myapp_schema_spec.rb
require 'rails_helper'

RSpec.describe MyappSchema do
  describe 'GraphQL Schema file' do
    it 'is up to date' do
      current_defn = described_class.to_definition
      printout_defn = Rails.root.join('app/graphql/myapp_schema.graphql').read
      expect(current_defn).to eq(printout_defn), 'Update the printed schema with `bundle exec rake graphql:schema:idl`'
    end
  end
end

GraphQL Inspector を使ってスキーマの変更をチェックする

GraphQL Inspectorは GraphQL スキーマの変更点を出力するツールです。
破壊的変更などを検出してくれる機能などがあります。
GitHub Actions の Action が用意されており、Pull Request に含まれる破壊的変更を検出することができます。

次のように GitHub Actions のワークフロー作成します。
実行するにはWorkflow permissionsRead and write permissionsにする必要があります。
https://github.com/[Owner]/[Repository]/settings/actionsから変更できます。

.github/workflows/checkGraphQLSchema.yml
name: Check GraphQL Schema

on:
  pull_request:
    paths:
      - "app/graphql/myapp_schema.graphql"

jobs:
  test:
    name: Check Schema
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@master

      - uses: kamilkisiela/graphql-inspector@master
        with:
          schema: "develop:app/graphql/myapp_schema.graphql" # 変更前のスキーマのブランチとファイルパス
          fail-on-breaking: false # 破壊的変更が検出された場合でもステップを失敗ステータスにしない

なお、詳しいオプションは公式ドキュメントを参照してください。
変更前のスキーマをファイルパスで指定する代わりに、GraphQL の API エンドポイントを指定するオプションなどもありました。
https://the-guild.dev/graphql/inspector/docs/products/action

チェック結果の例

実験的に次の変更をしたときのチェック結果の例です。

非破壊的変更

  • field の追加

破壊的変更

  • non-null な field を nullable に変更(タイプ変更)
  • field の削除
  • required な argument を追加

実際に変更したコードの内容です。
graphql-ruby code change sample

GraphQL Inspector によるチェック結果は次の通りです。
Pull Request のインラインコメントで変更箇所を教えてくれます。破壊的変更は ✗ マークと赤色で表示されているのですぐに気づけます。
さらに、field を削除している箇所については、まず deprecated にすることを勧めてくれています。
graphql-inspector result sample

まとめ

graphql-ruby でスキーマファイルを生成し、GraphQL Inspector の GitHub Actions を使って変更をチェックする方法をまとめました。
スキーマの破壊的変更や危険な変更を自動的に検出することで、より安全に GraphQL API の開発を進めることができそうです。

参考

https://zenn.dev/hyuta/articles/feae0d7ac11131
https://ayumitamai97.medium.com/continuously-generate-typescript-typings-from-graphql-schema-across-multiple-repositories-ja-fdb2c99c7f1c
https://qiita.com/sukechannnn/items/b2168d7214992e5d37bf
https://graphql-ruby.org/testing/schema_structure.html
https://rmosolgo.github.io/ruby/graphql/2017/03/16/tracking-schema-changes-with-graphql-ruby
https://github.com/marketplace/actions/graphql-inspector

以上

Discussion