T-CREATOR

Apollo GraphOS を用いた安全なリリース運用:Schema Checks/Launch Darkly 的な段階公開

Apollo GraphOS を用いた安全なリリース運用:Schema Checks/Launch Darkly 的な段階公開

GraphQL API の開発では、スキーマ変更が既存クライアントに与える影響を事前に把握することが重要です。Apollo GraphOS は、Schema Checks や段階的なリリース機能を提供し、破壊的変更を防ぎながら安全にスキーマを更新できます。本記事では、Apollo GraphOS を用いた安全なリリース運用について、Schema Checks の仕組みから Launch Darkly のような段階公開まで、実践的な手法を詳しく解説します。

背景

GraphQL API は、クライアントが必要なデータを柔軟に取得できる強力な仕組みです。しかし、スキーマの変更は慎重に行わなければ、既存のクライアントアプリケーションに予期しない不具合を引き起こす可能性があります。

従来の REST API では、エンドポイントごとにバージョン管理を行うことで後方互換性を保ってきました。一方、GraphQL では単一のエンドポイントですべてのクエリを処理するため、異なるアプローチが必要になります。

mermaidflowchart TB
    dev["開発者"] -->|スキーマ変更| schema["GraphQL<br/>スキーマ"]
    schema -->|配信| server["GraphQL<br/>サーバー"]
    server -->|クエリ実行| client1["Web<br/>クライアント"]
    server -->|クエリ実行| client2["モバイル<br/>アプリ"]
    server -->|クエリ実行| client3["その他<br/>クライアント"]

    style schema fill:#e1f5ff
    style server fill:#fff4e1

上の図は、GraphQL スキーマが複数のクライアントに影響を与える構造を示しています。スキーマ変更時には、すべてのクライアントへの影響を考慮する必要があります。

Apollo GraphOS の位置づけ

Apollo GraphOS は、GraphQL API の開発・運用を支援する統合プラットフォームです。スキーマレジストリ、パフォーマンス監視、そして安全なリリースを実現する機能を提供します。

特に以下の機能が、安全なリリース運用を実現します。

  • Schema Checks: スキーマ変更が既存クエリに与える影響を事前に検証
  • Schema Registry: スキーマのバージョン管理と履歴管理
  • Operation Metrics: 実際に使用されているクエリの分析
  • Variants: 環境ごとのスキーマ管理
  • Launch: 段階的なスキーマ公開機能

これらの機能を組み合わせることで、破壊的変更を事前に検出し、段階的にリリースを進めることができます。

課題

GraphQL API のリリース運用では、以下のような課題に直面します。

破壊的変更の検出が困難

スキーマを変更する際、どのクライアントがどのフィールドを使用しているかを把握することは簡単ではありません。フィールド名の変更や削除が、既存のクライアントアプリケーションに影響を与える可能性があります。

例えば、以下のようなケースが考えられます。

typescript// 変更前のスキーマ
type User {
  id: ID!
  name: String!
  email: String!
}

上記のスキーマで、name フィールドを fullName に変更する場合を考えてみましょう。

typescript// 変更後のスキーマ
type User {
  id: ID!
  fullName: String!  // name から変更
  email: String!
}

この変更は、name フィールドを使用している既存クライアントすべてに影響を与えます。影響範囲を把握せずに変更をデプロイすると、アプリケーションが動作しなくなる恐れがあります。

リリース後の影響範囲が予測できない

新しいスキーマをデプロイした後、実際にどれだけのクライアントが影響を受けるかを事前に知ることは困難です。特に、モバイルアプリケーションの場合、ユーザーがアプリを更新するまで古いバージョンが使われ続けます。

リリース直後に問題が発覚した場合、すべてのクライアントが一斉に影響を受けるため、ロールバックが必要になります。しかし、すでに新スキーマを使用しているクライアントがいる場合、ロールバック自体が新たな問題を引き起こす可能性があります。

段階的リリースの仕組みがない

Feature Flag を使った段階的リリースは、Web アプリケーションでは一般的な手法です。Launch Darkly などのツールを使えば、特定のユーザーグループに対してのみ新機能を公開できます。

