目錄
什麼是 API 範式?
API(Application Programming Interface) 是系統之間溝通的約定。「範式」指的是用什麼風格與協定來設計這個溝通介面。不同範式在「資料怎麼取、誰主動、型別多嚴格、即時性」上有不同取捨。
主流範式大致分兩類:
請求—回應型(client 問、server 答):REST、GraphQL、gRPC
即時/推送型(持續連線、server 可主動推):WebSocket、SSE
沒有「最好的範式」,只有「最適合場景的範式」——這也是本篇的重點。
REST
REST(Representational State Transfer) 是目前最普遍的 Web API 風格:把所有東西當成資源(resource),用 HTTP 動詞操作,以 URL 定位。
核心原則
資源用 URL 表示: /users/123
動作用 HTTP 動詞表示:
GET /users 取得列表
GET /users/123 取得單一
POST /users 新增
PUT /users/123 整筆更新
PATCH /users/123 部分更新
DELETE /users/123 刪除
- 無狀態(Stateless):每個請求自帶所有必要資訊,server 不保存 session 狀態
- 以 HTTP 狀態碼表達結果:200 成功、201 已建立、400 請求錯誤、401 未認證、404 找不到、500 伺服器錯誤
- 資源導向:URL 是名詞(資源),不是動詞(動作)
優缺點
| 優點 | 缺點 |
|---|---|
| 簡單、直覺、生態成熟 | Over-fetching:回傳整個物件,常拿到用不到的欄位 |
| 善用 HTTP 快取、狀態碼 | Under-fetching:一個畫面要打很多支 API(N+1 請求) |
| 工具 / 文件(OpenAPI)完備 | 多端點,版本演進需 /v1/、/v2/ |
| 人類可讀、易除錯 | 沒有強制的型別契約 |
REST 是 80% 場景的合理預設;多數公開 API(GitHub、Stripe)都是 REST。
GraphQL
GraphQL 由 Facebook 提出:用單一端點,讓客戶端自己描述要哪些欄位,server 精準回傳,解決 REST 的 over/under-fetching。
核心概念
# 客戶端的查詢:只要這些欄位
query {
user(id: "123") {
name
orders(last: 3) { # 一次查到關聯資料,不必再打一支
amount
}
}
}
- 單一端點(通常
/graphql),用查詢內容決定回傳 - 三種操作:Query(讀)、Mutation(寫)、Subscription(即時訂閱)
- 強型別 Schema:API 的結構由 schema 定義,自帶文件與型別檢查
優缺點
| 優點 | 缺點 |
|---|---|
| 精準取資料,解決 over/under-fetching | 學習曲線、伺服器端較複雜 |
| 一次請求取多種關聯資料 | HTTP 快取較難(多為單一 POST 端點) |
| 強型別 schema、自帶 introspection 文件 | N+1 查詢問題(需 DataLoader 批次解決) |
| 前端不必等後端加欄位 | 複雜查詢可能拖垮後端,需限制深度/複雜度 |
適合前端需求多變、關聯資料多的場景(如多種裝置共用一套 API)。
gRPC
gRPC 是 Google 的高效能 RPC 框架:以 Protocol Buffers 定義介面與訊息,透過 HTTP/2 傳輸二進位資料,把「呼叫遠端方法」做得像呼叫本地函式。
核心概念
// .proto:先定義服務與訊息(強型別契約)
service UserService {
rpc GetUser (UserRequest) returns (UserReply);
}
message UserRequest { int32 id = 1; }
message UserReply { string name = 1; }
- Protocol Buffers(protobuf):二進位序列化,比 JSON 小且快
- HTTP/2:多工、標頭壓縮,支援四種串流(一元、server 串流、client 串流、雙向串流)
- 強型別契約 + 自動產生各語言 client/server 程式碼
優缺點
| 優點 | 缺點 |
|---|---|
| 效能高、payload 小(二進位) | 瀏覽器不能直接用(需 gRPC-Web 代理) |
| 強型別契約、跨語言自動生成程式碼 | 二進位不可讀,除錯較難 |
| 原生支援雙向串流 | 生態與工具不如 REST 普及 |
| 適合微服務間高頻通訊 | 對外公開 API 較少用 |
典型用途:微服務之間的內部通訊(東西向流量),不是給瀏覽器/公開用。
即時通訊:輪詢 / SSE / WebSocket
當需要「server 有更新就讓 client 知道」時,請求—回應型不夠用,有三種做法:
1. 輪詢(Polling)
client 定時打 API 問「有沒有新資料」。
client ──每 3 秒問一次──► server
- ✅ 最簡單,用一般 REST 就能做
- ❌ 浪費請求、有延遲;多數請求是「沒有新資料」
2. SSE(Server-Sent Events)
基於 HTTP 的單向推送:連線開著,server → client 持續送事件。
client ──開一條連線──► server ══事件流══► client(單向,server 推)
- ✅ 比 WebSocket 簡單、走純 HTTP、瀏覽器原生
EventSource、自動重連 - ✅ 適合只需 server 推的場景:通知、即時報價、AI 串流回覆
- ❌ 單向(client 要傳資料仍走一般請求)、舊版 IE 不支援
3. WebSocket
升級成全雙工持久連線,雙向即時傳訊。
client ◄══雙向即時══► server(兩邊都能主動送)
- ✅ 真雙向、低延遲,適合聊天、多人遊戲、協作編輯
- ❌ 非 HTTP 請求—回應模型,需額外處理連線管理、重連、擴展(sticky session / pub-sub)
三者怎麼選
| 需求 | 選擇 |
|---|---|
| 偶爾更新、要最簡單 | 輪詢 |
| 只需 server 單向推(通知 / 串流) | SSE |
| 雙向即時(聊天 / 遊戲 / 協作) | WebSocket |
全範式比較
| 面向 | REST | GraphQL | gRPC | WebSocket | SSE |
|---|---|---|---|---|---|
| 傳輸 | HTTP/1.1+ | HTTP(多為 POST) | HTTP/2 | TCP(HTTP 升級) | HTTP |
| 資料格式 | JSON | JSON | 二進位(protobuf) | 任意 | 文字事件流 |
| 通訊方向 | 請求—回應 | 請求—回應 | 請求—回應 + 串流 | 雙向 | server→client |
| 型別契約 | 無強制(可配 OpenAPI) | 強(schema) | 強(.proto) | 無 | 無 |
| 取資料精準度 | 固定(易 over-fetch) | 精準(client 決定) | 固定 | — | — |
| HTTP 快取 | ✅ 佳 | ⚠️ 較難 | ❌ | ❌ | ⚠️ |
| 瀏覽器直接用 | ✅ | ✅ | ❌(需 gRPC-Web) | ✅ | ✅ |
| 典型場景 | 公開 API、CRUD | 多變前端、關聯資料 | 微服務內部 | 聊天/遊戲 | 通知/AI 串流 |
怎麼選
要對外公開 / 一般 CRUD / 想善用 HTTP 快取
→ REST
前端需求多變、一個畫面要拼很多關聯資料、想避免 over/under-fetch
→ GraphQL
微服務之間高頻內部通訊、要效能與強型別、要串流
→ gRPC
需要即時:
├─ 只 server 單向推(通知、即時報價、AI 逐字輸出)→ SSE
└─ 雙向互動(聊天、多人遊戲、協作)→ WebSocket
實務常混用:對外 REST、內部服務間 gRPC、即時功能用 WebSocket/SSE。不必非黑即白。
常見問題
問題 1:REST 和 GraphQL 該選哪個?
REST 適合單純 CRUD、想善用 HTTP 快取、API 結構穩定;GraphQL 適合前端需求多變、一次要取多種關聯資料、想避免 over/under-fetching。前端裝置多樣、欄位需求常變時 GraphQL 較划算。
問題 2:gRPC 為什麼瀏覽器不能直接用?
gRPC 依賴 HTTP/2 的底層控制與二進位 framing,瀏覽器的 fetch/XHR 無法完全操控,因此需要 gRPC-Web + 代理層轉換。所以 gRPC 主要用於後端服務之間,不直接面向瀏覽器。
問題 3:SSE 和 WebSocket 差在哪?
SSE 是單向(server→client)、走純 HTTP、瀏覽器原生支援且自動重連,適合通知 / 串流;WebSocket 是雙向全雙工,適合聊天 / 遊戲等互動。只需 server 推就用 SSE,要雙向才用 WebSocket。
問題 4:為什麼 AI 聊天的逐字輸出常用 SSE?
因為那是單向串流(server 把 token 一個個推給前端),SSE 剛好夠用、又比 WebSocket 簡單、走標準 HTTP。OpenAI 等串流回應多以 SSE 實作。
問題 5:GraphQL 的 N+1 問題是什麼?
一個查詢取列表再取每筆的關聯資料時,可能對每筆都打一次 DB(1 + N 次)。解法是用 DataLoader 之類的批次機制,把多次查詢合併。這與 資料庫索引 的關聯查詢效能也相關。
總結
核心要點
- 沒有最好的範式,只有最適合場景的範式
- REST:資源 + HTTP 動詞,簡單通用、快取好,但有 over/under-fetching
- GraphQL:單一端點、client 決定欄位,解決取資料問題,但快取難、有 N+1
- gRPC:protobuf + HTTP/2,高效強型別、支援串流,但瀏覽器不能直連,適合微服務內部
- 即時:單向推用 SSE、雙向互動用 WebSocket、最簡單用輪詢
- 實務常混用:對外 REST、內部 gRPC、即時 WebSocket/SSE
快速參考
| 範式 | 一句話 | 招牌場景 |
|---|---|---|
| REST | 資源 + HTTP 動詞 | 公開 API、CRUD |
| GraphQL | client 點菜、單端點 | 多變前端 |
| gRPC | protobuf + HTTP/2 RPC | 微服務內部 |
| WebSocket | 雙向持久連線 | 聊天、遊戲 |
| SSE | server 單向推 | 通知、AI 串流 |
建立日期:2026-06-18