GraphQL Federationとは
GraphQL Federationは、複数のGraphQLサービスを、利用者には一つのGraphQL APIとして見せる設計です。各サービスはサブグラフ(subgraph)としてデータと型を担当し、それらを合成した契約がスーパーグラフ(supergraph)になります。クライアントはサブグラフを呼ばず、スーパーグラフのRouterへ問い合わせます。
これはRESTをGraphQLへ置き換える仕組みではありません。複数チーム・複数サービスがあり、画面が横断データを必要とする場面で、APIの入口とスキーマ契約を整える選択肢です。単一サービスなら導入理由はありません。
この記事ではApollo Federation 2を例に、責任の分け方と導入判断を扱います。GraphQL自体の基礎は、先にGraphQL実装ガイドで確認してください。
まず全体像をつかむ
例えば、会員情報を扱うAccountsサービスと、レビューを扱うReviewsサービスがあるとします。レビュー画面では「レビュー本文」と「投稿者の名前」を一緒に表示したいはずです。しかし、データの責任まで一つのサービスに集める必要はありません。
クライアント
│ query { review(id: "r1") { body author { name } } }
▼
Apollo Router
│ スーパーグラフの契約とクエリ計画に従って呼び分ける
├───────────────┐
▼ ▼
Reviews subgraph Accounts subgraph
レビューと投稿者ID Userの名前など
このとき、Routerはクエリを受け、どのサブグラフからどの順番でデータを取得するかを決めます。Reviewsが返したauthor.idを手掛かりに、AccountsへUserの情報を取りに行く、という連携です。クライアントがサービス間の呼び出し順を知る必要はありません。
ただしRouterがデータベースを統合するわけではありません。各サブグラフは自分のDBや既存APIに対する責任を持ち続けます。Federationが統合するのは、主に外部へ出すGraphQLの型とデータ取得経路です。