しかし、GraphQL スキーマの場合、同様の仕組みを実現することは容易ではありません。スキーマはサーバー側で定義されるため、クライアントごとに異なるスキーマを提供する仕組みが必要になります。

mermaidflowchart LR
    client["クライアント"] -->|クエリ| router["ルーター"]
    router -->|判定| decision{"段階公開<br/>対象?"}
    decision -->|はい| newSchema["新スキーマ<br/>サーバー"]
    decision -->|いいえ| oldSchema["旧スキーマ<br/>サーバー"]

    style decision fill:#ffe1e1
    style newSchema fill:#e1ffe1
    style oldSchema fill:#e1e1ff

上の図は、段階的リリースに必要なルーティングの仕組みを示しています。クライアントの属性に応じて、適切なスキーマを提供する必要があります。

解決策

Apollo GraphOS は、上記の課題を解決するための包括的な機能を提供します。ここでは、具体的な解決策を段階的に説明していきます。

Schema Checks による事前検証

Schema Checks は、スキーマ変更をデプロイする前に、既存のクエリへの影響を自動的に検証する機能です。過去の Operation Metrics を基に、実際に使用されているクエリと新しいスキーマの互換性をチェックします。

Schema Checks の仕組みは以下の通りです。

mermaidflowchart TB
    dev["開発者"] -->|スキーマ変更| push["GitHub に<br/>プッシュ"]
    push -->|トリガー| ci["CI/CD<br/>パイプライン"]
    ci -->|スキーマ送信| graphos["Apollo<br/>GraphOS"]
    graphos -->|取得| metrics["Operation<br/>Metrics"]
    graphos -->|比較| check["互換性<br/>チェック"]
    check -->|結果| result{"破壊的<br/>変更?"}
    result -->|なし| approve["承認"]
    result -->|あり| reject["却下"]

    style check fill:#e1f5ff
    style approve fill:#e1ffe1
    style reject fill:#ffe1e1

この図は、Schema Checks が CI/CD パイプラインに組み込まれ、自動的に実行される流れを示しています。

Schema Checks を導入するには、まず Apollo CLI をインストールします。

bashyarn add -D @apollo/rover

Rover は、Apollo GraphOS と連携するための CLI ツールです。スキーマのアップロードや Schema Checks の実行に使用します。

次に、Apollo GraphOS にグラフを作成し、API キーを取得します。API キーは環境変数として設定しておきましょう。

bashexport APOLLO_KEY="service:your-graph-name:your-api-key"
export APOLLO_GRAPH_REF="your-graph-name@main"

環境変数を設定することで、Rover コマンドが自動的に Apollo GraphOS と連携します。

CI/CD パイプラインに Schema Checks を組み込むには、以下のコマンドを実行します。

yaml# .github/workflows/schema-check.yml
name: Schema Check
on:
  pull_request:
    branches: [main]

jobs:
  schema-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

上記は、GitHub Actions で Schema Check を実行するワークフローの基本構成です。プルリクエスト作成時に自動実行されます。

続いて、Rover を使ったスキーマチェックのステップを追加します。

yaml- name: Install dependencies
  run: yarn install

- name: Run Schema Check
  run: |
    npx rover subgraph check ${{ secrets.APOLLO_GRAPH_REF }} \
      --schema ./schema.graphql \
      --name users
  env:
    APOLLO_KEY: ${{ secrets.APOLLO_KEY }}

このステップで、変更されたスキーマが既存のクエリと互換性があるかをチェックします。問題が検出された場合、CI は失敗します。

Schema Checks の結果は、Apollo Studio のダッシュボードでも確認できます。どのクエリが影響を受けるか、どのクライアントが使用しているかなど、詳細な情報が表示されます。

Operation Metrics の活用

Schema Checks を効果的に機能させるには、Operation Metrics の収集が不可欠です。実際に使用されているクエリの情報がなければ、影響範囲を正確に判断できません。

