GraphQLとRESTは、単純な機能一覧だけでは比較できません。 大切なのは、画面や利用者によって必要なデータがどれほど変わるか、HTTPキャッシュをどこまで使いたいか、運用チームが複雑なクエリを管理できるかです。
この記事では実装方法ではなく、選択基準に集中します。
最初に用語を分ける
RESTはアーキテクチャスタイル
RESTは、Roy Fielding氏が示した次のような制約から成るアーキテクチャスタイルです。
- クライアントとサーバーを分離する
- リクエストをステートレスにする
- 応答がキャッシュ可能か示す
- 統一されたインターフェースを使う
- 階層化されたシステムを許容する
- 必要に応じてコードを配布する(任意)
実務で「REST API」と呼ばれるものには、リソースをURLで表し、HTTPメソッドとJSONを使うAPIも広く含まれます。 ただし、その呼び名だけでRESTの制約をすべて満たすとは限りません。
この記事では混同を避けるため、一般的なものを「リソース指向のHTTP API」と呼びます。
GraphQLは型付きの問い合わせ方式
GraphQLは、型付きスキーマに対してクライアントが必要なフィールドを指定する問い合わせ言語と実行方式です。 HTTPでは1つのエンドポイントを使う構成が一般的ですが、エンドポイント数だけが本質ではありません。
query Profile($id: ID!) {
user(id: $id) {
name
avatarUrl
}
}
クライアントはスキーマで許可された範囲から、今回必要なデータの形を宣言します。
同じ画面でも取得形状が違う

プロフィール画面にユーザー、投稿、フォロワー数を表示するとします。
リソース指向のHTTP APIでは、次のどれも設計可能です。
/users/123など複数のリソースを取得する- 画面向けの集約エンドポイントを用意する
fieldsやincludeで返す範囲を指定できるようにする
GraphQLでは、クライアントが1つのクエリで関連フィールドを選べます。
したがって「HTTP APIは必ず複数リクエスト」「GraphQLは必ず1リクエストで高速」とは限りません。 ブラウザーからサーバーへの往復が1回でも、サーバー内部で多数のDB問い合わせが発生する場合があります。
比較するときの6つの軸
| 観点 | リソース指向のHTTP API | GraphQL |
|---|---|---|
| 応答の形 | サーバーがエンドポイントごとに決める | クライアントがスキーマ内から選ぶ |
| 契約 | OpenAPIなどを導入できる | 型付きスキーマが中心になる |
| HTTPキャッシュ | GETとURLを使う設計では活用しやすい | GET、persisted document、CDNなどの設計が必要 |
| 部分的な失敗 | HTTP statusと独自のエラー形式で表す | dataとerrorsが同時に返る場合がある |
| クエリの自由度 | 公開した操作に限定しやすい | 高いが、深さや量の制御が必要 |
| 運用 | HTTP基盤を利用しやすい | スキーマ変更、クエリ分析、resolver監視が重要 |
1. オーバーフェッチとアンダーフェッチ
GraphQLでは必要なフィールドを選べるため、画面ごとに必要な形が大きく異なる場合に有効です。
一方、リソース指向のHTTP APIでも、用途別エンドポイントやフィールド選択を設計できます。 GraphQLを導入しただけで転送量が必ず減るわけではなく、クライアントが大きなクエリを送れば応答も大きくなります。
2. スキーマと変更管理
GraphQLでは、型、フィールド、引数がスキーマに集約されます。 非推奨化を使い、利用状況を確認しながら段階的に移行しやすい点が強みです。
リソース指向のHTTP APIでも、OpenAPIなどで契約を定義できます。 ただし、仕様書と実装を同期する仕組みは別途必要です。
どちらでも、互換性を壊す変更を自動的に防げるわけではありません。
3. キャッシュ
安全なGETリクエストと安定したURLを使うHTTP APIは、Cache-Control、ETag、共有キャッシュを利用しやすい構成です。
GraphQLでも、GETによる問い合わせ、persisted document、CDN、クライアントの正規化キャッシュを利用できます。 ただし、任意のクエリ文字列や認可されたデータをどう識別するかまで設計する必要があります。
HTTPキャッシュの利用可否は、方式名だけでは決まりません。 キャッシュ可能性、キー、利用者ごとの分離、無効化方法を確認します。
4. エラー
HTTP APIでは、通信や認証、リソース状態をHTTP statusで表し、本文に詳細を入れる設計が一般的です。 エラー本文にはProblem Detailsなどの共通形式も選べます。
GraphQLでは、実行できたフィールドのdataと、失敗したフィールドのerrorsが同時に返る場合があります。
HTTP transportの失敗と、GraphQLの要求・実行エラーは分けて扱います。
部分データを表示するのか、画面全体を失敗にするのかは、クライアント側の方針が必要です。
5. N+1
N+1は、一覧を1回取得した後、各項目の関連データを1件ずつ追加取得する問題です。 これはGraphQL固有ではなく、HTTP APIの集約処理やORMでも起こります。
GraphQLはフィールドごとにresolverを分ける実装が多いため、N+1が生まれやすく、観測しやすい傾向があります。 対策には、次の選択肢があります。
- DBのJOINや事前読み込み
- 同一リクエスト内のbatching
- DataLoaderなどによる重複排除
- query plannerやデータソース側での集約
DataLoaderを追加すればすべて解決するわけではありません。 発行されたDBクエリ数と実行計画を計測して判断します。
6. セキュリティと負荷制御
どちらの方式でも、認証だけでなく、対象データごとの認可が必要です。 入力検証、rate limit、応答サイズ、監査ログも共通の課題です。
GraphQLでは、利用状況に応じて次も検討します。
- クエリの深さ、alias数、一覧件数を制限する
- query complexityや実行時間を計測する
- persisted documentや許可済み操作を使う
- resolverごとではなく一貫した認可層を持つ
introspectionを無効にするだけでは、認可や負荷制御の代わりになりません。 開発ツールとの兼ね合いも含めて判断します。
選択基準
GraphQLが候補になりやすい
- Web、モバイルなど複数のクライアントで必要な形が大きく違う
- 画面の変更が多く、クライアントが取得フィールドを調整したい
- 複数のバックエンドを型付きスキーマの背後にまとめたい
- スキーマ所有者と変更手順を決められる
- クエリコストやresolverを観測する基盤を運用できる
リソース指向のHTTP APIが候補になりやすい
- 操作と応答の形が安定している
- 公開GET APIやCDNキャッシュを素直に活用したい
- ファイル配信、stream、webhookなどHTTPの仕組みが中心
- 許可する操作を少数のエンドポイントに限定したい
- チームがHTTPの運用基盤とOpenAPIに習熟している
併用もできる
外部公開APIはリソース指向のHTTP API、画面向け集約はGraphQLという構成もあります。 ただし、認可、監視、データモデルを2方式で維持する費用が増えます。
流行ではなく、主要な画面を1つ選び、転送量、DB問い合わせ数、キャッシュ率、実装と運用の複雑さを小さく検証して決めましょう。
実装を試す
GraphQLのスキーマ、Query、Mutation、認証を手元で試す場合は、GraphQL API実装のPracticeへ進んでください。 この記事では選定と設計判断に集中し、フレームワーク固有の実装はPracticeへ分けています。
参考リソース
- GraphQL Learn(公式)
- GraphQL Specification(公式)
- GraphQL over HTTP
- Fielding dissertation: REST
- HTTP Semantics: RFC 9110
- HTTP Caching: RFC 9111
- OpenAPI Specification