在 REST API 中使用 JSON:最佳實踐
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 中保持一致:
- 駝峰命名 (
createdAt、firstName):在 JavaScript/TypeScript 生態系統中常見 - 蛇形命名 (
created_at、first_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 格式化與驗證工具在開發過程中測試你的資料。