Operation Metrics を収集するには、Apollo Server にプラグインを設定します。

typescript// server.ts
import { ApolloServer } from '@apollo/server';
import { ApolloServerPluginUsageReporting } from '@apollo/server/plugin/usageReporting';

const server = new ApolloServer({
  typeDefs,
  resolvers,
  plugins: [
    ApolloServerPluginUsageReporting({
      sendVariableValues: { all: true },
    }),
  ],
});

上記の設定により、すべてのクエリ実行情報が Apollo GraphOS に送信されます。sendVariableValues オプションで、変数の値も含めて収集できます。

サーバーの起動時に、API キーを環境変数で指定する必要があります。

typescript// 環境変数の設定
process.env.APOLLO_KEY =
  'service:your-graph-name:your-api-key';
process.env.APOLLO_GRAPH_REF = 'your-graph-name@main';

これらの環境変数が設定されていれば、Apollo Server は自動的に GraphOS と連携します。

収集された Operation Metrics は、Apollo Studio で可視化されます。以下のような情報を確認できます。

  • クエリの実行回数と頻度
  • クエリのパフォーマンス(レイテンシ、エラー率)
  • 使用されているフィールドと使用頻度
  • クライアントの識別情報(バージョン、プラットフォーム)

これらの情報を基に、Schema Checks は影響範囲を正確に判断します。

Variants による環境管理

Apollo GraphOS の Variants 機能を使うと、環境ごとに異なるスキーマを管理できます。開発環境、ステージング環境、本番環境で、それぞれ独立したスキーマバージョンを運用することが可能です。

mermaidflowchart LR
    dev["開発環境"] -->|スキーマ| devVar["@dev<br/>Variant"]
    staging["ステージング<br/>環境"] -->|スキーマ| stagingVar["@staging<br/>Variant"]
    prod["本番環境"] -->|スキーマ| prodVar["@prod<br/>Variant"]

    devVar --> registry["Schema<br/>Registry"]
    stagingVar --> registry
    prodVar --> registry

    style registry fill:#e1f5ff

Variants を使うことで、各環境で異なるスキーマを安全にテストできます。

Variant を指定してスキーマをパブリッシュするには、以下のコマンドを使用します。

bashnpx rover subgraph publish $APOLLO_GRAPH_REF \
  --schema ./schema.graphql \
  --name users \
  --routing-url http://localhost:4000/graphql

$APOLLO_GRAPH_REF の形式は graph-name@variant-name となります。例えば、開発環境なら my-graph@dev のように指定します。

各環境の Apollo Server でも、対応する Variant を指定する必要があります。

typescript// 開発環境
process.env.APOLLO_GRAPH_REF = 'my-graph@dev';

// ステージング環境
process.env.APOLLO_GRAPH_REF = 'my-graph@staging';

// 本番環境
process.env.APOLLO_GRAPH_REF = 'my-graph@prod';

環境変数を切り替えることで、各環境が適切な Variant のスキーマを使用します。

Schema Checks も Variant ごとに実行されます。例えば、ステージング環境でのチェックを実行するには、以下のようにします。

bashnpx rover subgraph check my-graph@staging \
  --schema ./schema.graphql \
  --name users

これにより、ステージング環境の Operation Metrics を基にチェックが行われます。本番環境に影響を与えずにテストできます。

Launch による段階的公開

Apollo GraphOS の Launch 機能(Enterprise プラン)を使うと、Launch Darkly のような段階的な機能公開が可能になります。特定のクライアントグループに対してのみ、新しいスキーマを段階的に提供できます。

Launch の基本的な仕組みは、Apollo Router を使ったスキーマルーティングです。クライアントの属性(ユーザー ID、バージョン、地域など)に基づいて、提供するスキーマを動的に切り替えます。

Apollo Router を使った段階的公開の構成は以下の通りです。

yaml# router.yaml
supergraph:
  listen: 0.0.0.0:4000

preview_features:
  progressive_override: true

override_subgraph_url:
  users:
    staging: http://staging-users-service:4000/graphql
    production: http://prod-users-service:4000/graphql

