選擇正確的 API 典範至關重要。API 典範定義了服務如何將後端資料暴露給其他應用程式的介面。

組織在起步時往往未充分考慮所有影響 API 成功的因素,導致日後沒有足夠的空間添加新功能。更棘手的是,一旦有開發者開始使用,修改 API 幾乎是不可能的事。因此,在開始之前花時間思考協定、模式和最佳實踐,能幫助你設計出未來可演進的 API。

目前主流的 API 典範包括 RESTRPCGraphQLWebHooksWebSockets。本章將深入探討這些不同的典範。

Request-Response API#

Request-Response API 通常透過 HTTP Web 伺服器暴露介面。API 定義一組端點(endpoint),客戶端發送 HTTP 請求,伺服器回傳 JSON 或 XML 格式的回應。三種常見的 Request-Response API 典範為:RESTRPCGraphQL

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
CreatePOST建立新使用者不適用
ReadGET列出所有使用者取得使用者 U123
UpdatePUT / PATCH批次更新更新使用者 U123
DeleteDELETE刪除所有使用者刪除使用者 U123
  • 標準 HTTP 狀態碼2XX 表示成功,3XX 表示重導向,4XX 表示客戶端錯誤,5XX 表示伺服器錯誤
  • 回應格式:雖然也支援 XML,但 JSON 已成為現代 API 的標準
GET /v1/charges/ch_CWyutlXs9pZyfD
HOST api.stripe.com
Authorization: Bearer YNoJ1Yq64iCBhzfL9HNO00fzVrsEjtVl
POST /v1/charges/ch_CWyutlXs9pZyfD
HOST api.stripe.com
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer YNoJ1Yq64iCBhzfL9HNO00fzVrsEjtVl

amount=2000&currency=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 的兩條簡單規則:

  1. 端點包含要執行的操作名稱
  2. 使用最適當的 HTTP 動詞GET 用於唯讀請求,POST 用於其他操作

RPC 風格適合以下場景:

  • 暴露多種細微且複雜的動作
  • 有與「資源」無關的副作用
  • 複雜的資源模型或涉及多種資源類型的操作
POST /api/conversations.archive
HOST slack.com
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer xoxp-1650112-jgc2asDae

channel=C01234

Slack 的 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 比較#

RESTRPCGraphQL
核心概念資源導向動作導向查詢語言
代表服務Stripe, GitHub, GoogleSlack, FlickrFacebook, GitHub, Yelp
HTTP 動詞GET, POST, PUT, PATCH, DELETEGET, POSTGET, POST
優點標準化、易維護、善用 HTTP 特性易理解、輕量、高效能省往返、免版本、小 payload、強型別
缺點Payload 大、多次往返難以發現、標準化有限查詢解析複雜、後端優化困難
適用場景CRUD 類操作暴露多種動作需要查詢靈活性

Event-Driven API#

Request-Response API 的回應可能很快就過時。開發者為了保持資料最新,常常需要輪詢(Polling)——以固定頻率不斷查詢端點。

注意: 輪詢效率極低。Zapier 的研究發現,只有約 1.5% 的輪詢 API 呼叫實際回傳了新資料。低頻輪詢會遺漏事件,高頻輪詢則浪費大量資源。

為了即時共享事件資料,有三種常見機制:WebHooksWebSocketsHTTP 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

兩種傳輸方式:

  1. Chunked Transfer-Encoding:資料以換行分隔的字串分塊傳送,易於解析
  2. Server-Sent Events(SSE):適合瀏覽器端使用標準化的 EventSource API 消費事件

Twitter 就利用 HTTP Streaming 透過單一連線傳遞資料,開發者不需要持續輪詢就能接收新推文。

補充: HTTP Streaming 的主要問題在於緩衝。客戶端和代理伺服器常有緩衝限制,可能要到達閾值才開始渲染資料。若客戶端需要頻繁變更監聽的事件類型,則需要重新連線。

Event-Driven API 比較#

WebHooksWebSocketsHTTP Streaming
核心概念透過 HTTP 回呼的事件通知TCP 上的雙向串流連線HTTP 上的長連線
代表服務Slack, Stripe, GitHubSlack, Trello, BlockchainTwitter, Facebook
優點易於伺服器間通訊、使用 HTTP 協定雙向串流、原生瀏覽器支援、可穿越防火牆使用簡單 HTTP、原生瀏覽器支援
缺點無法穿越防火牆、難處理失敗與安全需維護持久連線、非 HTTP雙向通訊困難、需重連
適用場景伺服器端即時事件觸發瀏覽器與伺服器間的雙向即時通訊透過簡單 HTTP 的單向通訊

本章小結#

選擇 API 典範沒有萬能解。每種典範都適合特定的使用場景,你甚至可能需要同時支援多種典範——例如 Slack API 就同時支援 RPC 風格 API、WebSockets 和 WebHooks。

重點: 關鍵在於理解哪種方案最適合你的客戶、最能達成你的商業目標,以及在既有限制下什麼是可行的。