REST 架構風格 (REST)
核心定義
REST(Representational State Transfer)是一種 架構風格,用於設計分散式系統(特別是網路 API)。
核心理念
- 資源導向(Resource-oriented):伺服器上的資源透過 URI 表達
- HTTP 方法當動詞:用標準 HTTP 方法(GET/POST/PUT/...)操作資源
- 無狀態(Stateless):每次請求自包含,伺服器不保留 client session state
HTTP 動詞與冪等性
先理解冪等性(Idempotency)
一次操作 vs 多次操作,對 伺服器狀態 的影響相同。
注意:冪等談的是「伺服器狀態」,不是「回應內容」。
| 動詞 | 用途 | 冪等? | 範例 |
|---|---|---|---|
| GET | 讀取資源 | ✅ | GET /users/123 |
| POST | 建立資源 | ❌ | POST /users → 每次產生不同 ID |
| PUT | 完整更新 | ✅ | PUT /users/123 with full body |
| PATCH | 局部更新 | 依設計(通常 ❌) | PATCH /users/123 with partial body |
| DELETE | 刪除資源 | ✅ | DELETE /users/123 |
為什麼 DELETE 是冪等的?
刪一次或刪十次,結果都是「該資源不存在」—— 伺服器狀態相同。
回應碼可能不同(第一次 204,之後 404),但這不影響冪等性判斷。
PATCH 的灰色地帶
PATCH {age: 30}→ 冪等(設為固定值)PATCH {age: age + 1}→ 非冪等(累加)
一般不保證冪等,應搭配 冪等鍵(Idempotency-Key header) 處理重試。
如何傳遞資料給 API
三種參數位置
| 位置 | 用途 | 範例 |
|---|---|---|
| Path Parameter | 標示唯一資源 | GET /users/123 |
| Query Parameter | 篩選、排序、分頁 | GET /users?age=30&sort=desc&page=2 |
| Request Body | 結構化資料(POST/PUT/PATCH) | POST /users with JSON payload |
選用原則
想「指到」某一個資源? → Path
想「過濾」一批資源? → Query
想「上傳」完整資料結構? → Body
不要在 GET 用 Body
HTTP spec 沒禁止,但 CDN、Proxy、瀏覽器常不支援 GET with body,快取也會失效。
回傳資料設計
常見 HTTP 狀態碼
| 範圍 | 代表意義 | 常見碼 |
|---|---|---|
| 2xx | 成功 | 200 OK、201 Created、204 No Content |
| 3xx | 重定向 | 301 Moved Permanently、304 Not Modified |
| 4xx | 客戶端錯誤 | 400 Bad Request、401 Unauthorized、403 Forbidden、404 Not Found、409 Conflict、429 Too Many Requests |
| 5xx | 伺服器錯誤 | 500 Internal Server Error、502 Bad Gateway、503 Service Unavailable |
401 vs 403
- 401 Unauthorized:沒登入 / token 無效 → 「你是誰?」
- 403 Forbidden:已登入但沒權限 → 「你不能做這件事」
Response Body 結構
{
"data": [...],
"page": 2,
"page_size": 20,
"total_pages": 10,
"links": {
"next": "/users?page=3",
"prev": "/users?page=1"
}
}
HATEOAS(Hypermedia as the Engine of Application State):回應中內嵌「下一步可做什麼」的連結,讓 client 不用 hardcode URL。實務上多數 REST API 並未嚴格遵守 HATEOAS。
優點
| 優點 | 說明 |
|---|---|
| 簡單直觀 | HTTP 動詞 + URI,幾乎所有開發者都懂 |
| 跨平台 | HTTP 通用,所有語言與框架都支援 |
| 快取友好 | 天然支援瀏覽器、CDN HTTP caching(靠 URL + headers 當 key) |
| 分層架構友好 | 容易搭 Proxy、LB、API Gateway |
缺點
| 缺點 | 說明 | 緩解 |
|---|---|---|
| Over-fetching | 只要部分欄位,卻拿回整個物件 | GraphQL / sparse fieldsets (?fields=) |
| Under-fetching | 一個頁面要多次 API call | GraphQL / 聚合端點(BFF) |
| 複雜操作難表達 | 批次操作、複雜 query 不好塞進 HTTP 動詞 | 自訂 action endpoint(有爭議) |
| 版本控制麻煩 | Schema 演進時常用 /v1/…、/v2/… |
Schema evolution、deprecation headers |
反模式 vs 正解
❌ POST /updateUser ← URL 放動詞
✅ PUT /users/{id}
❌ GET /deleteUser?id=123 ← GET 改變狀態
✅ DELETE /users/123
❌ GET /users with body ← GET 不應帶 body
✅ GET /users?filter=active
❌ POST /getUserList ← 用 POST 查詢
✅ GET /users?...
面試陷阱:操作命名
POST /updateUser、GET /createOrder 都不是 RESTful。
正確是「資源 URI + HTTP 動詞」:PUT /users/{id}、POST /orders。
面試中如何談 REST
- 預設選擇:沒特別限制時,REST 是對外 API 的業界標準
- 使用情境:
- 對外公開 API → REST
- 需要 HTTP caching → REST
- 廣泛相容性(合作夥伴、多語言 client)→ REST
- 比較:
Simplification-with-exceptions
實務邊界
- RESTful 是光譜:完全符合 Roy Fielding 原始論文(含 HATEOAS)的 API 極少;業界多數是「RESTish」
- JSON 不是唯一:REST 規範上與格式無關,也可用 XML、Protobuf;只是 JSON 最普遍
- 批次操作沒有標準:
POST /users/batch、PATCH多個資源都是妥協方案
Related Notes
- 03-API-Design/01-API-Design-Framework — 什麼時候選 REST
- 03-API-Design/03-GraphQL — 解決 REST 的 over/under-fetching
- 03-API-Design/04-RPC-and-gRPC — 內部服務替代方案
- 03-API-Design/05-API-Security — 401/403、JWT、scope
- 01-Networking/03-HTTP-and-HTTPS(01-Networking)— HTTP 方法與狀態碼基礎
- 03-API-Design/Practice-API-Design