選擇正確的 API 典範至關重要。API 典範定義了服務如何將後端資料暴露給其他應用程式的介面。
組織在起步時往往未充分考慮所有影響 API 成功的因素,導致日後沒有足夠的空間添加新功能。更棘手的是,一旦有開發者開始使用,修改 API 幾乎是不可能的事。因此,在開始之前花時間思考協定、模式和最佳實踐,能幫助你設計出未來可演進的 API。
目前主流的 API 典範包括 REST、RPC、GraphQL、WebHooks 和 WebSockets。本章將深入探討這些不同的典範。
Request-Response API#
Request-Response API 通常透過 HTTP Web 伺服器暴露介面。API 定義一組端點(endpoint),客戶端發送 HTTP 請求,伺服器回傳 JSON 或 XML 格式的回應。三種常見的 Request-Response API 典範為:REST、RPC 和 GraphQL。
REST(Representational State Transfer)#
REST 是目前最熱門的 API 開發選擇,被 Google、Stripe、Twitter 和 GitHub 等公司採用。REST 的核心概念是資源(Resource)——在 Web 上可以被識別、命名、定址或操作的實體。
REST API 的基本規則:
- 資源作為 URL 的一部分,如
/users - 每個資源通常有兩個 URL:集合(
/users)和特定元素(/users/U123) - 使用名詞而非動詞:用
/users/U123而非/getUserInfo/U123 - 透過 HTTP 方法表達操作意圖:
| 操作 | HTTP 動詞 | /users | /users/U123 |
|---|---|---|---|
| Create | POST | 建立新使用者 | 不適用 |
| Read | GET | 列出所有使用者 | 取得使用者 U123 |
| Update | PUT / PATCH | 批次更新 | 更新使用者 U123 |
| Delete | DELETE | 刪除所有使用者 | 刪除使用者 U123 |
- 標準 HTTP 狀態碼:
2XX表示成功,3XX表示重導向,4XX表示客戶端錯誤,5XX表示伺服器錯誤 - 回應格式:雖然也支援 XML,但 JSON 已成為現代 API 的標準
GET /v1/charges/ch_CWyutlXs9pZyfD
HOST api.stripe.com
Authorization: Bearer YNoJ1Yq64iCBhzfL9HNO00fzVrsEjtVlPOST /v1/charges/ch_CWyutlXs9pZyfD
HOST api.stripe.com
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer YNoJ1Yq64iCBhzfL9HNO00fzVrsEjtVl
amount=2000¤cy=usd表達資源關係#
存在於另一個資源內部的資源,可用子資源(Subresource) 表示,使關係更加清晰。GitHub API 就大量使用這種模式:
POST /repos/:owner/:repo/issues # 建立 issue
GET /repos/:owner/:repo/issues/:number # 取得特定 issue
GET /repos/:owner/:repo/issues # 列出所有 issues
PATCH /repos/:owner/:repo/issues/:number # 編輯 issue非 CRUD 操作#
REST API 有時需要處理超出典型 CRUD 的操作,常見做法:
- 將動作渲染為資源欄位:GitHub 用
"archived": true參數來封存倉庫 - 將動作視為子資源:
PUT /repos/:owner/:repo/issues/:number/lock鎖定 issue - 直接使用動詞:
GET /search/code?q=:query搜尋程式碼
RPC(Remote Procedure Call)#
RPC 是最簡單的 API 典範之一——客戶端在另一台伺服器上執行一段程式碼。REST 關注資源,RPC 關注動作。客戶端傳送方法名稱和參數,接收 JSON 或 XML 回應。
RPC API 的兩條簡單規則:
- 端點包含要執行的操作名稱
- 使用最適當的 HTTP 動詞:
GET用於唯讀請求,POST用於其他操作
RPC 風格適合以下場景:
- 暴露多種細微且複雜的動作
- 有與「資源」無關的副作用
- 複雜的資源模型或涉及多種資源類型的操作
POST /api/conversations.archive
HOST slack.com
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer xoxp-1650112-jgc2asDae
channel=C01234Slack 的 Conversations API 支援 archive、join、kick、leave、rename 等多種動作——這些動作並非都能整潔地對應到 REST 模式。

