RESTful API 設計哲學
REST 不只是 URL 命名規則
很多人以為 REST 就是:
GET /api/users → 取得所有
GET /api/users/1 → 取得單一
POST /api/users → 新增
PUT /api/users/1 → 更新
DELETE /api/users/1 → 刪除
這只是表面。REST 的核心是資源導向和無狀態。
冪等性(Idempotency)
同一個請求執行一次和執行 N 次,結果一樣。
| HTTP 方法 | 冪等? | 為什麼? |
|---|---|---|
| GET | ✅ 是 | 只是查詢,不改變狀態 |
| PUT | ✅ 是 | 整個覆蓋,執行 N 次結果一樣 |
| DELETE | ✅ 是 | 刪第一次成功,之後都是「已刪除」 |
| POST | ❌ 否 | 每次都建立新資源 |
| PATCH | ❌ 否 | 部分更新,可能有副作用 |
為什麼重要?
→ 網路不穩定,Request 可能重送
→ 如果 POST 建立訂單被重送 3 次 → 建立 3 筆訂單!
→ 解法:客戶端帶 Idempotency-Key Header
狀態碼語意
2xx 成功:
200 OK → 查詢、更新成功
201 Created → 新增成功(回傳 Location Header)
204 No Content → 刪除成功(不回傳 body)
4xx 客戶端錯誤:
400 Bad Request → 參數格式錯誤
401 Unauthorized → 沒有身份(未登入)
403 Forbidden → 有身份但沒權限
404 Not Found → 資源不存在
409 Conflict → 資源衝突(重複建立)
422 Unprocessable → 參數格式對但語意錯(如:年齡 = -5)
5xx 伺服器錯誤:
500 Internal Server Error → 程式碼有 bug
503 Service Unavailable → 暫時無法服務
常見錯誤:所有錯誤都回 200 +
{ success: false }。這讓客戶端無法用 HTTP 機制處理錯誤。
API 版本控制
方式 1:URL 路徑(最常見)
/api/v1/users
/api/v2/users
方式 2:Header
Accept: application/vnd.myapp.v2+json
方式 3:Query String
/api/users?version=2
建議用 URL 路徑:最明確、最好 debug、容易做路由。
PUT vs PATCH
PUT:整個資源覆蓋(你必須送完整的物件)
PUT /api/users/1 { name: "小明", age: 21, email: "ming@test.com" }
→ 漏送 email?email 就變 null
PATCH:部分更新(只送要改的欄位)
PATCH /api/users/1 { age: 21 }
→ 只改 age,其他不動
巢狀資源
// 取得使用者的訂單
GET /api/users/1/orders ✅ 好
GET /api/orders?userId=1 ✅ 也可以
// 最多兩層巢狀
GET /api/users/1/orders/5 ✅ OK
GET /api/users/1/orders/5/items ⚠️ 太深了
// 太深就改用 query parameter
GET /api/order-items?orderId=5 ✅ 簡潔