この設定ファイルで、複数のサブグラフ URL を定義できます。

クライアントごとにスキーマを切り替えるには、Router のカスタムプラグインを実装します。

rust// router-plugin/src/lib.rs
use apollo_router::plugin::Plugin;
use apollo_router::services::supergraph;

struct LaunchPlugin {
    config: LaunchConfig,
}

#[async_trait::async_trait]
impl Plugin for LaunchPlugin {
    type Config = LaunchConfig;

    async fn supergraph_service(
        &self,
        service: supergraph::BoxService,
    ) -> Result<supergraph::BoxService> {
        // クライアント属性に基づいてルーティング
        Ok(service)
    }
}

上記は、Router プラグインの基本構造です。実際のルーティングロジックは、このプラグイン内に実装します。

ただし、Launch 機能は Enterprise プランでのみ利用可能です。代替案として、Apollo Router のカスタマイズや、アプリケーション層でのルーティング実装も検討できます。

@deprecated ディレクティブの活用

段階的な移行を実現する別のアプローチとして、@deprecated ディレクティブを活用する方法があります。フィールドを即座に削除するのではなく、まず非推奨としてマークし、クライアントに移行期間を与えます。

typescript// スキーマ定義
type User {
  id: ID!
  name: String! @deprecated(reason: "Use fullName instead")
  fullName: String!
  email: String!
}

@deprecated ディレクティブを使うことで、クライアント開発者に変更を通知できます。GraphQL IDE(GraphiQL、Apollo Studio など)では、非推奨フィールドが視覚的に表示されます。

移行期間を設けることで、すべてのクライアントが新しいフィールドに移行するのを待ってから、古いフィールドを削除できます。

typescript// 段階1: 新フィールド追加と旧フィールドの非推奨化
type User {
  id: ID!
  name: String! @deprecated(reason: "Use fullName instead")
  fullName: String!  // 新規追加
}

クライアントの移行状況は、Operation Metrics で確認できます。

typescript// 段階2: すべてのクライアントが移行完了後、旧フィールドを削除
type User {
  id: ID!
  fullName: String!
  email: String!
}

この段階的なアプローチにより、破壊的変更を最小限に抑えられます。

具体例

ここでは、実際のアプリケーションで Apollo GraphOS を使った安全なリリース運用を実装する手順を、ステップバイステップで説明します。

プロジェクトのセットアップ

まず、Apollo Server を使った GraphQL API の基本プロジェクトを作成します。

bashmkdir graphql-safe-release
cd graphql-safe-release
yarn init -y

必要なパッケージをインストールしましょう。

typescriptyarn add @apollo/server graphql
yarn add -D @apollo/rover typescript @types/node ts-node

TypeScript の設定ファイルを作成します。

