API はチームとの「契約」
API は内部実装の詳細を隠しつつ、クライアントとの**インターフェース(契約)**を提供します。一度公開した API の破壊的変更は、使っているクライアントをすべて壊します。
だからこそ、設計段階で十分に考える価値があります。
ルール 1:リソース名は名詞・複数形
✅ GET /users
✅ GET /users/123
✅ POST /orders
✅ DELETE /products/456
❌ GET /getUser
❌ POST /createOrder
❌ DELETE /deleteProduct?id=456
動詞はメソッド(GET/POST/PUT/DELETE)が担います。URI はリソースを表す名詞にします。
ルール 2:HTTP メソッドを正しく使う
| メソッド | 操作 | べき等か | 例 |
|---|---|---|---|
| GET | 取得 | ✅ | GET /users/123 |
| POST | 作成 | ❌ | POST /users |
| PUT | 全体更新 | ✅ | PUT /users/123 |
| PATCH | 部分更新 | ✅ | PATCH /users/123 |
| DELETE | 削除 | ✅ | DELETE /users/123 |
べき等(idempotent):同じリクエストを何度送っても結果が変わらない性質。GET/PUT/DELETE はべき等、POST は毎回新しいリソースを作るので非べき等。
ルール 3:適切な HTTP ステータスコードを返す
2xx 成功
200 OK — GET / PUT / DELETE 成功
201 Created — POST でリソース作成成功(Location ヘッダも返す)
204 No Content — 成功だが返すボディがない(DELETE など)
4xx クライアントエラー
400 Bad Request — リクエストの形式・バリデーションエラー
401 Unauthorized — 未認証(ログインしていない)
403 Forbidden — 認証済みだが権限なし
404 Not Found — リソースが存在しない
409 Conflict — 競合(例:すでに存在するメールアドレス)
422 Unprocessable — バリデーションエラー(詳細を body に)
5xx サーバーエラー
500 Internal Server Error — サーバー側のバグ
503 Service Unavailable — 一時的な障害
// 400 エラーのレスポンス例
{
"error": {
"code": "VALIDATION_FAILED",
"message": "バリデーションエラーが発生しました",
"details": [
{ "field": "email", "message": "メールアドレスの形式が正しくありません" },
{ "field": "age", "message": "18歳以上を入力してください" }
]
}
}
ルール 4:一貫したレスポンス構造
エンドポイントごとにレスポンス構造がバラバラだとクライアントの実装コストが上がります。
// 単一リソース
{
"data": {
"id": 123,
"name": "田中太郎",
"email": "tanaka@example.com",
"createdAt": "2026-04-25T10:00:00Z"
}
}
// コレクション(ページネーション付き)
{
"data": [...],
"meta": {
"total": 1543,
"page": 1,
"perPage": 20,
"totalPages": 78
}
}
ルール 5:ネストは 2 階層まで
✅ GET /users/123/orders
✅ GET /orders/456/items
❌ GET /users/123/orders/456/items/789/reviews
→ GET /items/789/reviews に分解
深すぎるネストは URL が脆くなり、変更に弱くなります。
ルール 6:フィルタ・ソート・ページネーションはクエリパラメータ
GET /products?category=electronics&minPrice=10000&sortBy=price&order=asc&page=2&perPage=20
これらをパスに入れるのは NG です。
❌ GET /products/electronics/sort-by-price/page-2
ルール 7:日時は ISO 8601・タイムゾーン付き
// ✅ UTC で統一
"createdAt": "2026-04-25T10:00:00Z"
// ❌ タイムゾーン不明
"createdAt": "2026/04/25 10:00:00"
サーバーは UTC で管理し、表示はクライアント側でローカル変換します。
ルール 8:バージョニング戦略を最初に決める
# URLパス方式(最もシンプル・推奨)
GET /v1/users
GET /v2/users
# ヘッダ方式(URLが汚れない)
GET /users
Accept: application/vnd.myapi.v2+json
バージョニングは最初から設計に含めます。後からの追加は難しい。
破壊的変更(フィールド削除・型変更・必須化)は必ず新バージョンに。
ルール 9:認証には Bearer トークン
GET /users/me HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
- Cookie 認証は CSRF リスクあり(API には不向き)
- Basic 認証は毎回認証情報を送信するので NG
- JWT の場合はペイロードに機密情報を入れない(Base64 は暗号化ではない)
ルール 10:API ドキュメントは OpenAPI で自動生成
# openapi.yaml
openapi: 3.0.0
info:
title: My API
version: "1.0"
paths:
/users/{id}:
get:
summary: ユーザー取得
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: 成功
コードファーストなら swagger-jsdoc、スキーマファーストなら OpenAPI Generator でクライアント SDK を自動生成できます。
まとめ
| ルール | ポイント |
|---|---|
| 1. 名詞・複数形 | /users, /orders |
| 2. メソッドを正しく | GET=取得, POST=作成, PUT=更新, DELETE=削除 |
| 3. ステータスコード | 200/201/400/401/403/404/422/500 |
| 4. 一貫した構造 | { "data": ... } + ページネーション |
| 5. ネストは 2 階層 | /users/123/orders まで |
| 6. フィルタはクエリパラメータ | ?page=2&sortBy=price |
| 7. UTC で管理 | 2026-04-25T10:00:00Z |
| 8. バージョニング | /v1/, /v2/ を最初から |
| 9. Bearer 認証 | JWT + Authorization ヘッダ |
| 10. OpenAPI | ドキュメントを自動生成 |
API の品質はその API を使うすべてのクライアントの品質に直結します。最初の設計に時間をかける価値は十分にあります。