ストーリー
高橋アーキテクトが2つのAPI仕様書を並べた。
左のAPIは /getUserInfo?action=get&uid=123、 右のAPIは GET /api/v1/users/123。
実例比較:ユーザー管理API
悪いAPI設計
// 悪い例1: 動詞をURLに含める
POST /api/getUserById
Body: { "userId": 123 }
POST /api/createNewUser
Body: { "name": "田中", "email": "tanaka@example.com" }
POST /api/updateUserInfo
Body: { "userId": 123, "name": "田中太郎" }
POST /api/removeUser
Body: { "userId": 123 }
// 問題点:
// - すべてPOSTメソッド(HTTPメソッドの意味を無視)
// - URLに動詞が含まれている
// - 一貫性がない(get/create/update/remove とバラバラ)
良いAPI設計
// 良い例: RESTful設計
GET /api/v1/users // ユーザー一覧取得
GET /api/v1/users/123 // 特定ユーザー取得
POST /api/v1/users // ユーザー作成
PUT /api/v1/users/123 // ユーザー更新(完全置換)
PATCH /api/v1/users/123 // ユーザー更新(部分更新)
DELETE /api/v1/users/123 // ユーザー削除
// 利点:
// - HTTPメソッドが操作を表現
// - URLはリソースを表す名詞のみ
// - パターンが一貫している
7つの観点で比較
1. URL設計
// 悪い例
GET /api/get-all-products // 動詞が入っている
GET /api/product_list // 命名がバラバラ
GET /api/Products/GetById/123 // PascalCase + 動詞
// 良い例
GET /api/v1/products // 複数形・小文字・ハイフン区切り
GET /api/v1/products/123 // パスパラメータでID指定
GET /api/v1/products/123/reviews // ネストでリレーションを表現
2. レスポンス形式
// 悪い例: 構造がバラバラ
// GET /api/users/123
{
"code": 0,
"msg": "success",
"d": { "user_name": "tanaka", "Email": "tanaka@example.com" }
}
// GET /api/products/456
{
"status": true,
"result": { "productName": "Widget", "Price": 1500 }
}
// 良い例: 一貫した構造
// GET /api/v1/users/123
{
"data": {
"id": "123",
"name": "田中太郎",
"email": "tanaka@example.com",
"createdAt": "2025-01-15T09:00:00Z"
}
}
// GET /api/v1/products/456
{
"data": {
"id": "456",
"name": "Widget",
"price": 1500,
"createdAt": "2025-01-10T10:30:00Z"
}
}
3. エラーレスポンス
// 悪い例: エラーの詳細が分からない
{
"error": true,
"message": "Error occurred"
}
// 良い例: 構造化されたエラー情報
{
"error": {
"type": "VALIDATION_ERROR",
"message": "入力内容に問題があります",
"details": [
{
"field": "email",
"message": "メールアドレスの形式が正しくありません",
"value": "not-an-email"
}
],
"traceId": "abc-123-def"
}
}
4. 日付・時刻の形式
// 悪い例: 形式がバラバラ
{
"created": "2025/01/15", // スラッシュ区切り
"updated": "Jan 15, 2025", // 英語表記
"lastLogin": 1705305600 // Unix timestamp
}
// 良い例: ISO 8601形式で統一
{
"createdAt": "2025-01-15T09:00:00Z",
"updatedAt": "2025-01-15T14:30:00Z",
"lastLoginAt": "2025-01-15T08:00:00Z"
}
5. IDの型
// 悪い例: 数値IDの問題
{
"id": 9007199254740993 // JavaScriptの安全な整数範囲を超える
}
// 良い例: 文字列ID
{
"id": "usr_abc123def456", // プレフィックス付き文字列ID
"orderId": "ord_789xyz"
}
// Stripe APIのように、リソース種別が分かるプレフィックスを付けると便利
6. Null の扱い
// 悪い例: nullと未定義が混在
{
"name": "田中",
"nickname": null, // nullが返る
// middleName は存在しない // フィールドが欠落
}
// 良い例: 明確なポリシー
// 方針1: nullを許容し、フィールドは常に存在させる
{
"name": "田中",
"nickname": null,
"middleName": null
}
// 方針2: 値がない場合はフィールドを省略する
{
"name": "田中"
}
// → どちらかに統一する。混在させない。
7. コレクションのレスポンス
// 悪い例: 配列をそのまま返す
[
{ "id": 1, "name": "田中" },
{ "id": 2, "name": "鈴木" }
]
// 問題: メタ情報(総件数、ページ情報)を追加できない
// 良い例: エンベロープパターン
{
"data": [
{ "id": "1", "name": "田中" },
{ "id": "2", "name": "鈴木" }
],
"meta": {
"totalCount": 150,
"page": 1,
"perPage": 20,
"totalPages": 8
}
}
有名APIから学ぶ
Stripe API(決済)
// Stripe は API 設計のお手本として有名
// プレフィックス付きID
{ "id": "cus_abc123" } // customer
{ "id": "ch_xyz789" } // charge
{ "id": "sub_def456" } // subscription
// 一貫したリスト形式
{
"object": "list",
"data": [...],
"has_more": true,
"url": "/v1/customers"
}
GitHub API
// ネストされたリソースの表現
GET /repos/{owner}/{repo}/issues // Issue一覧
GET /repos/{owner}/{repo}/issues/42 // 特定Issue
GET /repos/{owner}/{repo}/issues/42/comments // Issueのコメント
// Link ヘッダーによるページネーション
// Link: <https://api.github.com/repos/...?page=2>; rel="next"
まとめ
| 観点 | 悪いAPI | 良いAPI |
|---|---|---|
| URL | 動詞を含む、命名がバラバラ | 名詞・複数形・小文字で統一 |
| レスポンス | 構造が不統一 | 一貫したエンベロープ形式 |
| エラー | 詳細が分からない | 構造化エラー情報 |
| 日付 | 形式がバラバラ | ISO 8601で統一 |
| ID | 数値ID | 文字列ID(プレフィックス付き推奨) |
| Null | 混在 | ポリシーを統一 |
| コレクション | 配列をそのまま返す | メタ情報付きエンベロープ |
チェックリスト
- 良いAPIと悪いAPIの違いを7つの観点で説明できる
- Stripe API、GitHub APIの設計パターンを把握した
- 一貫性がAPI設計で最も重要であることを理解した
次のステップへ
良いAPIと悪いAPIの違いが分かりました。
次のセクションでは、API設計のベストプラクティスを体系的に学びます。 命名規則、ページネーション、フィルタリングなど、実務で即使えるテクニックを習得しましょう。
推定読了時間: 25分