GraphQL vs REST API: 主な違い、パフォーマンス、使い分けの指針
はじめに
GraphQLとRESTの議論は、FacebookがGraphQLを2015年にオープンソース化して以来、APIデザインの分野で最も議論されているテーマのひとつです。どちらもクライアントがサーバーからデータをリクエストするためのAPIを構築するアプローチですが、データのリクエスト方法と配信方法については根本的に異なるアプローチを取っています。
REST(Representational State Transfer)は20年以上にわたり主流のAPIアーキテクチャです。標準的なHTTPメソッドとCRUD操作に自然にマッピングされるリソースベースのURLを使用します。Facebookが作成したGraphQLは、クライアントが必要なデータを過不足なく正確にリクエストできる力を与えるクエリ言語です。
この比較では、コアの違い、パフォーマンス特性、開発者体験、実践的なユースケースを取り上げ、プロジェクトに適したアーキテクチャを選ぶ手助けをします。両方のアプローチのコード例も含め、違いを直接確認できます。
REST APIの仕組み
REST APIはURLでリソースを公開し、HTTPメソッドを使って操作を実行します。
# ユーザー一覧を取得
GET /api/users
# 特定のユーザーを取得
GET /api/users/123
# ユーザーの投稿を取得
GET /api/users/123/posts
# ユーザーを作成
POST /api/users
Content-Type: application/json
{"name": "Jane Doe", "email": "jane@example.com"}
# ユーザーを更新
PUT /api/users/123
Content-Type: application/json
{"name": "Jane Smith", "email": "jane@example.com"}
# ユーザーを削除
DELETE /api/users/123
RESTレスポンスの例
// GET /api/users/123
{
"id": 123,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": "https://cdn.example.com/avatars/123.jpg",
"role": "developer",
"department": "Engineering",
"createdAt": "2024-01-15T10:30:00Z",
"lastLogin": "2025-02-20T14:22:00Z"
}
クライアントは名前とメールだけが必要な場合でも、すべてのフィールドを受け取ります。これをオーバーフェッチと呼びます。
GraphQLの仕組み
GraphQLは単一のエンドポイントを使用し、クライアントがクエリを通じて必要なデータを正確に指定できます。
# すべてのGraphQLリクエストは単一のエンドポイントへ
POST /graphql
Content-Type: application/json
# クエリ: 名前とメールのみを取得
{
"query": "{ user(id: 123) { name email } }"
}
# レスポンス: リクエストしたフィールドのみ
{
"data": {
"user": {
"name": "Jane Doe",
"email": "jane@example.com"
}
}
}
GraphQLスキーマ定義
# GraphQLスキーマ(サーバーサイド)
type User {
id: ID!
name: String!
email: String!
avatar: String
role: String!
posts: [Post!]!
department: Department
}
type Post {
id: ID!
title: String!
content: String!
author: User!
comments: [Comment!]!
createdAt: DateTime!
}
type Query {
user(id: ID!): User
users(limit: Int, offset: Int): [User!]!
post(id: ID!): Post
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): Boolean!
}
単一クエリで関連データを取得する
# ユーザーとその投稿、各投稿のコメントを1リクエストで取得
query {
user(id: 123) {
name
email
posts {
title
createdAt
comments {
text
author { name }
}
}
}
}
RESTでは、これに3回の個別のAPIコール(ユーザー、投稿、各投稿のコメント)またはカスタムエンドポイントが必要です。GraphQLなら1回のクエリで済みます。
主な違い: GraphQL vs REST
1. データフェッチ
| 観点 | REST | GraphQL |
|---|---|---|
| エンドポイント | 複数(リソースごとに1つ) | 単一エンドポイント(/graphql) |
| オーバーフェッチ | 一般的(全フィールドを返す) | なし(クライアントがフィールドを指定) |
| アンダーフェッチ | 一般的(複数コールが必要) | なし(ネストされたクエリ) |
| リクエスト形式 | HTTPメソッド + URLパス | POSTボディのクエリ言語 |
2. パフォーマンス
RESTの優位点:
- HTTPキャッシュがネイティブに機能する(GETリクエストはURLでキャッシュ可能)
- CDNキャッシュが簡単
- シンプルなレスポンスで高速なパース
- クエリの複雑性のオーバーヘッドがない
GraphQLの優位点:
- ネットワークリクエストが少ない(1回のクエリで関連データを取得)
- 転送データ量が少ない(オーバーフェッチなし)
- モバイルフレンドリー(帯域幅の使用量が低い)
- バッチクエリでラウンドトリップを削減
3. キャッシュ
REST: ネイティブHTTPキャッシュがそのまま機能します。各URLが自然なキャッシュキーとなり、CDN、ブラウザ、プロキシがHTTPキャッシュヘッダーを理解します。
# REST、キャッシュが簡単
GET /api/users/123
Cache-Control: max-age=3600
ETag: "abc123"
GraphQL: すべてのリクエストがPOST経由で同じURLに送信されるため、キャッシュはより複雑です。Apollo Client、Relay、Persisted Queriesなどのツールを使ったアプリケーションレベルのキャッシュが必要です。
// GraphQL、クライアントサイドのキャッシュが必要
const client = new ApolloClient({
cache: new InMemoryCache(),
// オブジェクトの型とIDによる正規化キャッシュ
});
4. エラーハンドリング
RESTはHTTPステータスコード(200、400、404、500)を使います。GraphQLは常に200 OKを返し、エラーをレスポンスボディに含めます。
// RESTエラー、HTTP 404
// Status: 404 Not Found
{ "error": "User not found" }
// GraphQLエラー、HTTP 200 OK(常に)
{
"data": { "user": null },
"errors": [{
"message": "User not found",
"path": ["user"],
"extensions": { "code": "NOT_FOUND" }
}]
}
5. バージョニング
REST: 通常はURLバージョニング(/api/v1/、/api/v2/)を使います。破壊的変更には新しいバージョンが必要です。
GraphQL: バージョニングは不要です。既存クライアントを壊さずに新しいフィールドを追加できます。古いフィールドは@deprecatedディレクティブで非推奨にできます。クライアントは使用するフィールドのみをリクエストします。
6. 開発者体験
REST: 広く理解されており、シンプルなコンセプト、豊富なツール(APIテストツール)、巨大なエコシステムがあります。
GraphQL: 強い型付け、自動生成ドキュメント(GraphiQL/GraphQL Playground)、イントロスペクション、クエリのIDEオートコンプリートがあります。
コード比較: 同じ機能を構築する
ユーザー情報、最近の投稿、フォロワー数を表示するユーザープロフィールページを構築してみましょう。
REST実装
// REST: 3回の個別APIコール
async function loadUserProfile(userId) {
// コール1: ユーザーデータを取得
const userRes = await fetch(`/api/users/${userId}`);
const user = await userRes.json();
// コール2: ユーザーの投稿を取得
const postsRes = await fetch(`/api/users/${userId}/posts?limit=5`);
const posts = await postsRes.json();
// コール3: フォロワー数を取得
const followersRes = await fetch(`/api/users/${userId}/followers/count`);
const followers = await followersRes.json();
return { user, posts, followers: followers.count };
}
// ネットワークラウンドトリップ3回、各コールでオーバーフェッチの可能性
GraphQL実装
// GraphQL: 必要なフィールドだけを1回のAPIコールで取得
async function loadUserProfile(userId) {
const query = `
query UserProfile($id: ID!) {
user(id: $id) {
name
email
avatar
posts(limit: 5) {
title
createdAt
commentCount
}
followerCount
}
}
`;
const res = await fetch('/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables: { id: userId } }),
});
const { data } = await res.json();
return data.user;
}
// ネットワークラウンドトリップ1回、必要なデータのみ
GraphQL vs REST APIのテスト
どちらのAPIスタイルも徹底的なテストが必要ですが、アプローチが異なります。
REST APIのテスト
REST APIのテストは簡単です。各エンドポイントをさまざまなHTTPメソッド、パラメーター、ペイロードでテストします。詳細はREST APIテストガイドをご覧ください。
GraphQL APIのテスト
// JestでGraphQLをテスト
describe('GraphQL User Queries', () => {
test('選択したフィールドでユーザーを取得する', async () => {
const query = `
query { user(id: "1") { name email } }
`;
const res = await request(app)
.post('/graphql')
.send({ query })
.expect(200);
expect(res.body.data.user).toEqual({
name: 'John Doe',
email: 'john@example.com',
});
// 余分なフィールドが返されないことを確認
expect(Object.keys(res.body.data.user)).toHaveLength(2);
});
test('ネストされたクエリを処理する', async () => {
const query = `
query {
user(id: "1") {
name
posts(limit: 2) { title }
}
}
`;
const res = await request(app)
.post('/graphql')
.send({ query })
.expect(200);
expect(res.body.data.user.posts).toHaveLength(2);
});
test('存在しないユーザーのエラーを返す', async () => {
const query = `query { user(id: "99999") { name } }`;
const res = await request(app)
.post('/graphql')
.send({ query })
.expect(200); // GraphQLは常に200を返す
expect(res.body.errors).toBeDefined();
expect(res.body.errors[0].message).toContain('not found');
});
});
REST APIとGraphQL APIの両方の自動テスト生成には、Qodex.aiがAPIの仕様を分析して包括的なテストスイートを生成できます。
REST vs GraphQLの使い分け
RESTを選ぶ場合
- シンプルなCRUD操作と明快なデータモデルが必要な場合
- HTTPキャッシュとCDNサポートが重要な場合
- チームがRESTに慣れており、素早く動く必要がある場合
- サードパーティが利用するパブリックAPIを構築している場合
- APIリソースがURLパターンに綺麗にマッピングされる場合
- ネイティブでファイルアップロードをサポートする必要がある場合
GraphQLを選ぶ場合
- クライアントが柔軟で多様なデータ要件を持つ場合(モバイル vs ウェブ vs TV)
- データモデルに多くのリレーションシップがある場合(SNS、ECカタログ)
- ネットワークリクエスト数を減らしたい場合
- フロントエンドチームがバックエンドの変更なしにデータをリクエストしたい場合
- 複数のバックエンドサービスからデータを集約している場合
- リアルタイム機能が必要な場合(GraphQLサブスクリプション)
両方を使う(ハイブリッドアプローチ)
多くの組織は、シンプルでキャッシュ可能なパブリックエンドポイントにはRESTを使い、複雑な内部のクライアント固有のデータ要件にはGraphQLを使っています。GitHubがRESTとGraphQL両方のAPIを提供しているのも珍しいことではありません。
GraphQL vs REST vs gRPC
gRPCを含む完全な比較については、gRPCがバイナリシリアライゼーション(Protocol Buffers)でサーバー間通信に優れており、RESTとGraphQLはクライアントとサーバー間の通信に適していることを考慮してください。また、厳格なコントラクトを持つエンタープライズシステムでは、SOAPも依然として有力な選択肢です。
| 観点 | REST | GraphQL | gRPC |
|---|---|---|---|
| 最適な用途 | CRUD、パブリックAPI | 複雑なクエリ、モバイル | マイクロサービス、ストリーミング |
| データ形式 | JSON(主に) | JSON | Protocol Buffers(バイナリ) |
| パフォーマンス | 良好 | 良好(オーバーフェッチ少) | 優秀(バイナリ) |
| キャッシュ | 優秀(HTTPネイティブ) | 複雑(アプリレベル) | 手動 |
| 学習曲線 | 低 | 中 | 高 |
| ブラウザサポート | ネイティブ | fetch/POST経由 | grpc-web経由 |
よくある質問
GraphQLとRESTの主な違いは何ですか?
RESTは固定されたレスポンス構造を持つ複数のエンドポイント(リソースごとに1つ)を使います。GraphQLはクライアントがクエリ言語を通じて必要なデータを正確に指定する単一のエンドポイントを使います。RESTはデータのオーバーフェッチやアンダーフェッチが発生することがありますが、GraphQLは要求されたフィールドのみを正確に返します。
GraphQLはRESTより速いですか?
ユースケースによります。GraphQLは複数のラウンドトリップを排除し(1回のクエリで関連データを取得)、ペイロードサイズを削減(オーバーフェッチなし)することで高速化できます。RESTはHTTPキャッシュとCDNがネイティブに機能するため、シンプルでキャッシュ可能なリクエストでは高速になることがあります。パフォーマンスが重要なアプリケーションでは、特定のデータパターンで両方のアプローチをベンチマークすることをお勧めします。
GraphQL vs REST APIはいつ使うべきですか?
シンプルなCRUD操作、パブリックAPI、HTTPキャッシュが重要な場合はRESTを使いましょう。クライアントが多様なデータ要件を持つ場合、データに複雑なリレーションシップがある場合、またはモバイルアプリケーションのネットワークリクエストを最小化する必要がある場合はGraphQLを使いましょう。多くのチームは両方を使っています。シンプルなエンドポイントにはREST、複雑なデータ要件にはGraphQLというように。
GraphQLはRESTを完全に置き換えられますか?
技術的には可能ですが、実際には多くの組織が両方を並行して使っています。RESTはシンプルなリソースに向いており、ネイティブHTTPキャッシュの恩恵を受けられます。GraphQLは複雑でネストされたデータ要件で力を発揮します。選択は教条主義ではなく、具体的なニーズによって決まるべきです。
GraphQL APIのテストはREST APIと比べてどう違いますか?
REST APIのテストはHTTPメソッド(GET、POST、PUT、DELETE)で特定のエンドポイントをターゲットにします。GraphQLのテストはクエリ/ミューテーションを単一のエンドポイントに送信し、レスポンスの構造を検証します。どちらも認証、認可、エラーハンドリング、パフォーマンスのテストが必要です。REST固有の手法についてはREST APIテストガイドをご覧ください。Qodex.aiなどのツールはRESTとGraphQLの両方のテストをサポートしています。
FacebookはなぜGraphQLを作りましたか?
Facebookは2012年にモバイルアプリのパフォーマンス問題を解決するためにGraphQLを作成しました。REST APIはデータを過剰に返し(オーバーフェッチ)、複雑なビューを構築するためには多くのラウンドトリップが必要でした。GraphQLはモバイルクライアントが各画面に必要なデータだけをリクエストできるようにし、帯域幅の使用量を削減してアプリのパフォーマンスを向上させました。2015年にオープンソース化されました。



