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          # List users
POST   /api/users          # Create a user
GET    /api/users/123      # Get user 123
PUT    /api/users/123      # Update user 123
DELETE /api/users/123      # Delete user 123

命名慣例

  • 使用小寫加連字號:/api/blog-posts(而非 blogPostsblog_posts
  • 巢狀相關資源:/api/users/123/orders
  • 巢狀限制在 2 層:/api/users/123/orders/456(不要更深)
  • 避免在 URL 中使用動詞:/api/users/123/activate 對於無法對應到 CRUD 的操作是可接受的

回應封裝

將回應包裝在一致的封裝中:

{
  "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 回應,確保它們符合你的結構描述。

分頁

三種常見方法:

偏移量分頁(最簡單)

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          # Ascending
GET /api/users?sort=-created_at   # Descending (prefix with -)
GET /api/users?sort=-created_at,name  # Multiple fields

錯誤處理

一致的錯誤回應對 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非預期的伺服器錯誤

版本控制

三種方法:

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 工具。

日期與時間處理

一律使用 ISO 8601 格式的 UTC:

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

永遠不要在 API 回應中使用 Unix 時間戳——它們含糊不清(秒 vs 毫秒)且不易閱讀。有關時間戳處理的更多資訊,請參閱我們的 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 建構工作。

常見問題

我應該使用 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