REST APIとGraphQLの違いと使い分け|選定基準と運用コスト
REST APIとGraphQLの比較記事は「GraphQLなら必要なデータだけ取れる」で終わりがちですが、実際の選定で判断を分けるのはその先です。CDNキャッシュが効くか、エラーを監視で拾えるか、レート制限をどう設計するか、N+1をどこで止めるか。Postmanの2025年版State of the API Report(回答者5,700人超)では、REST 93%に対しGraphQL 33%で、GraphQLはRESTを置き換えるのではなく併用されています。この記事では両者の構造的な違いを整理したうえで、運用に入ってから効いてくるコスト差と、ShopifyやGitHubが実際に取った選択をもとに判断基準をまとめます。
まとめ
- 構造の違いは1点に集約される:RESTは「サーバーが決めた単位のリソースを複数エンドポイントで返す」、GraphQLは「クライアントが必要な形をクエリで宣言し単一エンドポイントで返す」。オーバーフェッチもバージョン管理も、この差から派生した結果にすぎません。
- GraphQLが効く条件:画面ごとに必要データが大きく異なる、複数バックエンドを1リクエストに集約したい、モバイルで通信量を削りたい。どれにも当てはまらないなら、RESTのままのほうが安く済みます。
- RESTが有利な条件:レスポンスをCDNでキャッシュしたい、ファイルやバイナリを扱う、単純なCRUDで公開APIの互換性を長く保ちたい。
- 見落とされがちな運用コスト:GraphQLはHTTPキャッシュが素直に効かず、エラーでもHTTP 200を返すため監視の作り込みが要り、レート制限もリクエスト数では測れません。N+1対策とクエリ複雑度の制限は「あとで入れる」ではなく設計時の必須項目です。
- 移行は全面置き換えにしない:既存RESTの前にGraphQLゲートウェイを置く形から始めるのが現実的です。Shopifyは2024年10月1日にREST Admin APIをレガシー扱いにしましたが、GitHubはRESTとGraphQLを併存させたままです。ベンダーの方針は一枚岩ではありません。
REST APIとGraphQLの構造的な違い
REST APIの構造:リソースのURL割り当てとHTTPメソッド
REST APIは、扱う対象(リソース)をURLに割り当て、取得・作成・更新・削除をGET/POST/PUT/DELETEというHTTPメソッドで表す設計スタイルです。ユーザー一覧は/users、特定ユーザーは/users/123、その投稿は/users/123/postsのように、URLの階層がそのままデータの構造を表します。レスポンスの形はサーバー側が決めるため、クライアントが「名前だけ欲しい」と思ってもプロフィール全体が返ってきます。これがオーバーフェッチです。逆に、必要なデータが1回で揃わず関連先を追加で取りに行く状態をアンダーフェッチと呼びます。
REST自体のアーキテクチャ定義と6原則、SOAPを含む他方式との位置づけはRESTとは?REST APIの仕組みと6原則・SOAP/GraphQLとの違いを実装目線で解説で扱っています。リソースの切り出し方そのものを設計する考え方はリソース指向アーキテクチャ(ROA)とは?RESTとの違いとAPI設計への落とし込み方、命名やエラー形式まで含めた具体的な指針はGoogle API設計ガイドの概要と良いAPI設計の基本ポイント【完全ガイド序章】を参照してください。
GraphQLの構造:スキーマ定義とクライアント側のクエリ指定
GraphQLは、サーバーが公開できるデータの型と関係を「スキーマ」として定義し、クライアントはその範囲内で必要なフィールドだけをクエリとして送ります。エンドポイントは原則1つ(多くの実装で/graphql)で、取得はquery、更新はmutation、リアルタイム受信はsubscriptionという操作の種類で区別します。
スキーマは単なるドキュメントではなく実行時の検証基盤です。存在しないフィールドを要求したクエリは、データベースに触れる前にサーバーが拒否します。GraphQLの言語仕様やリゾルバの動き、導入事例といった基礎はGraphQLとは?REST APIとの違い・メリット・デメリットをわかりやすく解説にまとめてあるので、GraphQL自体が初見であればそちらを先に読むと本記事の比較が追いやすくなります。仕様の最新エディションは2025年9月版で、前版の2021年10月版から約4年ぶりの改訂でした(改訂内容も同記事で扱っています)。
同じデータを取るときのリクエストの差
ユーザー名とその投稿タイトルだけが欲しい場合、RESTでは関連を辿るたびに往復が増えます。返ってくるのは本文や更新日時なども含む全フィールドです。
GET /users/123
GET /users/123/posts
GraphQLでは1回のPOSTで、必要なフィールドだけを指定します。
POST /graphql
query {
user(id: "123") {
name
posts(first: 10) {
title
}
}
}
GitHubの公式ドキュメントも、フォロワーのフォロワーを辿る例でRESTなら11回の呼び出しが必要なところ、GraphQLでは1リクエストで同じ情報が得られると説明しています。ただしこれは「GraphQLのほうが速い」という意味ではありません。往復回数が減るだけで、サーバー側が内部で行うデータ取得の回数は別問題です(後述のN+1)。
比較表:判断に効く10項目
| 観点 | REST API | GraphQL |
|---|---|---|
| エンドポイント | リソースごとに複数 | 原則1つ |
| レスポンスの形 | サーバーが決定 | クライアントがクエリで指定 |
| 型定義 | 任意(OpenAPI等で別途) | スキーマが必須 |
| 取得しすぎ/不足 | 起きやすい | 原理的に起きにくい |
| HTTPキャッシュ | GETでそのまま効く | POST既定で効かない |
| エラー通知 | HTTPステータスコード | errorsフィールド(原則200) |
| レート制限 | リクエスト数 | クエリコスト計算 |
| バージョン管理 | URLに版を付ける運用が主流 | フィールド追加と非推奨化で吸収 |
| リアルタイム | WebSocket等を別途用意 | subscriptionが仕様内(転送方式は仕様外) |
| ファイル送受信 | 標準的に扱える | 仕様外(多くは別経路) |
どちらを選ぶか:判断基準
GraphQLを選ぶ理由になる条件
採用の判断は「新しいから」ではなく、次のどれかに実際に困っているかで決めます。
1. クライアントごとに必要なデータが大きく違う。 Web管理画面・iOSアプリ・パートナー向け連携が同じバックエンドを見ていて、それぞれ必要なフィールドが異なるケースです。RESTでこれをやると、画面専用エンドポイントが増殖するか、全部入りレスポンスを返して各クライアントが捨てるかの二択になります。
2. 複数のバックエンドを1リクエストに集約したい。 商品情報は基幹システム、在庫は別サービス、レビューはSaaSといった構成で、フロントエンドに何度も往復させたくない場合です。複数のGraphQLサービスを1つのスキーマに合成する方法は、これまでApollo Federationなどベンダーごとに方式が分かれていました。GraphQL FoundationのComposite Schemas仕様として標準化の議論も進んでいますが、リポジトリの表記は「Stage 0: Preliminary(提案段階で、Draft到達前に変更されうる)」で、後述するGraphQL over HTTPのStage 2にも達していません。当面は既存の実装方式で組み、標準化の完了を前提にした設計は避けるのが妥当です。
3. モバイルの通信量を削りたい。 GitHubも公式ドキュメントで、リクエスト数と転送量を減らせる点がモバイルアプリ開発者にとっての魅力だと明記しています。
RESTのままが有利な条件
- レスポンスをCDNでキャッシュしたい:GETのURL単位でキャッシュが効くのはRESTの構造的な強みです(詳細は後述)。
- ファイルアップロードやバイナリを扱う:GraphQL仕様にファイル転送の定義はなく、別経路や非公式仕様に頼ることになります。
- 単純なCRUDで、クライアントが自社の1アプリだけ:AWSのAppSyncドキュメントも、データ要件が複雑でない小規模アプリや、全クライアントが同じデータを使うシナリオではRESTが適すると整理しています。
- 不特定多数に公開するAPIで、利用者に学習コストを強いたくない:GitHubは「RESTのほうが歴史が長く、標準的なHTTPの動詞と概念に慣れた開発者にとって扱いやすい」ことを、RESTを残す理由として挙げています。
採用を見送るべきなのに見送られないパターン
実務で失敗が起きやすいのは、「オーバーフェッチを解消したい」という一点だけでGraphQLを選ぶケースです。オーバーフェッチが問題になるのはモバイル回線や大量トラフィックの局面であって、社内システムの管理画面で数十KB余分に返っていることは、多くの場合コストではありません。GitHubが自社のGraphQL APIに毎時5,000ポイントのコスト計算と500,000ノードの上限という装置を用意しているのは、GraphQLを開けたまま運用するにはこの水準の作り込みが要るということでもあります。数十KBを削るために同等の仕組みを自作する価値があるかは、着手前に見積もってください。
もう1つは、クライアントが自社製の1つだけで、バックエンドチームとフロントエンドチームが同一というケースです。GraphQLの利点は「サーバーに手を入れずにクライアントが取得内容を変えられる」ことにありますが、両方を同じチームが同時に変更できるなら、その利点はほぼ消えます。
運用に入ってから効いてくる差
HTTPキャッシュ:GETとCDNをどう取り戻すか
RESTはGETリクエストがそのままキャッシュの単位になるため、CDNやブラウザキャッシュが素直に効きます。一方GraphQLは、クエリをリクエストボディに入れたPOSTが既定であり、多くのCDNはPOSTをキャッシュしません。
回避策は仕様側にも実装側にも用意されています。GraphQL over HTTP仕様は、サーバーがPOSTを必ず受け付けること、queryに対してGETを受け付けてもよいことを定めています(mutationをGETで実行することは禁止で、その場合はステータスコード405を返さなければなりません)。実装面ではApolloのAutomatic Persisted Queries(APQ)が代表的で、クライアントはクエリ本文の代わりにSHA-256ハッシュだけを送ります。サーバーが未登録ならPERSISTED_QUERY_NOT_FOUNDを返し、クライアントがクエリ本文とハッシュを再送して登録、以降はハッシュだけで実行できます。Apollo Client側でcreateHttpLink({ useGETForHashedQueries: true })を指定すると短いハッシュがGETで送られるため、CDNキャッシュの対象にできます。なおフルサイズのクエリとすべてのmutationはPOSTのままです。
GraphQLでもキャッシュは効かせられます。ただしREST側が何もせず得ている性質を、構成要素を足して取り戻す形になる点は見積もりに含めてください。
エラー設計:HTTP 200問題と、仕様側の答え
GraphQLはフィールド単位のエラーをレスポンス内のerrorsに入れて返すため、実行が始まった時点で多くの実装はHTTP 200を返します。監視やロードバランサ、APMがステータスコードで異常を判定していると、エラーが起きているのに正常として集計される事故が起きます。
GraphQL over HTTP仕様(Stage 2: Draft)は、この曖昧さを埋める方向で規定を整理しています。レスポンス用のメディアタイプとしてapplication/graphql-response+jsonを定め、そのうえで次のように使い分けます。
| 状況 | 推奨ステータス |
|---|---|
| dataのみ(errorsなし) | 200 |
| dataとerrorsの両方(部分成功) | 294 |
| JSONまたはGraphQLドキュメントのパースに失敗 | 400 |
| リクエストが仕様に適合しない | 422 |
| Content-Typeが非対応 | 415 |
| GETでmutationを実行 | 405(MUST) |
注意したいのは294の位置づけです。IETFに登録された標準コードではなく仕様側が独自に定めたもので、仕様自身もapplication/graphql-response+jsonと併用する場合に限って推奨するとしています。application/jsonで返すレガシー互換の経路で294を使えば、既存クライアントを壊しかねません。専用コードを割り当てる狙いは、この仕様を実装していない中間のプロキシやCDNでも「完全な成功ではない」と記録できるようにすることです。仕様はDraft段階で受け入れが保証されてはいないため、現時点ではエラー検知をステータスコードに依存させず、レスポンスボディのerrorsを見る監視を用意しておくべきです。
レート制限:リクエスト数では測れない
RESTは「1時間あたり何リクエストまで」で制限を設計できますが、GraphQLは1リクエストの重さが桁違いに変わるため、同じ方法が通用しません。GitHubのGraphQL APIはポイント制で、ユーザーおよびGitHub Appインストールあたり毎時5,000ポイント、GitHub Enterprise Cloudアカウントが所有するGitHub Appなら1インストールあたり10,000ポイント、GitHub Actionsはリポジトリあたり毎時1,000ポイントです。ポイントはコネクションごとに必要なリクエスト数を合算して100で割って算出され、1回の呼び出しの最小コストは1ポイント。さらに1回の呼び出しで要求できるノードは合計500,000までで、firstとlastの値は1〜100の範囲に制限されています。RESTのレート制限はこれとは別枠です。自社でGraphQLを公開するなら、同種のコスト計算を公開前に用意することになります。
GraphQL特有の実装コスト:N+1とクエリ制限
N+1問題はGraphQLが作るのではなく、露出させる
「投稿10件と、それぞれの著者」を1クエリで要求されると、素朴な実装では投稿一覧に1回、著者取得に10回、合計11回データベースへ問い合わせます。これがN+1です。RESTでも起きますが、RESTはエンドポイントごとにクエリを固定できるのに対し、GraphQLはクライアントが組み合わせを自由に決めるため、開発時に想定していなかった呼ばれ方が本番で発生します。
標準的な対策がDataLoaderです。同一イベントループ内で発生した個別の取得要求をキーの配列にまとめ、バッチ関数へ一度に渡します。公式READMEの例では、素朴な実装で4往復必要だった処理が最大2往復に収まると説明されています。加えて同一リクエスト内のキャッシュも持つため、同じ著者が複数の投稿に紐づいていても取得は1回で済みます。
DataLoaderは自動的には効きません。リゾルバをDataLoader経由で書き直す必要があり、この作業量はスキーマの規模に比例します。GraphQL導入の工数見積もりで最も抜けやすい項目です。
クエリ深度・複雑度の制限とintrospection
単一エンドポイントで任意のクエリを受け付ける以上、深くネストしたクエリや巨大な件数指定は、そのままDoSの手段になります。OWASPのGraphQL Cheat Sheetは、アルバム→曲→アルバムと循環的にネストを重ねる深度攻撃、posts(first: 99999999)のような量の指定、そしてクエリの配列やエイリアス(second:droid(id: "2001"))で1リクエストに多数の操作を詰め込むバッチング攻撃を具体的な攻撃面として挙げています。バッチングは、認証情報の総当たりやレート制限の回避に使われる手口です。
Cheat Sheetが挙げる対策は、深度制限(JavaScriptならgraphql-depth-limit、JavaならMaxQueryDepthInstrumentation)、複雑度分析(graphql-cost-analysis、MaxQueryComplexityInstrumentation)、件数の上限設定、アプリケーション層とインフラ層の双方でのタイムアウトです。ただし推奨される具体的な深度の数値は示されていません。スキーマの構造によって適正値が変わるため、自社のスキーマで実測して決める必要があります。これらとは別に、安全な既定設定としてintrospectionやGraphiQLの無効化・制限も推奨されています。ただしintrospectionを止めてもフィールド名を総当たりで推測する探索は可能なので、無効化だけを対策と考えるのは危険です。
RESTからGraphQLへ移行する現実的な手順
全面置き換えではなく、前段に置く
既存のREST APIを一度に捨てる移行は、リスクに対して見返りが釣り合いません。実務で選ばれるのは、既存RESTの前段にGraphQLサーバーを置き、リゾルバから既存エンドポイントを呼ぶ構成です。クライアント側から順に切り替えられ、問題があればGraphQL層だけを戻せます。REST Admin APIをレガシー化したShopifyも、移行を一度に強制するのではなく、ライブラリ単位の移行ガイドを用意して段階的な置き換えを前提にしています。
この構成では、GraphQL層が既存RESTを複数回呼ぶため、往復の削減はクライアントとサーバー間に限られます。それでもGitHubの例で言う11回が1回になる側がモバイル回線であれば、体感差は出ます。サーバー間の呼び出しまで減らすにはリゾルバをデータベース直結に作り替えることになり、前述したDataLoader経由の書き直しが発生します。どこで止めるかを最初に決めてください。
ベンダーの選択は割れている
移行判断の材料になる大手APIプロバイダの動きは、方向が一致していません。
Shopifyは、REST Admin APIを2024年10月1日付でレガシーAPIと位置づけ、2025年4月1日以降にShopifyアプリストアへ提出される新しいパブリックアプリはGraphQL Admin APIのみで構築することを必須としました。新機能の開発もGraphQL側に集約されています。
一方GitHubは、RESTとGraphQLの両方を提供し続けており、公式ドキュメントでも「どちらを使うべきか」を用途で説明しています。REST APIは歴史が長く扱いやすい、GraphQLは必要なデータだけを1回で取得できる、という並列の説明です。
PostmanのState of the API Report 2025年版(回答者5,700人超)でも、REST 93%に対しGraphQL 33%、Webhook 50%、WebSocket 35%という結果でした。回答者は複数のスタイルを併用できるため、この数字はGraphQLがRESTを置き換えている状況ではなく、RESTの上に別のスタイルが積み増されている状況を示します。「いずれRESTは無くなるから今のうちに」という前提で移行を正当化するのは、データに合いません。
REST・GraphQL以外のAPIプロトコルとの住み分け
API方式の選定は2択ではありません。Web APIで使われる通信方式の主な種類として、REST・GraphQLのほかに次の3つがあり、用途が明確に分かれます。
gRPC:スキーマ固定のサービス間通信
gRPCはProtocol Buffersでスキーマを定義し、HTTP/2上でバイナリをやり取りします。マイクロサービス間の内部通信のように、送受信するデータの形が固定で、レイテンシとスループットを詰めたい場面に向きます。ブラウザから直接呼ぶには追加のプロキシが要るため、公開APIの第一候補にはなりにくい方式です。詳細はgRPCとは?定義・仕組み・RESTとの違いをまとめて解説で扱っています。
tRPC:フルスタックTypeScript限定の型共有
tRPCはサーバーとクライアントが両方TypeScriptである前提で、スキーマ定義ファイルもコード生成もなしに型を共有します。GraphQLの型安全性が欲しいが、スキーマ管理やリゾルバの運用コストは払いたくないという構成に絞った答えです。比較はtRPCとは?REST・GraphQL・gRPCとの違いと型安全なAPI実装をv11の実コードで解説にまとめてあります。
Webhook:サーバー起点の変更通知
Webhookはそもそも方向が逆で、クライアントが取りに行くのではなくサーバー側が変化を通知します。GraphQLのsubscriptionと目的が近いように見えますが、常時接続を維持しない分だけ運用は軽くなります。仕組みはIncoming Webhookとは?仕組みとSlack・Discordでの使い方を解説を参照してください。
よくある質問
REST APIとは何かを一言で説明すると?
データをリソースとしてURLに割り当て、GET・POST・PUT・DELETEというHTTPメソッドで操作する、Web APIの設計スタイルです。仕様書として1つの規格があるわけではなく、リソース指向・ステートレスといった制約に沿った設計方針の総称なので、実装ごとに細部は異なります。
GraphQLはREST APIより速いのですか?
速度改善を目的にするなら、DataLoaderの導入までを計画に含めてください。N+1対策のないGraphQLは、1クエリの裏で大量のデータベースアクセスが発生し、同じ処理のREST APIより遅くなります。
GraphQLではエンドポイントを1つにしなければいけませんか?
仕様上の強制ではなく、GraphQL over HTTP仕様もURLをどう切るかは規定していません。実運用では認証境界や社内外の公開範囲でエンドポイントを分けることがあります。
GraphQLにすればAPIのバージョン管理は不要になりますか?
URLにv1、v2と付ける形の版管理は不要になりますが、互換性の管理そのものは残ります。フィールドの追加は既存クエリに影響しない一方、フィールドの削除や型の変更は利用中のクライアントを壊します。@deprecatedで非推奨を示し、利用状況を計測してから消す運用が前提です。
gRPCやtRPCとはどう住み分けますか?
公開APIで多様なクライアントを想定するならRESTかGraphQL、社内のサービス間通信で性能を詰めるならgRPC、サーバーもクライアントもTypeScriptで完結するならtRPCが候補になります。GraphQLを選ぶ決め手は「クライアントごとに必要なデータが違うこと」なので、そこが該当しない構成では他の選択肢のほうが運用は軽くなります。