REST API設計入門 - 原則・HTTPメソッド・エンドポイント設計のベストプラクティス
REST APIの基本原則、HTTPメソッドの使い分け、エンドポイント設計、ステータスコード、認証方式をまとめたリファレンス。
RESTとは何か
REST(Representational State Transfer)は、2000年にRoy Fielding氏が博士論文で提唱したアーキテクチャスタイルである。RESTはプロトコルや規格ではなく、Webの設計思想を体系化した制約の集合であり、これらの制約に従って設計されたAPIを「RESTful API」と呼ぶ。
RESTの6つの制約
RESTは以下の6つの制約(原則)で構成されている。これらを理解することで、設計判断の根拠が明確になる。
1. クライアント-サーバー(Client-Server)
クライアント(UIやフロントエンド)とサーバー(データ処理やビジネスロジック)を明確に分離する。これにより、それぞれが独立して進化・スケールできる。フロントエンドをReactからVueに変更しても、APIが変わらなければバックエンドへの影響はない。
2. ステートレス(Stateless)
サーバーはクライアントの状態(セッション)を保持しない。各リクエストには、処理に必要なすべての情報(認証トークンなど)が含まれている必要がある。これによりサーバーのスケールアウトが容易になり、どのサーバーインスタンスがリクエストを受けても同じ結果を返せる。
3. キャッシュ可能(Cacheable)
レスポンスはキャッシュ可能かどうかを明示する必要がある。適切なキャッシュにより、クライアントが不要なリクエストを送らずに済み、パフォーマンスが向上する。HTTPのCache-ControlやETagヘッダーがこの制約を実現する仕組みである。
4. 統一インターフェース(Uniform Interface)
RESTの最大の特徴であり、すべてのリソースに対して統一された方法でアクセスする。具体的には以下の4つの原則で構成される。
- リソースの識別: URIによってリソースを一意に識別する
- 表現を通じたリソース操作: JSON・XMLなどの表現形式でリソースを操作する
- 自己記述的メッセージ: リクエスト・レスポンスに処理に必要な情報がすべて含まれる
- HATEOAS: レスポンスに次に取りうるアクションへのリンクを含める
5. 階層化システム(Layered System)
クライアントは直接サーバーに接続しているのか、ロードバランサーやCDN経由なのかを意識する必要がない。中間層(プロキシ、ゲートウェイ等)を挿入してもシステムが正しく動作する。
6. コードオンデマンド(Code on Demand)(任意)
唯一のオプション制約である。サーバーがクライアントに実行可能なコード(JavaScriptなど)を送信できる。Webページで<script>タグを通じてJavaScriptが配信されるのが典型例である。
HTTPメソッドの使い分け
REST APIでは、HTTPメソッドを使ってリソースに対する操作を表現する。CRUD操作との対応を理解することが設計の基本である。
GET - リソースの取得
リソースの読み取りに使用する。サーバーの状態を変更しない安全なメソッドであり、何度実行しても同じ結果を返す冪等性を持つ。
GET /api/users # ユーザー一覧の取得
GET /api/users/42 # ID=42のユーザーを取得
GET /api/users?role=admin # クエリパラメータで絞り込み
POST - リソースの作成
新しいリソースの作成に使用する。同じリクエストを複数回送ると、複数のリソースが作成される可能性があるため、冪等ではない。
POST /api/users # 新しいユーザーを作成
PUT - リソースの全体更新
既存リソースの全体を置き換える操作に使用する。冪等性を持ち、同じリクエストを何度送っても結果は同じである。
PUT /api/users/42 # ID=42のユーザー情報を全体更新
PATCH - リソースの部分更新
リソースの一部のフィールドだけ更新する場合に使用する。PUTとの違いは、送信するのが変更したいフィールドのみという点である。
PATCH /api/users/42 # ID=42のユーザーの一部を更新
DELETE - リソースの削除
リソースの削除に使用する。冪等であり、すでに削除されたリソースに対してDELETEを送っても結果(「存在しない」状態)は同じである。
DELETE /api/users/42 # ID=42のユーザーを削除
| メソッド | 操作 | 冪等性 | 安全性 |
|---|---|---|---|
| GET | 取得 | あり | あり |
| POST | 作成 | なし | なし |
| PUT | 全体更新 | あり | なし |
| PATCH | 部分更新 | 条件付き | なし |
| DELETE | 削除 | あり | なし |
エンドポイントURL設計のベストプラクティス
リソース指向で設計する
URLは**名詞(リソース)**を表し、動詞(操作)はHTTPメソッドで表現する。
# 良い例(名詞・リソース指向)
GET /api/articles
POST /api/articles
GET /api/articles/15
PUT /api/articles/15
DELETE /api/articles/15
# 悪い例(動詞がURLに入っている)
GET /api/getArticles
POST /api/createArticle
POST /api/deleteArticle/15
複数形を使う
リソース名は複数形で統一する。単数と複数が混在すると、API利用者が迷う原因になる。
# 良い例
/api/users
/api/products
/api/orders
# 悪い例
/api/user
/api/product-list
ネストでリレーションを表現する
リソース間の関連は、URLのネストで直感的に表現できる。ただし、3階層以上のネストは避け、クエリパラメータの利用を検討する。
# ユーザー42の注文一覧
GET /api/users/42/orders
# ユーザー42の注文100の詳細
GET /api/users/42/orders/100
# 深すぎるネスト(避けるべき)
GET /api/users/42/orders/100/items/3/reviews
# 代わりにフラットにする
GET /api/order-items/3/reviews
バージョニング
APIの互換性を壊す変更が必要な場合に備えて、バージョンをURLに含めるのが一般的である。
/api/v1/users
/api/v2/users
ヘッダーでバージョンを指定する方式もあるが、URLベースのほうが直感的で広く採用されている。
ステータスコードの使い分け
HTTPステータスコードは、リクエストの処理結果をクライアントに正しく伝えるために不可欠である。すべてのレスポンスを200で返してボディ内にエラー情報を入れるのは、RESTfulな設計ではない。
2xx 成功系
| コード | 意味 | 使い方 |
|---|---|---|
| 200 OK | 成功 | GET、PUT、PATCHの成功時 |
| 201 Created | リソース作成成功 | POSTでリソースが作られた時 |
| 204 No Content | 成功(レスポンスボディなし) | DELETEの成功時 |
4xx クライアントエラー
| コード | 意味 | 使い方 |
|---|---|---|
| 400 Bad Request | リクエスト不正 | バリデーションエラー、不正なJSON |
| 401 Unauthorized | 認証エラー | トークン未送信、トークン期限切れ |
| 403 Forbidden | 権限不足 | 認証済みだが操作権限がない |
| 404 Not Found | リソースが存在しない | 指定IDのリソースがない |
| 409 Conflict | 競合 | 重複登録、楽観ロック失敗 |
| 422 Unprocessable Entity | 処理不能 | 形式は正しいが意味的に不正 |
| 429 Too Many Requests | レート制限 | API呼び出し回数の上限超過 |
5xx サーバーエラー
| コード | 意味 | 使い方 |
|---|---|---|
| 500 Internal Server Error | サーバー内部エラー | 予期しない例外が発生 |
| 503 Service Unavailable | サービス利用不可 | メンテナンス中、過負荷 |
リクエスト・レスポンスの具体例
以下にAPI通信の具体例を示す。
ユーザー作成(POST)
リクエスト:
POST /api/v1/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
{
"name": "田中太郎",
"email": "tanaka@example.com",
"role": "editor"
}
レスポンス(成功):
HTTP/1.1 201 Created
Content-Type: application/json
Location: /api/v1/users/42
{
"id": 42,
"name": "田中太郎",
"email": "tanaka@example.com",
"role": "editor",
"createdAt": "2026-03-03T10:30:00Z"
}
ユーザー一覧取得(GET)
リクエスト:
GET /api/v1/users?page=1&limit=20&role=editor HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
レスポンス(成功):
{
"data": [
{
"id": 42,
"name": "田中太郎",
"email": "tanaka@example.com",
"role": "editor"
},
{
"id": 58,
"name": "鈴木花子",
"email": "suzuki@example.com",
"role": "editor"
}
],
"pagination": {
"page": 1,
"limit": 20,
"totalItems": 2,
"totalPages": 1
}
}
バリデーションエラー(POST)
レスポンス(エラー):
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "入力値に問題があります",
"details": [
{
"field": "email",
"message": "メールアドレスの形式が正しくありません"
},
{
"field": "name",
"message": "名前は1文字以上100文字以内で入力してください"
}
]
}
}
エラーレスポンスの形式をAPI全体で統一すると、クライアント側のエラーハンドリングが簡素化される。
認証方式の概要
APIを公開する際、誰がアクセスしているのかを識別し、適切な権限制御を行う必要がある。以下は代表的な認証方式である。
APIキー認証
最もシンプルな方式である。サーバーが発行した固定の文字列をリクエストに含めて送信する。
GET /api/v1/data HTTP/1.1
X-API-Key: sk-abc123def456ghi789
メリット: 実装が簡単、サーバー間通信に適している デメリット: キーが漏洩すると不正利用されるリスクが高い、きめ細かい権限制御が難しい
主にサーバー間通信や、公開APIのレート制限用途で使われる。
OAuth 2.0
ユーザーが第三者アプリケーションにリソースへのアクセスを委譲するための標準的なフレームワークである。「Googleでログイン」「GitHubでログイン」などのソーシャルログインはOAuth 2.0がベースである。
認可コードフロー(最も一般的)の流れは以下の通りである。
- クライアントがユーザーを認可サーバーにリダイレクト
- ユーザーが認可サーバーでログイン・許可
- 認可サーバーがクライアントに認可コードを返す
- クライアントが認可コードをアクセストークンに交換
- アクセストークンでAPIにアクセス
メリット: パスワードを第三者に渡さずに済む、スコープで権限を制限可能 デメリット: 実装が複雑、フロー全体の理解が必要
JWT(JSON Web Token)
認証情報をJSON形式でエンコードし、署名付きのトークンとして発行する方式である。トークン自体にユーザー情報が含まれているため、サーバー側でセッションを保持する必要がない。
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiI0MiIsIm5hbWUiOiJ0YW5ha2EiLCJyb2xlIjoiZWRpdG9yIiwiZXhwIjoxNzA5MjI0MDAwfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
JWTは3つの部分(ヘッダー、ペイロード、署名)をBase64エンコードしてドット(.)で連結した文字列である。
メリット: ステートレス(サーバー側のセッション管理が不要)、マイクロサービスに適している デメリット: トークンのサイズが大きい、発行後の無効化が困難(有効期限まで使える)
実務では、OAuth 2.0のアクセストークンとしてJWTを使う組み合わせが一般的である。
API設計で意識すべきポイント
実務でのAPI設計における重要なポイントを以下に示す。
一貫性を保つ
命名規則(キャメルケースかスネークケースか)、エラーレスポンスの形式、ページネーションの仕組みなど、API全体で統一する。一貫性のあるAPIは学習コストが低く、利用者の生産性を高める。
ページネーションを設計する
大量のデータを返すエンドポイントには、ページネーションの実装が必須である。オフセットベース(?page=2&limit=20)とカーソルベース(?cursor=abc123&limit=20)の2種類があり、データ量やユースケースに応じて選択する。
適切なフィルタリングとソート
クエリパラメータを活用して、クライアントが必要なデータを効率的に取得できるようにする。
GET /api/v1/articles?status=published&sort=-createdAt&fields=id,title
レート制限を実装する
APIの安定性を守るために、レート制限は必須である。429 Too Many Requestsを返す際は、Retry-Afterヘッダーで待機時間を通知する。
ドキュメントを充実させる
OpenAPI(Swagger)仕様でAPIを記述し、自動生成ツール(Swagger UI、Redocなど)でドキュメントを公開するのが現在のベストプラクティスである。