API 設計
選擇合適的 API 類型
| 類型 | 最適合用於 | 應避免使用時機 |
|---|
| REST | 公開 API、CRUD、簡單客戶端、物聯網 | 複雜巢狀資料、結構快速迭代 |
| GraphQL | 行動應用、複雜巢狀資料、多個客戶端 | 簡單 CRUD、不熟悉 GraphQL 的小型團隊 |
| tRPC | TypeScript 單一倉儲、內部全端 TypeScript API | 非 TypeScript 客戶端、公開 API |
| gRPC | 高效能微服務通訊、串流 | 瀏覽器客戶端、簡單使用案例 |
REST API 設計
URL 慣例
GET /users ← 列表
GET /users/{id} ← 單一項目
POST /users ← 建立
PUT /users/{id} ← 取代
PATCH /users/{id} ← 部分更新
DELETE /users/{id} ← 刪除
# 巢狀資源
GET /users/{id}/orders
POST /users/{id}/orders
# 動作(當 REST 動詞不足時)
POST /orders/{id}/cancel
POST /users/{id}/activate
HTTP 狀態碼
| 代碼 | 使用時機 |
|---|
| 200 | 成功的 GET、PUT、PATCH |
| 201 | 成功的 POST(建立資源) |
| 204 | 成功的 DELETE(不含內容) |
| 400 | 驗證失敗、錯誤請求 |
| 401 | 缺少或無效的驗證 |
| 403 | 已驗證但未授權 |
| 404 | 找不到資源 |
| 409 | 衝突(重複、版本不符) |
| 422 | 無法處理的實體(語意錯誤) |
| 429 | 超過速率限制 |
| 500 | 未預期的伺服器錯誤 |
回應封裝格式
{
"data": [...],
"meta": { "total": 100, "page": 1, "perPage": 20 }
}
{ "data": { "id": "1", "name": "James" } }
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [{ "field": "email", "issue": "Invalid format" }]
}
}
API 設計原則
版本管理策略
# URL 版本管理(最明顯、最容易路由)
/v1/users
/v2/users
# 標頭版本管理(URL 更簡潔)
Accept: application/vnd.api+json;version=2
絕不破壞現有客戶端。先棄用,再移除。
分頁
# 偏移分頁(簡單,適合小型資料集)
GET /posts?page=2&perPage=20
# 游標分頁(大型資料集快速,適合無限滾動)
GET /posts?cursor=eyJpZCI6MTAwfQ&limit=20
篩選與排序
GET /orders?status=pending&userId=123
GET /products?sort=-price,name # - 前綴表示降冪
GET /products?fields=id,name,price # 稀疏欄位集
冪等性
# 為非冪等操作包含冪等金鑰
POST /payments
Idempotency-Key: unique-client-generated-uuid
GraphQL 設計
結構設計規則
- 描述業務領域,而非資料庫結構
- 列表使用連線模式(可準備分頁)
- Mutation 回傳修改後的物件
- 有限的值集合使用列舉
- 為所有類型和欄位加入描述
type Query {
user(id: ID!): User
users(filter: UserFilter, pagination: PaginationInput): UserConnection!
}
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
API 安全檢查清單