GraphQL設計原則

英語名 GraphQL Design Principles
読み方 グラフキューエル デザイン プリンシプルズ
難易度
所要時間 スキーマ設計に3〜5日
提唱者 Facebook(2012年開発、2015年公開)
目次

ひとことで言うと
#

REST APIの「エンドポイントごとに固定レスポンス」という制約から解放され、クライアントが必要なフィールドだけを宣言的に指定して取得できるクエリ言語とランタイム。過不足のないデータ取得が実現できる。

押さえておきたい用語
#

押さえておきたい用語
スキーマ(Schema)
GraphQL APIの型定義と構造を宣言する設計図を指す。SDL(Schema Definition Language)で記述し、フロントエンドとバックエンドの契約として機能する。
リゾルバー(Resolver)
スキーマの各フィールドに対応するデータ取得ロジックの関数のこと。「このフィールドのデータをどこから取ってくるか」を定義する。
N+1問題
親レコードN件に対して子レコードをN回個別にDBクエリするパフォーマンス上の問題のこと。DataLoaderパターンでバッチ取得して解消する。
Mutation(ミューテーション)
データの作成・更新・削除を行う操作のこと。RESTのPOST/PUT/DELETEに相当する。Queryが読み取り、Mutationが書き込み。
クエリコスト(Query Complexity)
1つのGraphQLクエリが消費するサーバーリソースの見積もり値である。悪意あるクエリからサーバーを守るために上限を設定する。

GraphQL設計原則の全体像
#

GraphQL設計原則:スキーマを中心にクライアントとサーバーをつなぐ
Client必要なフィールドだけ宣言的に指定Schema(型定義)フロントとバックの契約・仕様書Serverリゾルバーでデータを取得1つのエンドポイント /graphqlQuery(読み取り)データの取得REST の GET に相当Mutation(書き込み)データの変更REST の POST/PUT に相当Subscriptionリアルタイム通知WebSocket で購読設計の4原則スキーマファースト型定義から始めるN+1対策DataLoaderで解消セキュリティ深さ制限+コスト分析スキーマ進化後方互換で育てる過不足のないAPINo Over-fetching, No Under-fetching
GraphQL設計の進め方フロー
1
スキーマ設計
SDLで型を定義し、フロント・バックの契約にする
2
リゾルバー実装
各フィールドのデータ取得ロジックを実装
3
セキュリティ設計
深さ制限・コスト分析・認証認可を設定
スキーマ進化
後方互換を保ちながらスキーマを育てる

こんな悩みに効く
#

  • REST APIのレスポンスが「過剰(使わないフィールドが多い)」か「不足(複数APIを叩く必要がある)」
  • 画面ごとに専用のAPIエンドポイントが増え続けて管理しきれない
  • モバイルとWebで必要なデータが異なり、1つのAPIで対応しきれない

基本の使い方
#

ステップ1: スキーマファーストで設計する

スキーマ(型定義)を最初に設計し、フロントエンド・バックエンドの契約とする。

  • GraphQL SDL(Schema Definition Language)で型を定義する
  • Query(読み取り)、Mutation(書き込み)、Subscription(リアルタイム)を分ける
  • ドメインモデルに基づいた直感的な型名・フィールド名をつける

ポイント: スキーマはAPIの「仕様書」。これをベースにフロントエンドとバックエンドが並行開発できる。

ステップ2: リゾルバーを実装する

各フィールドの**データ取得ロジック(リゾルバー)**を実装する。

  • 型の各フィールドにリゾルバー関数を紐づける
  • DataLoaderパターンでN+1問題を防止する
  • リゾルバーの中にビジネスロジックを書きすぎない(薄いレイヤーに保つ)

ポイント: リゾルバーは「データをどこから取ってくるか」の責務だけ持たせる。

ステップ3: パフォーマンスとセキュリティを設計する

GraphQL特有のリスクに対策する。

  • クエリの深さ制限(depth limiting)で再帰的クエリを防ぐ
  • クエリコストの見積もり(query complexity analysis)で重いクエリを制限
  • 認証・認可はリゾルバーレベルでフィールド単位に適用する

ポイント: GraphQLは自由度が高い分、悪意あるクエリへの防御が必要。

ステップ4: スキーマの進化を管理する

後方互換性を保ちながらスキーマを進化させる。

  • フィールドの追加は非破壊的変更(安全)
  • フィールドの削除は @deprecated で段階的に廃止
  • バージョニングではなく、スキーマの進化(evolution)で対応する

