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 OK201 Created204 No Content
3xx 重定向 301 Moved Permanently304 Not Modified
4xx 客戶端錯誤 400 Bad Request401 Unauthorized403 Forbidden404 Not Found409 Conflict429 Too Many Requests
5xx 伺服器錯誤 500 Internal Server Error502 Bad Gateway503 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 /updateUserGET /createOrder 都不是 RESTful。
正確是「資源 URI + HTTP 動詞」:PUT /users/{id}POST /orders


面試中如何談 REST

  1. 預設選擇:沒特別限制時,REST 是對外 API 的業界標準
  2. 使用情境
    • 對外公開 API → REST
    • 需要 HTTP caching → REST
    • 廣泛相容性(合作夥伴、多語言 client)→ REST
  3. 比較
    • 前端避免 over-fetching → 考慮 GraphQL
    • 內部微服務高效能通訊 → 考慮 gRPC

Simplification-with-exceptions

實務邊界

  • RESTful 是光譜:完全符合 Roy Fielding 原始論文(含 HATEOAS)的 API 極少;業界多數是「RESTish」
  • JSON 不是唯一:REST 規範上與格式無關,也可用 XML、Protobuf;只是 JSON 最普遍
  • 批次操作沒有標準POST /users/batchPATCH 多個資源都是妥協方案