Figure 2.1: RPC-style Slack API methods
補充: RPC 風格不限於 HTTP。Apache Thrift 和 gRPC 等高效能協定也支援 RPC,使用序列化的結構化資料和明確定義的介面。
GraphQL#
GraphQL 是一種 API 查詢語言,由 Facebook 於 2012 年內部開發、2015 年公開發布,已被 GitHub、Yelp、Pinterest 等公司採用。GraphQL 允許客戶端精確定義所需的資料結構,伺服器則回傳完全對應的結構。
{
user(login: "saurabhsahni") {
id
name
company
createdAt
}
}與 REST 和 RPC 不同,GraphQL 只需要單一 URL 端點,也不需要不同的 HTTP 動詞來區分操作——在 JSON body 中指明是 query 還是 mutation 即可。
GraphQL 的關鍵優勢#
| 優勢 | 說明 |
|---|---|
| 減少往返次數 | 客戶端可在單一請求中巢狀查詢並跨資源獲取資料,對行動裝置特別有利 |
| 避免版本問題 | 可自由添加新欄位和類型而不影響既有查詢,透過日誌分析找出棄用欄位的使用者 |
| 更小的 Payload | 客戶端精確指定需要的資料,回傳結果可預測 |
| 強型別 | 開發時即可進行型別檢查,確保查詢語法正確 |
| 自省能力(Introspection) | 內建 GraphiQL 瀏覽器 IDE,可直接撰寫、驗證和測試查詢 |

Figure 2.2: GraphiQL — GitHub's GraphQL explorer showing a complex query
專家建議: GitHub 遇到的最大問題是 REST payload 膨脹。隨著時間推移,序列化器中不斷添加資料,API 回應越來越龐大。GraphQL 讓開發者只查詢需要的資料。— Kyle Daigle,GitHub 生態系工程總監
GraphQL 的劣勢#
- 為 API 提供者增加了複雜性:伺服器需要額外處理來解析複雜查詢
- 效能優化困難:開放給第三方後,使用模式難以預測,管理多個傳入請求的開銷轉移到了後端複雜查詢的組合上
Request-Response API 比較#
| REST | RPC | GraphQL | |
|---|---|---|---|
| 核心概念 | 資源導向 | 動作導向 | 查詢語言 |
| 代表服務 | Stripe, GitHub, Google | Slack, Flickr | Facebook, GitHub, Yelp |
| HTTP 動詞 | GET, POST, PUT, PATCH, DELETE | GET, POST | GET, POST |
| 優點 | 標準化、易維護、善用 HTTP 特性 | 易理解、輕量、高效能 | 省往返、免版本、小 payload、強型別 |
| 缺點 | Payload 大、多次往返 | 難以發現、標準化有限 | 查詢解析複雜、後端優化困難 |
| 適用場景 | CRUD 類操作 | 暴露多種動作 | 需要查詢靈活性 |
Event-Driven API#
Request-Response API 的回應可能很快就過時。開發者為了保持資料最新,常常需要輪詢(Polling)——以固定頻率不斷查詢端點。
注意: 輪詢效率極低。Zapier 的研究發現,只有約 1.5% 的輪詢 API 呼叫實際回傳了新資料。低頻輪詢會遺漏事件,高頻輪詢則浪費大量資源。
為了即時共享事件資料,有三種常見機制:WebHooks、WebSockets 和 HTTP Streaming。
WebHooks#
WebHook 本質上是一個接受 HTTP POST 的 URL。當事件發生時,API 提供者向設定的 URL 發送訊息,實現即時更新。Slack、Stripe、GitHub 和 Zapier 都支援 WebHooks。

