📋
← 返回教學列表

在 REST API 中使用 JSON:最佳實踐

· 標籤: json, rest-api, api-design, json-best-practices, pagination, web-development

REST API 中的 JSON

JSON 和 REST API 是天作之合。JSON 的輕量級語法、原生陣列支援和通用語言支援使其成為現代 Web API 的預設格式。但僅僅在 API 中使用 JSON 是不夠的——遵循既定的約定和最佳實踐可以確保你的 API 一致、直覺且易於整合。

請求與回應格式

一致的信封結構

為所有 API 回應採用一致的 JSON 信封結構。這樣可以使客戶端處理變得可預測,並簡化錯誤處理。

{
  "status": "success",
  "data": {
    "user": {
      "id": 123,
      "name": "Alice",
      "email": "alice@example.com"
    }
  },
  "meta": {
    "requestId": "req-a1b2c3d4",
    "timestamp": "2026-07-19T10:30:00Z"
  }
}

蛇形命名 vs 駝峰命名

選擇一種命名約定,並在整個 API 中保持一致:

  • 駝峰命名 (createdAtfirstName):在 JavaScript/TypeScript 生態系統中常見
  • 蛇形命名 (created_atfirst_name):在 Python、Ruby 和 PHP 生態系統中常見

無論選擇哪種,都應清楚記錄下來,如果後端語言使用不同的命名約定,可以考慮使用轉換層。

JSON 相關的 HTTP 狀態碼

適當的 HTTP 狀態碼與 JSON 回應相輔相成。請一致地使用它們:

| 狀態碼 | 含義 | 使用時機 | |-------------|---------|-------------| | 200 OK | 成功 | GET、PUT、PATCH 成功時 | | 201 Created | 資源已建立 | POST 成功時 | | 204 No Content | 刪除成功 | DELETE 成功時(無 JSON 主體) | | 400 Bad Request | 無效的 JSON 語法 | 請求主體格式錯誤 | | 401 Unauthorized | 需要驗證 | 缺少或無效的權杖 | | 403 Forbidden | 權限不足 | 驗證有效但不允許 | | 404 Not Found | 資源不存在 | 無效的 ID 或路徑 | | 422 Unprocessable Entity | 驗證失敗 | 有效 JSON 中的語意錯誤 | | 429 Too Many Requests | 觸發速率限制 | 客戶端超出限制 | | 500 Internal Server Error | 伺服器端故障 | 未預期的錯誤 |

標準錯誤回應格式

{
  "status": "error",
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "請求主體包含無效欄位",
    "details": [
      {
        "field": "email",
        "message": "必須是有效的電子郵件地址",
        "code": "INVALID_FORMAT"
      },
      {
        "field": "age",
        "message": "必須是正整數",
        "code": "OUT_OF_RANGE"
      }
    ]
  }
}

巢狀資源

表示關聯關係

REST API 經常需要表示相關資源。以下是常見的模式:

內嵌(預先載入):

{
  "order": {
    "id": 5001,
    "total": 29.99,
    "customer": {
      "id": 123,
      "name": "Alice",
      "email": "alice@example.com"
    },
    "items": [
      {
        "productId": 42,
        "name": "Widget",
        "quantity": 2,
        "price": 14.99
      }
    ]
  }
}

引用(延遲載入)——使用 ID 並提供獨立的端點:

{
  "order": {
    "id": 5001,
    "total": 29.99,
    "customerId": 123,
    "itemIds": [101, 102]
  }
}

經驗法則: 總是需要一起使用的相關資料使用內嵌。有條件地或在不同時間取得的資料使用引用。

分頁模式

在回傳資源列表時,分頁是必不可少的。使用一致的分頁格式:

基於偏移的分頁

{
  "status": "success",
  "data": [
    { "id": 1, "name": "User 1" },
    { "id": 2, "name": "User 2" }
  ],
  "pagination": {
    "page": 1,
    "perPage": 20,
    "totalItems": 156,
    "totalPages": 8,
    "links": {
      "first": "/api/users?page=1&perPage=20",
      "prev": null,
      "next": "/api/users?page=2&perPage=20",
      "last": "/api/users?page=8&perPage=20"
    }
  }
}

基於游標的分頁(推薦用於大型資料集)

{
  "status": "success",
  "data": [
    { "id": 100, "name": "User 100" },
    { "id": 101, "name": "User 101" }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6MTAxfQ==",
    "hasMore": true
  }
}

對於即時資料,基於游標的分頁更加可靠,因為新記錄可能會改變頁面邊界。

API 請求中的 JSON

POST / PUT 請求主體

使用 Content-Type: application/json 標頭接受 JSON:

{
  "title": "新部落格文章",
  "content": "這是文章內容...",
  "tags": ["json", "rest-api"],
  "published": false
}

使用 PATCH 進行部分更新

使用 PATCH 進行部分更新。只接受需要變更的欄位:

// PATCH /api/users/123
{
  "email": "newemail@example.com"
}

過濾、排序和搜尋

使用查詢參數進行資料操作,保持 JSON 主體簡潔:

GET /api/users?filter[role]=admin&sort=-createdAt&search=alice
{
  "status": "success",
  "data": [ /* 已過濾、排序的結果 */ ]
}

速率限制

在回應標頭中包含速率限制資訊,也可以選擇性地在 JSON 主體中包含:

{
  "status": "error",
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "請求過多。請稍後再試。"
  },
  "meta": {
    "rateLimit": {
      "limit": 100,
      "remaining": 0,
      "resetAt": "2026-07-19T11:00:00Z"
    }
  }
}

JSON 最佳實踐檢查清單

  • [ ] 使用一致的鍵名命名(全程使用 camelCase 或 snake_case)
  • [ ] 每個回應都回傳適當的 HTTP 狀態碼
  • [ ] 包含一致的錯誤格式和機器可讀的錯誤碼
  • [ ] 使用標準化的分頁物件對列表端點進行分頁
  • [ ] 使用 JSON Schema 來記錄和驗證請求/回應結構
  • [ ] 在所有 JSON 端點上設定 Content-Type: application/json
  • [ ] 在生產環境中使用 gzip 或 brotli 壓縮 JSON 回應
  • [ ] 強制設定最大資料量限制(例如預設 1MB)
  • [ ] 使用 HTTPS 加密傳輸中的 JSON 資料
  • [ ] 建構錯誤詳情以幫助客戶端除錯,同時不暴露內部資訊

驗證你的 API JSON

透過 JSON 驗證器檢查你的 API 回應,在錯誤到達客戶端之前捕捉格式錯誤。一致、有效的 JSON 回應讓你的 API 可靠且對開發者友好。使用我們的 JSON 格式化與驗證工具在開發過程中測試你的資料。