用語を四つに分ける
| 用語 | 役割 | 例 |
|---|---|---|
| サブグラフ | ドメインごとのGraphQLサービス | Accounts、Reviews、Catalog |
| エンティティ | サブグラフをまたいで参照できる型 | User、Product |
| スーパーグラフ | サブグラフを合成したスキーマ契約 | Userの各フィールドの担当を含む定義 |
| Router | スーパーグラフを実行する入口 | クエリ計画を作り、サブグラフへ要求を送る実行基盤 |
エンティティは「他のサブグラフがフィールドを追加できる、識別可能な型」です。Userにidがあり、そのidからAccountsが該当ユーザーを復元できるなら、Reviews側はUserを参照してreviewsのようなフィールドを担当できます。
単に同じ形の値を返す型までエンティティにする必要はありません。横断参照が必要な型だけを選びます。
なぜ一つの巨大スキーマにしないのか
一つのGraphQLサーバーにすべてのResolverを書けば、初期の実装は単純です。その構成が悪いわけではありません。小さなチーム、単一のデプロイ、境界がまだ定まらないプロダクトでは、モノリスのGraphQLが適しています。
Federationを検討するのは、次のような状況です。
- 会員、商品、注文などのドメインを別チームが独立して変更・デプロイしている
- 画面ごとに複数サービスのデータを結合する処理がクライアントやBFFに繰り返し現れる
- APIの入口を一つに保ちつつ、スキーマの責任を分けたい
- スキーマ変更を、複数チームで検査・合意できる形にしたい
反対に、依存が少ない、運用担当者がいない、認可が整っていない段階では早すぎます。Router、合成、監視、リリース手順が増えるためです。単一エンドポイントだけが目的なら、BFFや通常のGraphQLサーバーでも解決できます。
最小のスキーマ例
以下は、AccountsがUserの基本情報を所有し、Reviewsが同じUserへreviewsフィールドを追加する最小例です。Federation 2のサブグラフは、@linkディレクティブで使用する仕様とディレクティブを明示します。
# accounts/schema.graphql
extend schema
@link(
url: "https://specs.apollo.dev/federation/v2.0"
import: ["@key"]
)
type Query {
user(id: ID!): User
}
type User @key(fields: "id") {
id: ID!
name: String!
}
@key(fields: "id")は、「このサブグラフはidでUserを識別できる」という宣言です。キーは実際に一意で、原則としてnullにならない値を選びます。
# reviews/schema.graphql
extend schema
@link(
url: "https://specs.apollo.dev/federation/v2.0"
import: ["@key"]
)
type Query {
review(id: ID!): Review
}
type Review {
id: ID!
body: String!
author: User!
}
type User @key(fields: "id") {
id: ID!
reviews: [Review!]!
}
Reviews側はUserのidを使ってユーザーを指し、reviewsだけを追加します。同じnameを別々に返す重複所有は、更新先を曖昧にするため最初は避けます。
参照解決が必要になる理由
@keyを書くだけでは、Routerは実在するユーザーを取得できません。キーを定義したサブグラフは、そのキーを受け取ってエンティティを返す参照解決(reference resolver)を実装します。Apollo Serverの場合は__resolveReferenceがその入口です。
const resolvers = {
User: {
__resolveReference(reference: { id: string }) {
return userRepository.findById(reference.id);
},
},
};
ここでも認可と存在しないIDの扱いを決めます。IDを知っていれば取得できる実装では、Routerを経由しても情報漏えいを防げません。
ディレクティブは必要になってから使う
@shareable、@external、@requires、@overrideなどはFederation 2で使える重要なディレクティブです。ただし、最初から一覧を埋め込むものではありません。
@shareable:複数サブグラフが同じフィールドを解決してよいことを明示する@external:別サブグラフのフィールドを、計算の入力として参照する@requires:フィールド解決に必要な外部フィールドを指定する@override:フィールドの解決責任を別サブグラフから移す
これらは移行や計算フィールドに役立つ一方、所有権を読み取りにくくします。必要なケースだけ公式仕様を確認して導入してください。
スーパーグラフを合成する
ローカル開発では、RoverでサブグラフのSDLを合成し、Routerへ渡すスーパーグラフスキーマを作れます。まず二つのサブグラフを起動し、それぞれのGraphQLエンドポイントでスキーマを公開できる状態にします。
# 1. サブグラフのSDLを取得する
rover subgraph introspect http://localhost:4001/graphql > accounts.graphql
rover subgraph introspect http://localhost:4002/graphql > reviews.graphql
次に構成ファイルを用意します。routing_urlはRouterから見えるサブグラフのURLです。コンテナ内のRouterを使う場合、localhostではなくサービス名を使うなど、ネットワークから到達できるURLに変えます。
# supergraph.yaml
federation_version: "=2.0.0"
subgraphs:
accounts:
routing_url: http://localhost:4001/graphql
schema:
file: ./accounts.graphql
reviews:
routing_url: http://localhost:4002/graphql
schema:
file: ./reviews.graphql
# 2. 合成エラーがないか確認し、スーパーグラフを出力する
rover supergraph compose --config ./supergraph.yaml > supergraph.graphql
このコマンドが失敗したら、先にエラーを直します。主な原因は、同名フィールドの型の不一致、意図しない重複所有、@keyのフィールド不足です。合成は型を検査しますが、業務上の正しさは判断しません。
# router.yaml
supergraph:
listen: 127.0.0.1:4000
include_subgraph_errors:
all: true
# 3. 合成結果をRouterで実行する
./router --supergraph ./supergraph.graphql --config ./router.yaml
開発環境ではサブグラフ起因の調査に役立ちます。本番では内部実装を見せないよう、エラー応答・ログ・トレースの公開範囲を分けます。設定は導入時にRouter YAML設定リファレンスで確認してください。
動作確認は横断クエリで行う
Routerが起動しただけでは不十分です。二つのサブグラフをまたぐクエリを送り、期待するデータとエラーの両方を確かめます。
query ReviewWithAuthor {
review(id: "r1") {
body
author {
id
name
reviews {
id
}
}
}
}
確認するのは、author.nameをAccountsが解決できるか、存在しないユーザーの結果、認可のない利用者に返さないことです。ログ・トレースで不要な繰り返し問い合わせも調べます。
変更を安全に進める手順
Federationの難しさは、スキーマを合成することよりも、複数チームが公開契約を変えることにあります。次の順序をCIに組み込むと、問題を早く見つけやすくなります。
- 変更するフィールドの所有者と利用者を決める
- 各サブグラフの単体テストでResolverと認可を確認する
rover supergraph composeで合成できるか確認する- Routerを含む統合テストで横断クエリを実行する
- 既存のクライアントクエリを壊さないか、スキーマ差分をレビューする
- 段階的に公開し、エラー率・遅延・サブグラフ障害を監視する
GraphOSを使う構成なら、認証情報をCIのシークレットとして設定したうえで、rover subgraph checkによるスキーマチェックも利用できます。例えば次のコマンドでは、指定したグラフ参照に対して候補スキーマを検査します。
rover subgraph check my-graph@production \
--name reviews \
--schema ./reviews.graphql
my-graph@productionや認証方法は自分の環境の値に置き換えます。登録済みクライアントへの影響確認は、ローカル合成とは別に必要です。
ガバナンスは「型の会議」を減らすためにある
サブグラフを分けると、共通型を誰が変えられるかという調整が発生します。口頭連絡だけに頼ると、同じフィールドを別の意味で使う問題が起きます。
最低限、次をリポジトリかスキーマの近くに残します。
| 決めること | 例 |
|---|---|
| 型・フィールドの所有者 | User.nameはAccountsチームが変更する |
| 識別子の契約 | User.idは不変の内部IDを使う |
| 非推奨の手順 | 先に@deprecatedを付け、利用状況を確認してから削除する |
| リリース責任 | 合成、統合テスト、ロールバックの担当を決める |
| 障害時の扱い | どのサブグラフが失敗したら部分応答にするかを決める |
所有者を決める目的は、変更の相談先とデータの意味を明確にすることです。組織図より、データの更新責任と業務の境界に沿って分けます。
セキュリティと可用性の注意点
Routerが一つの入口でも、サブグラフ側の認可は必要です。入口でトークンを検証しても、データを読めるかの判断はデータを知る側で行います。サービス間の権限伝達とログの個人情報も設計します。
無制限の深さ、別名、リスト取得は、少数のリクエストでもサブグラフやDBへ負荷をかけます。実際の画面と計測値に基づき、深さ・複雑度・タイムアウト・レート制限を設定します。
サブグラフ障害時の挙動も決めます。補足情報は部分エラーにできても、決済確定に必要なデータは失敗として止めるべきです。
導入判断のチェックリスト
次の質問に多く「はい」と答えられるなら、試験的な導入を検討できます。
- 複数のドメインサービスを、複数チームが継続して運用している
- クライアントやBFFに横断データの結合処理が増えている
- 共通のスキーマ契約と変更レビューを持つ意義がある
- Router、監視、統合テストを運用する担当と時間を確保できる
UserやProductの所有者、識別子、認可境界を説明できる
「まだ決められない」が多いなら、既存APIの境界、認可、監視を先に整えます。Federationはサービス分割を成功させる道具ではなく、既存の責任分割を一貫したAPIにする仕組みです。
まとめ
Apollo Federation 2では、サブグラフが担当する型を合成し、Routerがクライアントのクエリを各サブグラフへ振り分けます。@keyは横断参照するエンティティの識別契約であり、参照解決と認可まで実装して初めて安全に使えます。
導入の第一歩は、二つの明確なドメインを選び、所有者を決め、Roverで合成し、横断クエリを統合テストすることです。得た運用知識をもとに、対象を広げるか判断してください。
関連記事・参考リソース
- GraphQL実装ガイド
- GraphQLとREST APIの選択基準
- マイクロサービスアーキテクチャ
- Apollo Federation 公式ドキュメント
- Apollo Federation Subgraph Specification
- Apollo Routerの自己ホスト手順