Figure 2.3: Polling versus WebHooks
WebHook 的實作對開發者而言通常很簡單——只需建立一個新的 HTTP 端點來接收事件,可以重用既有的基礎設施。但也帶來了新的複雜性:
| 挑戰 | 說明 |
|---|---|
| 失敗與重試 | 需要建立重試機制。Slack 會重試最多三次(立即、1 分鐘後、5 分鐘後),若端點持續回傳 95% 錯誤則停止推送並通知開發者 |
| 安全性 | WebHook 安全標準仍在演進中,開發者需自行確認收到的是合法的 WebHook |
| 防火牆 | 在防火牆後的應用程式無法接收入站流量,難以使用 WebHook |
| 雜訊 | 每次呼叫代表一個事件,當短時間內發生數千個事件時可能產生大量雜訊 |

Figure 2.4: Configuring a GitHub WebHook
WebSockets#
WebSocket 是一種在單一 TCP 連線上建立雙向串流通訊通道的協定。受主流瀏覽器支援,廣泛用於即時應用。
實際應用案例:
- Slack:透過 WebSocket 推送工作區中的所有事件(新訊息、表情符號反應、頻道建立),並提供 Real Time Messaging API
- Trello:將其他人的變更即時推送到監聽中的瀏覽器
- Blockchain:發送即時交易和區塊通知
WebSocket 的關鍵特性:
| 特性 | 說明 |
|---|---|
| 全雙工通訊 | 伺服器和客戶端可同時相互通訊,開銷低 |
| 穿越防火牆 | 設計為在 80 或 443 埠上運作,企業開發者尤其重視此特性 |
| 需維護連線 | 連線斷開時客戶端需重新建立,擴展性是挑戰 |

Figure 2.5: Frames sent over a full-duplex WebSocket connection
注意: 使用 Slack WebSocket API 的開發者必須為每個安裝應用的工作區建立一條連線。若應用安裝在 10,000 個工作區,開發者就需維護 10,000 條連線。
HTTP Streaming#
HTTP Streaming 讓伺服器透過客戶端開啟的單一長連線持續推送新資料,使回應長度變為無限。

Figure 2.6: Client-server interaction with an HTTP Streaming API
兩種傳輸方式:
- Chunked Transfer-Encoding:資料以換行分隔的字串分塊傳送,易於解析
- Server-Sent Events(SSE):適合瀏覽器端使用標準化的 EventSource API 消費事件
Twitter 就利用 HTTP Streaming 透過單一連線傳遞資料,開發者不需要持續輪詢就能接收新推文。
補充: HTTP Streaming 的主要問題在於緩衝。客戶端和代理伺服器常有緩衝限制,可能要到達閾值才開始渲染資料。若客戶端需要頻繁變更監聽的事件類型,則需要重新連線。
Event-Driven API 比較#
| WebHooks | WebSockets | HTTP Streaming | |
|---|---|---|---|
| 核心概念 | 透過 HTTP 回呼的事件通知 | TCP 上的雙向串流連線 | HTTP 上的長連線 |
| 代表服務 | Slack, Stripe, GitHub | Slack, Trello, Blockchain | Twitter, Facebook |
| 優點 | 易於伺服器間通訊、使用 HTTP 協定 | 雙向串流、原生瀏覽器支援、可穿越防火牆 | 使用簡單 HTTP、原生瀏覽器支援 |
| 缺點 | 無法穿越防火牆、難處理失敗與安全 | 需維護持久連線、非 HTTP | 雙向通訊困難、需重連 |
| 適用場景 | 伺服器端即時事件觸發 | 瀏覽器與伺服器間的雙向即時通訊 | 透過簡單 HTTP 的單向通訊 |
本章小結#
選擇 API 典範沒有萬能解。每種典範都適合特定的使用場景,你甚至可能需要同時支援多種典範——例如 Slack API 就同時支援 RPC 風格 API、WebSockets 和 WebHooks。
重點: 關鍵在於理解哪種方案最適合你的客戶、最能達成你的商業目標,以及在既有限制下什麼是可行的。