json{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

プロジェクトの基本構造ができました。次に、GraphQL スキーマとサーバーを実装していきます。

初期スキーマの定義

シンプルなユーザー管理 API のスキーマを定義します。

typescript// src/schema.ts
export const typeDefs = `#graphql
  type User {
    id: ID!
    name: String!
    email: String!
    createdAt: String!
  }

  type Query {
    users: [User!]!
    user(id: ID!): User
  }

  type Mutation {
    createUser(name: String!, email: String!): User!
    updateUser(id: ID!, name: String, email: String): User
    deleteUser(id: ID!): Boolean!
  }
`;

このスキーマでは、ユーザーの基本的な CRUD 操作を提供します。

次に、リゾルバーを実装します。

typescript// src/resolvers.ts
interface User {
  id: string;
  name: string;
  email: string;
  createdAt: string;
}

// サンプルデータ(実際はデータベースから取得)
const users: User[] = [
  {
    id: '1',
    name: '山田太郎',
    email: 'yamada@example.com',
    createdAt: new Date().toISOString(),
  },
];

export const resolvers = {
  Query: {
    users: () => users,
    user: (_: unknown, { id }: { id: string }) =>
      users.find((user) => user.id === id),
  },
};

リゾルバーでは、クエリに対する実際のデータ取得ロジックを実装します。

Mutation のリゾルバーも追加しましょう。

typescript// src/resolvers.ts(続き)
export const resolvers = {
  // ... Query
  Mutation: {
    createUser: (
      _: unknown,
      { name, email }: { name: string; email: string }
    ) => {
      const newUser: User = {
        id: String(users.length + 1),
        name,
        email,
        createdAt: new Date().toISOString(),
      };
      users.push(newUser);
      return newUser;
    },

    updateUser: (
      _: unknown,
      {
        id,
        name,
        email,
      }: { id: string; name?: string; email?: string }
    ) => {
      const user = users.find((u) => u.id === id);
      if (!user) return null;

      if (name) user.name = name;
      if (email) user.email = email;

      return user;
    },

    deleteUser: (_: unknown, { id }: { id: string }) => {
      const index = users.findIndex((u) => u.id === id);
      if (index === -1) return false;

      users.splice(index, 1);
      return true;
    },
  },
};

これで、基本的な CRUD 操作が実装できました。

Apollo Server の構成

Apollo GraphOS と連携する Apollo Server を構成します。

typescript// src/server.ts
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { ApolloServerPluginUsageReporting } from '@apollo/server/plugin/usageReporting';
import { typeDefs } from './schema';
import { resolvers } from './resolvers';

async function startServer() {
  const server = new ApolloServer({
    typeDefs,
    resolvers,
    plugins: [
      ApolloServerPluginUsageReporting({
        sendVariableValues: { all: true },
        sendHeaders: { all: true },
      }),
    ],
  });

  const { url } = await startStandaloneServer(server, {
    listen: { port: 4000 },
  });

  console.log(`🚀 Server ready at ${url}`);
}

startServer();

ApolloServerPluginUsageReporting により、すべてのクエリ実行情報が GraphOS に送信されます。

環境変数を設定するための .env ファイルを作成します。

bash# .env
APOLLO_KEY=service:your-graph-name:your-api-key
APOLLO_GRAPH_REF=your-graph-name@main

実際の値は、Apollo Studio で取得した API キーとグラフ名に置き換えてください。

package.json にスクリプトを追加します。

json{
  "scripts": {
    "dev": "ts-node src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js"
  }
}

サーバーを起動して、動作を確認しましょう。

bashyarn dev

http:​/​​/​localhost:4000 にアクセスすると、Apollo Server の GraphQL Playground が表示されます。

Schema Checks の導入

CI/CD パイプラインに Schema Checks を組み込みます。GitHub Actions の設定ファイルを作成しましょう。

yaml# .github/workflows/schema-check.yml
name: GraphQL Schema Check

on:
  pull_request:
    branches: [main]
    paths:
      - 'src/schema.ts'
      - 'schema.graphql'

jobs:
  schema-check:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

プルリクエスト作成時、スキーマファイルが変更された場合のみ実行されます。

Node.js のセットアップと依存関係のインストールを追加します。

yaml- name: Setup Node.js
  uses: actions/setup-node@v3
  with:
    node-version: '18'
    cache: 'yarn'

- name: Install dependencies
  run: yarn install --frozen-lockfile

スキーマファイルをエクスポートするステップを追加します。

yaml- name: Extract schema
  run: |
    yarn ts-node -e "
      import { typeDefs } from './src/schema';
      import { writeFileSync } from 'fs';
      writeFileSync('schema.graphql', typeDefs);
    "

TypeScript で定義されたスキーマを、GraphQL ファイルとして出力します。

Schema Check を実行するステップを追加します。

yaml- name: Run Schema Check
  run: |
    npx rover subgraph check \
      ${{ secrets.APOLLO_GRAPH_REF }} \
      --schema ./schema.graphql \
      --name users
  env:
    APOLLO_KEY: ${{ secrets.APOLLO_KEY }}

このステップで、破壊的変更がないかをチェックします。問題があれば、CI が失敗してプルリクエストのマージをブロックします。

GitHub リポジトリに Secrets を設定する必要があります。

#Secret 名
1APOLLO_KEYservice:graph-name
2APOLLO_GRAPH_REFgraph-name@main

これらの値は、Apollo Studio で取得できます。

破壊的変更の検出例

実際に破壊的変更を加えて、Schema Checks がどのように動作するかを確認してみましょう。

typescript// src/schema.ts(変更前)
export const typeDefs = `#graphql
  type User {
    id: ID!
    name: String!
    email: String!
    createdAt: String!
  }
`;

name フィールドを削除する変更を加えます。

typescript// src/schema.ts(変更後)
export const typeDefs = `#graphql
  type User {
    id: ID!
    fullName: String!  # name から変更
    email: String!
    createdAt: String!
  }
`;

この変更をプルリクエストとして作成すると、Schema Check が実行されます。

bashgit checkout -b remove-name-field
git add src/schema.ts
git commit -m "feat: Change name field to fullName"
git push origin remove-name-field

GitHub Actions が実行され、以下のようなエラーが報告されます。

javaError: FAILURE
Validated the proposed subgraph against metrics from the last 7 days.

Breaking changes found:
  - Field 'User.name' was removed.
    This is used in 15 operations across 3 clients:
    - Web App (v1.2.3): getUserProfile, userList, searchUsers
    - Mobile App (v2.1.0): userQuery, profile
    - Admin Panel (v1.0.5): allUsers

Schema Check により、破壊的変更が検出され、影響を受けるクライアントとクエリが明示されます。

安全な移行の実装

破壊的変更を避けるため、段階的な移行を実装します。まず、新しいフィールドを追加し、古いフィールドを非推奨化します。

typescript// src/schema.ts(段階1)
export const typeDefs = `#graphql
  type User {
    id: ID!
    name: String! @deprecated(reason: "Use fullName instead. Will be removed in v2.0")
    fullName: String!
    email: String!
    createdAt: String!
  }
`;

両方のフィールドを提供することで、既存クライアントを壊すことなく新機能を提供できます。

リゾルバーも更新します。

typescript// src/resolvers.ts
export const resolvers = {
  Query: {
    // ...
  },
  User: {
    // name フィールドは fullName から生成
    name: (user: User) => user.fullName,
    fullName: (user: User) => user.fullName,
  },
};

フィールドリゾルバーを使うことで、データ構造を変更しながら後方互換性を保てます。

この変更を Schema Check にかけると、破壊的変更として検出されません。

bashgit checkout -b add-fullname-field
git add src/schema.ts src/resolvers.ts
git commit -m "feat: Add fullName field (deprecated name)"
git push origin add-fullname-field

Schema Check が成功し、プルリクエストをマージできます。

csharpSuccess! No breaking changes detected.

Changes:
  - Field 'User.fullName' was added.
  - Field 'User.name' was marked as deprecated.

Operation Metrics の確認

Apollo Studio で Operation Metrics を確認し、クライアントの移行状況を監視します。

ダッシュボードにアクセスすると、以下のような情報が確認できます。

#フィールド使用回数(7 日間)使用クライアント最終使用
1User.name1,234Web App v1.2.32 分前
2User.fullName45Web App v1.3.05 分前
3User.email1,890すべて1 分前

User.name の使用が減少し、User.fullName の使用が増加していることが確認できます。

すべてのクライアントが fullName に移行したことを確認してから、name フィールドを削除します。

typescript// src/schema.ts(段階2:name フィールドの削除)
export const typeDefs = `#graphql
  type User {
    id: ID!
    fullName: String!
    email: String!
    createdAt: String!
  }
`;

Operation Metrics で User.name の使用がゼロになっていれば、安全に削除できます。

環境別の運用

開発環境とステージング環境で、異なる Variant を使った運用を実装します。

typescript// src/config.ts
export const getApolloConfig = () => {
  const env = process.env.NODE_ENV || 'development';

  const configs = {
    development: {
      graphRef: 'my-graph@dev',
      introspection: true,
    },
    staging: {
      graphRef: 'my-graph@staging',
      introspection: true,
    },
    production: {
      graphRef: 'my-graph@prod',
      introspection: false,
    },
  };

  return (
    configs[env as keyof typeof configs] ||
    configs.development
  );
};

環境に応じて、適切な Variant を使用します。

サーバー起動時に設定を適用します。

typescript// src/server.ts
import { getApolloConfig } from './config';

async function startServer() {
  const config = getApolloConfig();

  process.env.APOLLO_GRAPH_REF = config.graphRef;

  const server = new ApolloServer({
    typeDefs,
    resolvers,
    introspection: config.introspection,
    plugins: [
      ApolloServerPluginUsageReporting({
        sendVariableValues: { all: true },
      }),
    ],
  });

  // ...
}

各環境で独立した Operation Metrics が収集されます。

デプロイ時には、環境ごとに Schema Check を実行します。

bash# 開発環境
npx rover subgraph check my-graph@dev \
  --schema ./schema.graphql \
  --name users

# ステージング環境
npx rover subgraph check my-graph@staging \
  --schema ./schema.graphql \
  --name users

# 本番環境
npx rover subgraph check my-graph@prod \
  --schema ./schema.graphql \
  --name users

各環境で別々にチェックすることで、より安全なリリースが可能になります。

mermaidsequenceDiagram
    participant Dev as 開発者
    participant CI as CI/CD
    participant DevEnv as 開発環境
    participant Staging as ステージング
    participant Prod as 本番環境

    Dev->>CI: コード変更<br/>プッシュ
    CI->>DevEnv: Schema Check<br/>(@dev)
    DevEnv-->>CI: OK
    CI->>DevEnv: デプロイ

    Dev->>CI: PR作成
    CI->>Staging: Schema Check<br/>(@staging)
    Staging-->>CI: OK
    CI->>Staging: デプロイ

    Dev->>CI: マージ
    CI->>Prod: Schema Check<br/>(@prod)
    Prod-->>CI: OK
    CI->>Prod: デプロイ

上の図は、環境ごとの段階的なデプロイフローを示しています。各環境で Schema Check が実行され、問題がなければ次の環境に進みます。

まとめ

Apollo GraphOS を活用することで、GraphQL API の安全なリリース運用が実現できます。Schema Checks により破壊的変更を事前に検出し、Operation Metrics で実際の使用状況を把握できます。

本記事で紹介した手法のポイントをまとめます。

Schema Checks の導入により、以下のメリットが得られます。

  • スキーマ変更が既存クライアントに与える影響を事前に把握できる
  • CI/CD パイプラインに組み込むことで、自動的にチェックを実行できる
  • 影響を受けるクエリとクライアントが明示されるため、移行計画を立てやすい

Operation Metrics の活用により、データに基づいた判断ができます。

  • 実際に使用されているクエリとフィールドを把握できる
  • クライアントごとの使用状況を確認できる
  • 非推奨フィールドの使用がゼロになったタイミングで、安全に削除できる

段階的な移行により、破壊的変更を最小限に抑えられます。

  • @deprecated ディレクティブで移行期間を設ける
  • 新旧両方のフィールドを並行提供し、クライアントの移行を待つ
  • すべてのクライアントが移行完了後、古いフィールドを削除する

Variants による環境管理で、より安全な運用が可能になります。

  • 環境ごとに独立したスキーマバージョンを管理できる
  • 開発環境やステージング環境で事前にテストできる
  • 本番環境への影響を最小限に抑えられる

Apollo GraphOS は、GraphQL API の開発から運用まで、包括的なサポートを提供します。特に、Schema Checks と Operation Metrics の組み合わせは、安全なリリース運用に不可欠な機能です。

Launch Darkly のような段階的公開機能は Enterprise プランで利用できますが、@deprecated ディレクティブと Operation Metrics を活用することで、同様の効果を得ることができます。

これらの手法を組み合わせることで、破壊的変更を防ぎながら、継続的にスキーマを改善していくことが可能になります。GraphQL API の安全な運用に、ぜひ Apollo GraphOS を活用してください。

関連リンク