ポイント: RESTのv1/v2のようなバージョン管理は不要。スキーマを育てていく考え方。

具体例
#

例1:SNSアプリのタイムラインAPIをGraphQLで設計する

状況: MAU 200万人のSNSアプリ。タイムライン表示にREST APIを使っており、1画面の表示に平均3.2回のAPIコールが必要だった。

RESTの場合: タイムラインを表示するのに /posts/users/{id}/posts/{id}/comments と3回APIを叩く必要がある。

GraphQLの場合:

query Timeline {
  posts(first: 20) {
    id
    content
    createdAt
    author {
      name
      avatarUrl
    }
    comments(first: 3) {
      content
      author { name }
    }
  }
}

1リクエストで、投稿・著者情報・コメントを必要なフィールドだけ取得。

指標REST APIGraphQL
APIコール数/画面3.2回1回
データ転送量148KB52KB(65%削減)
タイムライン表示速度1.8秒0.6秒

APIコール数3.2回→1回、データ転送量65%削減、表示速度3倍。1エンドポイントで必要なデータだけを取得する——それだけでこの差がつく。

例2:BtoB SaaS企業がマルチプラットフォーム対応をGraphQLで効率化する

状況: 従業員60名のプロジェクト管理SaaS。Web・iOS・Android向けにそれぞれ専用のREST APIエンドポイントを作っており、APIエンドポイント数が142個に膨れ上がっていた。

問題: 新機能追加のたびに3プラットフォーム分のAPIを作成・テスト。バックエンドチーム4名がAPI作成だけで工数の40%を消費。

GraphQL化:

  • 共通スキーマ1つで3プラットフォームに対応
  • Webは詳細データ(ガントチャート情報含む)を取得
  • モバイルはサマリーデータのみ取得(同じエンドポイント)
  • クライアントが必要なフィールドを選ぶので、専用エンドポイント不要
指標BeforeAfter
APIエンドポイント数1421(/graphql)
新機能のAPI開発工数平均5人日平均1.5人日
バックエンドのAPI作成比率40%12%

APIエンドポイント142→1、API開発工数5人日→1.5人日。「クライアントが必要なデータを選ぶ」仕組みにより、プラットフォーム別APIという概念自体が消えた。

例3:地方の観光情報プラットフォームがGraphQLでAPIパートナー連携を実現する

状況: 地方自治体が運営する観光情報プラットフォーム。宿泊施設・飲食店・観光スポットなど1,200件のデータをREST APIで提供していたが、データ利用パートナー(旅行サイト、地図アプリ等)ごとに欲しいデータが異なり、カスタムエンドポイントの要望が絶えなかった。

GraphQL化の効果:

  • 旅行サイトA: 宿泊施設の空室情報と料金だけを取得
  • 地図アプリB: 緯度経度と営業時間だけを取得
  • グルメサイトC: 飲食店のメニューと口コミだけを取得
  • パートナーが自分で必要なフィールドを選べるので、カスタムAPI開発がゼロに
指標BeforeAfter
パートナー対応の開発工数月40時間月2時間(ドキュメント更新のみ)
新規パートナー接続までの期間平均3週間平均2日
APIパートナー数5社18社(1年で3.6倍)

パートナー対応の開発工数、月40時間→2時間。APIパートナー数は1年で5社→18社に。カスタムAPI開発から解放されたことで、むしろデータ利用者が増えた。

やりがちな失敗パターン
#

  1. N+1問題を放置する — リレーションを辿るたびにDBクエリが発生し、パフォーマンスが壊滅的になる。DataLoaderでバッチ取得を必ず実装すること
  2. スキーマをDB構造そのままにする — テーブル定義をそのままGraphQLスキーマにすると、クライアントに不要な内部構造が露出する。ユースケースに基づいたスキーマ設計をすること
  3. クエリの複雑さを制限しない{ user { friends { friends { friends { ... } } } } } のような再帰的クエリでサーバーが落ちる。深さ制限とコスト分析を必ず導入すること
  4. RESTを全部置き換えようとする — ファイルアップロードやWebhookなどGraphQLに不向きな処理まで無理にGraphQL化して複雑になる。ユースケースに合わせてRESTとGraphQLを使い分けること

まとめ
#

GraphQLは 「クライアントが必要なデータを宣言的に取得する」 強力なAPI設計手法。スキーマファーストで設計し、N+1問題への対策とセキュリティを確保すれば、RESTよりも柔軟で効率的なAPI基盤が作れる。ただし、すべてのAPIをGraphQLにする必要はなく、ユースケースに合わせて使い分けよう。