alltools.one
API
2025-06-30
9 min
alltools.one Team
JSONAPIRESTDesign PatternsBackend

JSON APIデザインパターン:より良いREST APIの構築

適切に設計されたAPIは使うのが楽しいものです。設計が不十分なものはバグ、フラストレーション、技術的負債を生みます。このガイドでは、一貫性があり、発見しやすく、保守しやすいJSON REST APIを設計するための実証済みパターンを紹介します。

リソース命名

リソースは名詞であり、動詞ではありません。コレクションには複数形名詞を、IDによる単一リソースには単数形を使用します:

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

命名規則

  • 小文字とハイフンを使用:/api/blog-postsblogPostsblog_postsではなく)
  • 関連リソースをネスト:/api/users/123/orders
  • ネストは2レベルまでに制限:/api/users/123/orders/456(それ以上深くしない)
  • URLに動詞を避ける:CRUDにマッピングされないアクションの場合は/api/users/123/activateは許容

レスポンスエンベロープ

一貫したエンベロープでレスポンスをラップします:

{
  "data": {
    "id": "123",
    "type": "user",
    "attributes": {
      "name": "Alice",
      "email": "alice@example.com",
      "createdAt": "2024-01-15T10:30:00Z"
    }
  },
  "meta": {
    "requestId": "req_abc123"
  }
}

コレクションの場合:

{
  "data": [
    { "id": "123", "name": "Alice" },
    { "id": "456", "name": "Bob" }
  ],
  "meta": {
    "total": 142,
    "page": 1,
    "perPage": 20
  }
}

JSONバリデーターでAPIレスポンスを検証し、スキーマに一致するか確認しましょう。

ページネーション

3つの一般的なアプローチ:

オフセットベース(最もシンプル)

GET /api/users?page=2&per_page=20
{
  "data": [...],
  "meta": {
    "page": 2,
    "perPage": 20,
    "total": 142,
    "totalPages": 8
  }
}

利点: シンプル、任意のページにジャンプ可能。欠点: 同時挿入/削除で結果が不整合になる。

カーソルベース(最も信頼性が高い)

GET /api/users?cursor=eyJpZCI6MTIzfQ&limit=20
{
  "data": [...],
  "meta": {
    "hasNext": true,
    "nextCursor": "eyJpZCI6MTQzfQ"
  }
}

利点: 同時変更でも一貫性あり、大規模データセットでパフォーマンスが良い。欠点: 任意のページにジャンプ不可。

キーセットベース(最もパフォーマンスが高い)

GET /api/users?after_id=123&limit=20

最後のアイテムのID(またはソートフィールド)を使用して次のページを取得します。カーソルベースに似ていますが、パラメーターが透過的です。

推奨: リアルタイムフィードや大規模データセットにはカーソルベース。ページジャンプが必要な管理ダッシュボードにはオフセットベース。

フィルタリングとソート

フィルタリング

GET /api/users?status=active&role=admin
GET /api/users?created_after=2024-01-01
GET /api/users?search=alice

複雑なフィルターには専用のクエリパラメーターを検討:

GET /api/users?filter[status]=active&filter[role]=admin

ソート

GET /api/users?sort=name          # 昇順
GET /api/users?sort=-created_at   # 降順(-をプレフィックス)
GET /api/users?sort=-created_at,name  # 複数フィールド

エラーハンドリング

一貫したエラーレスポンスはAPIの使いやすさに不可欠です:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "message": "Must be a valid email address",
        "value": "not-an-email"
      },
      {
        "field": "age",
        "message": "Must be between 0 and 150",
        "value": -5
      }
    ]
  },
  "meta": {
    "requestId": "req_abc123"
  }
}

使用すべきHTTPステータスコード

コード意味使用場面
200OK成功したGET、PUT
201Created成功したPOST
204No Content成功したDELETE
400Bad Requestバリデーションエラー
401Unauthorized認証なし/無効
403Forbidden認証は有効だが権限不足
404Not Foundリソースが存在しない
409Conflictリソースの重複、バージョン競合
422Unprocessable意味的に無効
429Too Many Requestsレート制限超過
500Internal Error予期しないサーバーエラー

バージョニング

3つのアプローチ:

URLパス(推奨)

GET /api/v1/users
GET /api/v2/users

利点: 明示的、ルーティングが容易、テストが容易。

ヘッダーベース

GET /api/users
Accept: application/vnd.myapi.v2+json

利点: クリーンなURL。欠点: テストが困難、発見しにくい。

クエリパラメーター

GET /api/users?version=2

利点: テストが容易。欠点: オプションパラメーターのセマンティクス。

推奨: URLパスバージョニングが最も実用的です。明示的で、キャッシュ可能で、あらゆるHTTPツールで動作します。

日付と時間の処理

常にUTCのISO 8601を使用:

{
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T14:22:33Z",
  "expiresAt": "2024-12-31T23:59:59Z"
}

APIレスポンスでUnixタイムスタンプを使用しないでください — 曖昧(秒かミリ秒か)で人間が読めません。タイムスタンプの処理について詳しくは、Unixタイムスタンプガイドをご覧ください。

レート制限

レスポンスヘッダーでレート制限を伝えます:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 67
X-RateLimit-Reset: 1705312800
Retry-After: 30

制限を超えた場合は429 Too Many Requestsを返し、明確なエラーメッセージとRetry-Afterヘッダーを含めます。

HATEOAS(オプションだが強力)

関連リソースとアクションへのリンクを含めます:

{
  "data": {
    "id": "123",
    "name": "Alice",
    "links": {
      "self": "/api/users/123",
      "orders": "/api/users/123/orders",
      "avatar": "/api/users/123/avatar"
    }
  }
}

これによりAPIが自己文書化され、クライアント側でのURL構築が削減されます。

FAQ

JSON:API仕様を使うべきですか、それとも独自フォーマットを設計すべきですか?

JSON:API仕様(jsonapi.org)は包括的な標準を提供しますが、シンプルなAPIには冗長になる可能性があります。ほとんどのプロジェクトでは、このガイドのパターンに従ってシンプルなカスタムフォーマットを設計する方が実用的です。自動クライアントライブラリと厳密な標準が必要な場合はJSON:APIを使用してください。

部分更新はどう処理すべきですか(PATCH vs PUT)?

PUTは完全なリソース置換(クライアントがすべてのフィールドを送信)に使用します。PATCHは部分更新(クライアントが変更されたフィールドのみを送信)に使用します。JSON Merge Patch(RFC 7396)を使用したPATCHが最もシンプルなアプローチです:更新するフィールドのみを含むJSONオブジェクトを送信し、フィールドを削除するにはnullを指定します。

関連リソース

Published on 2025-06-30
JSON API Design Patterns: Building Better REST APIs | alltools.one