REST と GraphQL の概要

Web APIの設計手法として、RESTGraphQLは最も広く使われている2つのアプローチです。どちらにも長所と短所があり、プロジェクトの要件に応じた選択が重要です。

REST とは

REST(Representational State Transfer)は、HTTPメソッドとURLでリソースを操作するアーキテクチャスタイルです。

GET    /api/users          # ユーザー一覧
GET    /api/users/123      # ユーザー詳細
POST   /api/users          # ユーザー作成
PUT    /api/users/123      # ユーザー更新
DELETE /api/users/123      # ユーザー削除

GraphQL とは

GraphQL は、クライアントが必要なデータの形を指定してクエリを送るクエリ言語です。

query {
  user(id: 123) {
    name
    email
    posts {
      title
      createdAt
    }
  }
}

比較表

項目RESTGraphQL
エンドポイントリソースごとに複数単一エンドポイント
データ取得サーバーが決めた形クライアントが指定
オーバーフェッチ起きやすい起きない
アンダーフェッチ起きやすい起きない
キャッシュHTTPキャッシュが使える独自のキャッシュが必要
ファイルアップロード標準的追加ライブラリが必要
学習コスト低いやや高い
ツール・エコシステム非常に豊富急速に成長中
リアルタイムWebSocket等を別途用意Subscriptionで対応
型定義OpenAPI/Swaggerスキーマで自動

REST のメリット・デメリット

メリット

1. HTTPの仕組みをフル活用できる

# キャッシュヘッダーがそのまま使える
GET /api/users/123
Cache-Control: max-age=3600
ETag: "abc123"

# ステータスコードが明確
200 OK
201 Created
404 Not Found

2. シンプルで理解しやすい

URLを見ればどのリソースにアクセスしているかが明確です。

3. ツールが豊富

curl、Postman、OpenAPI/Swagger、各言語のHTTPクライアントなど、成熟したエコシステムがあります。

デメリット

1. オーバーフェッチ(余分なデータを取得)

// ユーザー名だけ欲しいのに全フィールドが返ってくる
GET /api/users/123
{
  "id": 123,
  "name": "田中太郎",
  "email": "[email protected]",
  "address": "...",
  "phone": "...",
  "createdAt": "...",
  "updatedAt": "..."
}

2. アンダーフェッチ(複数リクエストが必要)

# ユーザーとその投稿を取得するのに2回リクエストが必要
GET /api/users/123
GET /api/users/123/posts

3. バージョニングの悩み

/api/v1/users
/api/v2/users  # フィールド追加時に新バージョンが必要

GraphQL のメリット・デメリット

メリット

1. 必要なデータだけ取得できる

# 名前だけ欲しい場合
query {
  user(id: 123) {
    name
  }
}

# 投稿も含めて欲しい場合(1リクエストで完結)
query {
  user(id: 123) {
    name
    posts {
      title
    }
  }
}

2. 型システムが強力

type User {
  id: ID!
  name: String!
  email: String!
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  content: String!
  author: User!
}

スキーマから自動的にドキュメントとTypeScriptの型が生成されます。

3. バージョニングが不要

フィールドの追加は後方互換性を保ちます。不要になったフィールドは @deprecated を付けるだけです。

type User {
  id: ID!
  name: String!
  fullName: String!  # 新フィールド
  email: String! @deprecated(reason: "Use contactEmail instead")
  contactEmail: String!
}

デメリット

1. N+1問題

query {
  users {       # 1回のクエリ
    posts {     # ユーザーごとに1回ずつDB問い合わせ → N+1
      title
    }
  }
}

解決策: DataLoaderパターンを使う。

2. HTTPキャッシュが使えない

すべてのリクエストが POST /graphql なので、HTTPレベルのキャッシュが効きません。Apollo Client等のクライアントキャッシュで対応します。

3. ファイルアップロードが面倒

GraphQLの仕様にはファイルアップロードが含まれていません。graphql-upload 等の追加ライブラリが必要です。

選定基準

REST を選ぶべきケース

  • シンプルなCRUD API: リソースが明確で関連が少ない
  • パブリックAPI: サードパーティ開発者が使いやすい
  • キャッシュが重要: CDNでのHTTPキャッシュを活用したい
  • ファイル操作が多い: アップロード・ダウンロードが頻繁
  • チームがRESTに慣れている: 学習コストを抑えたい

GraphQL を選ぶべきケース

  • 複雑なデータ関連: ネストした関連データが多い
  • 複数クライアント: Web・モバイル・デスクトップで異なるデータが必要
  • 頻繁なUI変更: フロントエンドの変更にバックエンドが追従しなくて良い
  • リアルタイム機能: Subscriptionでチャットや通知を実装
  • マイクロサービス: 複数サービスのデータを1つのエンドポイントで統合

実装例

REST(Express.js)

const express = require('express');
const app = express();

// ユーザー一覧
app.get('/api/users', async (req, res) => {
  const users = await db.users.findAll();
  res.json(users);
});

// ユーザー詳細
app.get('/api/users/:id', async (req, res) => {
  const user = await db.users.findById(req.params.id);
  if (!user) return res.status(404).json({ error: 'Not found' });
  res.json(user);
});

// ユーザー作成
app.post('/api/users', async (req, res) => {
  const user = await db.users.create(req.body);
  res.status(201).json(user);
});

GraphQL(Apollo Server)

const typeDefs = `
  type User {
    id: ID!
    name: String!
    email: String!
    posts: [Post!]!
  }

  type Post {
    id: ID!
    title: String!
    author: User!
  }

  type Query {
    users: [User!]!
    user(id: ID!): User
  }

  type Mutation {
    createUser(name: String!, email: String!): User!
  }
`;

const resolvers = {
  Query: {
    users: () => db.users.findAll(),
    user: (_, { id }) => db.users.findById(id),
  },
  User: {
    posts: (user) => db.posts.findByUserId(user.id),
  },
  Mutation: {
    createUser: (_, { name, email }) =>
      db.users.create({ name, email }),
  },
};

ハイブリッドアプローチ

REST と GraphQL は排他的ではありません。組み合わせて使うことも有効です。

/api/upload      → REST(ファイルアップロード)
/api/webhooks    → REST(Webhook受信)
/graphql         → GraphQL(データ取得・更新)

まとめ

判断軸RESTGraphQL
シンプルさ重視
柔軟なデータ取得
HTTPキャッシュ
型安全
学習コスト低いやや高い

最終的には「チームのスキル」「プロジェクトの複雑さ」「クライアントの多様性」で判断しましょう。どちらを選んでも、一貫した設計と適切なドキュメントが最も重要です。


APIのレスポンスを整形して確認するには、AssistyのJSONフォーマッターをご活用ください。ブラウザ上でJSONを見やすく整形・バリデーションできます。