JSON API 最佳實務:RESTful API 設計完整指南
建構穩健的 JSON API 需要的不僅是將資料以 JSON 格式返回。本全面指南涵蓋了設計、實作和維護安全、高效能且開發人員友善的 API 的基本最佳實務。
API 卓越:遵循這些最佳實務可以將 API 採用率提高 300%,並將整合時間減少 70%。設計良好的 API 成為成功數位產品的基礎。
為何 JSON API 最佳實務重要
良好 API 設計的影響
設計良好的 API 提供:
- 更快的整合 給開發人員
- 減少支援 請求和文件需求
- 更高的採用率 和開發人員滿意度
- 更容易的維護 和隨時間演進
- 更好的效能 和可擴展性
常見 API 問題
不良 API 設計導致:
- 不一致的回應 讓開發人員困惑
- 來自不當驗證的安全漏洞
- 來自低效資料傳輸的效能問題
- 由於不清楚的文件導致的整合失敗
- 來自技術債務的維護噩夢
RESTful API 基礎
REST 原則
Representational State Transfer (REST) 核心原則:
- Client-Server Architecture:明確的關注點分離
- Stateless:每個請求包含所有必要資訊
- Cacheable:回應在適當時應可快取
- Uniform Interface:一致的資源識別和操作
- Layered System:架構可由階層式層組成
HTTP 方法及其正確使用
標準 HTTP 方法:
GET /api/users # Retrieve all users
GET /api/users/123 # Retrieve specific user
POST /api/users # Create new user
PUT /api/users/123 # Update entire user resource
PATCH /api/users/123 # Partial update of user
DELETE /api/users/123 # Delete user
方法指南:
- GET:安全且冪等,無副作用
- POST:非冪等,創建資源
- PUT:冪等,取代整個資源
- PATCH:不一定冪等,部分更新
- DELETE:冪等,移除資源
URL 結構和命名慣例
基於資源的 URL
良好的 URL 設計:
✅ GET /api/v1/users
✅ GET /api/v1/users/123
✅ GET /api/v1/users/123/orders
✅ POST /api/v1/orders
避免這些模式:
❌ GET /api/getUsers
❌ POST /api/createUser
❌ GET /api/user_orders?userId=123
命名慣例
資源命名規則:
- 使用 複數名詞 來表示集合(
/users,而非/user) - 使用 小寫 並以連字號提高可讀性(
/user-profiles) - 在整個 API 中保持 一致性
- 使用 巢狀資源 來表示關係(
/users/123/orders)
查詢參數:
GET /api/users?page=2&limit=50&sort=created_at&order=desc
GET /api/products?category=electronics&min_price=100
GET /api/posts?search=json&tags=api,development
JSON 回應結構
一致的回應格式
標準成功回應:
{
"success": true,
"data": {
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"created_at": "2024-01-01T10:00:00Z"
},
"message": "User retrieved successfully"
}
集合回應:
{
"success": true,
"data": [
{
"id": 123,
"name": "John Doe",
"email": "john@example.com"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 1250,
"pages": 25,
"has_next": true,
"has_prev": false
},
"message": "Users retrieved successfully"
}
資料格式化標準
日期和時間:
{
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T15:30:00Z"
}
貨幣值:
{
"price": {
"amount": 1999,
"currency": "USD",
"formatted": "$19.99"
}
}
布林值:
{
"is_active": true,
"email_verified": false,
"has_premium": null
}
錯誤處理最佳實務
HTTP 狀態碼
成功碼:
200 OK:成功的 GET、PUT、PATCH201 Created:成功的 POST204 No Content:成功的 DELETE
客戶端錯誤碼:
400 Bad Request:無效的請求資料401 Unauthorized:需要驗證403 Forbidden:存取被拒404 Not Found:資源不存在422 Unprocessable Entity:驗證錯誤
伺服器錯誤碼:
500 Internal Server Error:通用伺服器錯誤502 Bad Gateway:上游伺服器錯誤503 Service Unavailable:暫時無法使用
錯誤回應格式
標準錯誤回應:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The request data is invalid",
"details": [
{
"field": "email",
"message": "Email format is invalid",
"rejected_value": "invalid-email"
},
{
"field": "age",
"message": "Age must be between 18 and 120",
"rejected_value": 15
}
]
},
"timestamp": "2024-01-01T10:00:00Z",
"request_id": "req_123456789"
}
安全警告:切勿在錯誤訊息中暴露敏感資訊。提供足夠的除錯細節,但不透露系統內部或使用者資料。
驗證和授權
驗證方法
API 金鑰驗證:
GET /api/users
Authorization: Bearer api_key_here
JWT 權杖驗證:
GET /api/users
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
OAuth 2.0:
GET /api/users
Authorization: Bearer oauth_access_token_here
安全最佳實務
基本安全措施:
- 僅 HTTPS:切勿透過 HTTP 傳輸敏感資料
- 速率限制:防止濫用和 DoS 攻擊
- 輸入驗證:清理和驗證所有輸入
- 輸出編碼:防止 XSS 攻擊
- CORS 配置:正確配置跨來源請求
速率限制標頭:
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
分頁策略
基於偏移的分頁
請求:
GET /api/users?page=2&limit=50
回應:
{
"data": [...],
"pagination": {
"page": 2,
"limit": 50,
"total": 1250,
"pages": 25,
"offset": 50
}
}
基於游標的分頁
請求:
GET /api/users?cursor=eyJpZCI6MTIzfQ&limit=50
回應:
{
"data": [...],
"pagination": {
"limit": 50,
"has_next": true,
"next_cursor": "eyJpZCI6MTczfQ",
"prev_cursor": "eyJpZCI6NzN9"
}
}
連結標頭分頁
回應標頭:
Link: <https://api.example.com/users?page=1>; rel="first",
<https://api.example.com/users?page=2>; rel="prev",
<https://api.example.com/users?page=4>; rel="next",
<https://api.example.com/users?page=25>; rel="last"
篩選、排序和搜尋
查詢參數慣例
篩選:
GET /api/products?category=electronics&status=active&min_price=100
GET /api/users?role=admin&created_after=2024-01-01
排序:
GET /api/users?sort=created_at&order=desc
GET /api/products?sort=price,name&order=asc,desc
搜尋:
GET /api/users?search=john&fields=name,email
GET /api/posts?q=json%20api&in=title,content
進階篩選
運算子:
GET /api/products?price[gte]=100&price[lte]=500
GET /api/users?created_at[between]=2024-01-01,2024-12-31
GET /api/posts?tags[in]=api,json,rest
版本控制策略
URL 路徑版本控制
GET /api/v1/users
GET /api/v2/users
標頭版本控制
GET /api/users
Accept: application/vnd.api+json;version=1
API-Version: 2
查詢參數版本控制
GET /api/users?version=1
版本控制最佳實務:
- Semantic Versioning:使用 major.minor.patch 格式
- 向後相容性:在合理期間維護舊版本
- 棄用通知:提供清晰的遷移路徑
- 文件:維護版本特定文件
效能最佳化
回應最佳化
欄位選擇:
GET /api/users?fields=id,name,email
GET /api/posts?include=author,comments&fields[posts]=title,body&fields[author]=name
壓縮:
Accept-Encoding: gzip, deflate
Content-Encoding: gzip
快取策略
HTTP 快取標頭:
Cache-Control: public, max-age=3600
ETag: "abc123def456"
Last-Modified: Wed, 01 Jan 2024 10:00:00 GMT
條件式請求:
GET /api/users/123
If-None-Match: "abc123def456"
If-Modified-Since: Wed, 01 Jan 2024 10:00:00 GMT
資料庫最佳化
N+1 查詢預防:
{
"data": [
{
"id": 1,
"title": "Post Title",
"author": {
"id": 123,
"name": "John Doe"
},
"comments": [
{
"id": 456,
"content": "Great post!",
"author": {
"id": 789,
"name": "Jane Smith"
}
}
]
}
]
}
內容協商
Accept 標頭
JSON 回應:
Accept: application/json
Content-Type: application/json
XML 回應:
Accept: application/xml
Content-Type: application/xml
多格式支援
API 回應:
GET /api/users/123
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 123,
"name": "John Doe"
}
文件最佳實務
OpenAPI/Swagger 規格
基本 API 定義:
openapi: 3.0.0
info:
title: User API
version: 1.0.0
description: A simple user management API
paths:
/users:
get:
summary: Get all users
parameters:
- name: page
in: query
schema:
type: integer
default: 1
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
互動式文件
基本文件元素:
- 所有端點的清晰描述
- 每個操作的請求/回應範例
- 錯誤情境 及其回應
- 驗證需求 和範例
- 速率限制 資訊
- 多語言的 SDK 和程式碼範例
測試策略
API 測試金字塔
單元測試:
describe('User API', () => {
test('should create user with valid data', async () => {
const userData = {
name: 'John Doe',
email: 'john@example.com'
};
const response = await request(app)
.post('/api/users')
.send(userData)
.expect(201);
expect(response.body.data.name).toBe('John Doe');
});
});
整合測試:
describe('User Integration Tests', () => {
test('should handle user creation workflow', async () => {
// Create user
const createResponse = await createUser(userData);
expect(createResponse.status).toBe(201);
// Verify user exists
const getResponse = await getUser(createResponse.body.data.id);
expect(getResponse.status).toBe(200);
// Update user
const updateResponse = await updateUser(user.id, updatedData);
expect(updateResponse.status).toBe(200);
});
});
合約測試
API 合約範例:
{
"consumer": "Frontend App",
"provider": "User API",
"interactions": [
{
"description": "Get user by ID",
"request": {
"method": "GET",
"path": "/api/users/123"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": {
"id": 123,
"name": "John Doe",
"email": "john@example.com"
}
}
}
]
}
監控和分析
基本指標
效能指標:
- 回應時間百分位數 (p50, p95, p99)
- 請求速率和吞吐量
- 按端點和狀態碼的錯誤率
- 快取命中/未命中比率
業務指標:
- API 採用和使用模式
- 最受歡迎的端點
- 開發人員入門成功率
- 支援票券類別
記錄最佳實務
結構化記錄:
{
"timestamp": "2024-01-01T10:00:00Z",
"level": "INFO",
"method": "GET",
"path": "/api/users/123",
"status_code": 200,
"response_time": 150,
"user_id": "user_456",
"request_id": "req_789",
"ip_address": "192.168.1.1"
}
進階主題
Webhooks 實作
Webhook 負載:
{
"event": "user.created",
"timestamp": "2024-01-01T10:00:00Z",
"data": {
"id": 123,
"name": "John Doe",
"email": "john@example.com"
},
"webhook_id": "wh_abc123"
}
GraphQL 與 REST
何時選擇 GraphQL:
- 複雜的資料關係
- 多種客戶端類型具有不同需求
- 需要即時訂閱
- 強類型需求
何時堅持 REST:
- 簡單的 CRUD 操作
- 快取至關重要
- 團隊熟悉 REST
- 檔案上傳/下載密集
API 演進和維護
棄用策略
棄用流程:
- 宣布棄用 並提供清晰的時間表
- 提供遷移指南 和範例
- 監控棄用端點的使用
- 在過渡期間提供支援
- 寬限期後移除棄用功能
破壞性與非破壞性變更
非破壞性變更:
- 新增新的選用欄位
- 新增新的端點
- 新增新的選用查詢參數
- 將必要欄位設為選用
破壞性變更:
- 移除欄位或端點
- 變更欄位類型或格式
- 將選用欄位設為必要
- 變更驗證需求
結論
建構優秀的 JSON API 需要注意細節、一致性和對技術及使用者體驗考量的深入理解。最佳的 API 對開發人員來說感覺直觀,並提供清晰、可預測的介面,以實現快速整合和開發。
請記住,API 設計是關於在您的服務及其消費者之間建立合約。盡可能使該合約清晰、穩定且開發人員友善,您的 API 將成為推動採用和業務成功的寶貴資產。
API 成功的關鍵是將您的 API 視為產品,具有真實使用者及其真實需求。以同理心設計、徹底文件化,並根據回饋迭代。
準備建構更好的 API 嗎?使用我們的 JSON Formatter 來確保您的 API 回應正確格式化和驗證。