何時使用 GraphQL、gRPC 和 REST?
構建 API 是現代工程中開發人員的最重要任務之一。這些 API 允許不同的系統進行通信和數據交換。雖然 REST 多年來一直是實現 API 的事實標準,但今天也有新興的標準,如 gRPC 和 GraphQL。

什么是 API?
“應用程序編程接口”(API)是各種軟件服務之間的通信渠道。傳輸請求和響應的應用程序分別稱為客戶端和服務器。API 是一個外部軟件組件,使程序功能可供其他程序使用。
在下面的蜜蜂 ?? 插圖中,花朵充當服務器,蜂巢充當客戶端,蜜蜂提供通信手段(REST API 請求)。

什么是 API?(圖片來源:Rapid API)
存在不同的 API 架構或協議,如 REST、gRPC 和 GraphQL。
為什么 gRPC 很重要?
gRPC 是由 Google 開發的高性能、開源、通用遠程過程調用(RPC)框架。它使用 Protocol Buffers (protobuf) 作為其接口定義語言。協議緩沖區是一種非常有效和快速的網絡數據序列化方式。這項技術使用 HTTP 2.0 協議 實現了 RPC API;然而,服務器和 API 開發者都無法訪問 HTTP。它遵循 客戶端-響應通信模型,由于 gRPC 能夠接收來自多個客戶端的多個請求并同時處理它們,因此支持雙向通信和流媒體。然而,gRPC 在瀏覽器支持方面仍然 相當有限。
如前所述,gRPC 默認使用 Protocol Buffers 來序列化有效載荷數據。Protocol Buffers 是緊湊的二進制序列化格式,用于結構化數據。它們使用在 .proto 文件中定義的模式,允許在不同語言之間進行高效的編碼和解碼。它們提供了比傳統的 JSON 或 XML 更小的尺寸和更快的處理速度等優勢。
gRPC 的優點:
- 速度:由于 HTTP/2,gRPC 比 HTTP/1.1 上的 REST 更快、更高效。
- 多語言支持:提供工具在多種語言中生成客戶端和服務器代碼。
- 流媒體: 支持雙向流媒體,允許更互動的實時通信。
- 截止時間/超時: 內置支持確保請求不會掛起。它自動解決重試、網絡問題等。
- 生態系統: 支持身份驗證、負載均衡等。
gRPC 的缺點:
- 復雜: 您必須了解 Protocol Buffers 和 gRPC API。還必須預先定義模式。
- 瀏覽器支持有限: 由于依賴 HTTP/2,原生瀏覽器支持有限。
- 工具: 雖然在增長,但 gRPC 工具的成熟度不如 REST。您可以使用 gRPCurl 或 Postman 來測試這些 API。
- 不可讀性: 由于它們是二進制的,它們難以調試,就像您可以使用基于文本的格式(如 XML 或 JSON)那樣。

gRPC
什么是 Protocol Buffers?
Protocol Buffers,通常縮寫為 Protobuf,是 Google 在 2008 年設計的一種序列化結構化數據的方法。與 XML 或 JSON 類似,它們更精簡、更快,因為它們是二進制的,使它們成為與服務器通信或高效存儲數據的應用程序的首選。
使用 Protocol Buffers 進行數據序列化涉及幾個步驟:

- 定義數據結構:您從在 .proto 文件中定義數據結構開始。這包括指定數據類型(整數、字符串、布爾值、自定義類型等)及其字段編號。
- 生成源代碼:使用 Protocol Buffers 編譯器(protoc)從文件中生成您所需語言的源代碼。編譯器可以為多種語言生成代碼,包括 Java、C++、Python 等。
- 生成可執行包:可執行包也是與 Protobuf 代碼生成的源文件一起生成和部署的。在運行時,消息以二進制格式序列化和壓縮。
- 反序列化: 當接收方收到序列化的數據流時,他們可以使用生成的類輕松地將其轉換回結構化格式。
什么是 REST API?
REST(Representational State Transfer,表述性狀態傳遞)不是一個框架或庫,而是一種用于構建 Web 服務和 API 的架構風格。在 REST 中,一切都是 由唯一 URL 標識的資源,這些資源使用 HTTP 方法(如 GET(檢索資源)、POST(創建新資源)、PUT 或 PATCH(更新資源)和 DELETE(移除資源))進行操作。
客戶端到服務器的每個請求都必須包含理解和完成請求所需的所有信息。服務器不存儲請求之間的客戶端上下文,簡化了設計并提高了可伸縮性。客戶端和服務器的 HTTP 請求和響應體攜帶 JSON 或 XML 表示 資源的狀態。
在他的 博士論文中,計算機科學家 Roy Fielding 在 2000 年介紹并定義了表述性狀態傳遞。 REST API 的好處:
- 簡單性: 使用標準 HTTP 方法和常見數據格式使 REST API 易于理解和實現。
- 互操作性: REST API 促進了互操作性,因為不同的應用程序可以無縫交互,無論使用的是哪種編程語言或平臺。
- 可伸縮性: REST API 的無狀態性質允許輕松擴展以處理大量請求。
- 靈活性: 由于其多功能設計原則,REST API 可以適應各種用例。
REST API 的缺點:
- 無狀態性: REST 依賴于無狀態事務,這意味著每個請求都必須獨立完成所有信息。對于需要在多個請求之間維護狀態的工作流程(如電子商務網站上的購物車)來說,這可能很麻煩。
- 有效載荷大小有限: REST 中的數據傳輸通常通過 JSON 或 XML 有效載荷進行,如果您處理復雜數據或多個查詢,這可能會變得相當大。這可能導致性能問題。
- 可發現性不足: REST API 本身并不容易讓用戶理解其功能或如何與之交互,這可能會為新用戶增加復雜性。
- 復雜查詢的性能: 對于從較大資源中檢索特定數據點,REST 可能不是理想選擇。其他選項,如 GraphQL,在這種情況下可能更有效。
REST 定義了一個 API 應該遵循的 六個架構約束,以被認為是真正的 RESTful:
(1) 客戶端-服務器: 這種關注點的分離將客戶端(使用 API 的應用程序)與服務器(提供 API 的應用程序)分開。客戶端發起請求,服務器處理并發送響應。
(2) 無狀態: 客戶端到服務器的每個請求都必須包含理解請求所需的所有信息。服務器不存儲有關客戶端的任何上下文。這簡化了通信并提高了可伸縮性。
(3) 統一接口: 此約束定義了一組規則,規定客戶端如何與服務器交互。這些規則包括:
- 基于資源: API 暴露客戶端可以交互的資源。URL 標識資源。
- 標準方法: 客戶端使用標準 HTTP 方法(GET、POST、PUT、DELETE)對資源進行操作。
- 表示: 客戶端和服務器之間的數據以 JSON 或 XML 等標準格式交換。
(4) 可緩存: 客戶端可以將服務器響應標記為可緩存。這允許客戶端本地存儲頻繁訪問的數據,減輕服務器負載并提高性能。
(5) 分層系統: 架構可能包括客戶端和服務器之間的多個層次(代理、緩存、負載均衡器)。這些層可以提高性能、安全性和可伸縮性。
(6) 按需代碼(可選): 雖然不是嚴格必需的,但 RESTful API 可以選擇性地將可執行代碼傳輸給客戶端。客戶端可以使用此代碼擴展其功能或本地處理數據。

REST 架構約束
REST API 調用的一個例子 是當我們想要獲取 ID 為 500 的用戶信息時,使用 curl 命令行工具為 https://api.example.com 地址上的 API 發出的請求:curl -X GET https://api.example.com/users/500 -H "Accept: application/json"。最后一部分(Accept: application/json)是一個頭部,表明客戶端期望以 JSON 格式接收數據。響應將是 JSON 格式的結果,200 將是響應狀態碼。

REST API 架構
即使在性能至關重要時 REST 不是最佳選擇,我們仍然可以在這里做一些事情,如 緩存、分頁、有效載荷壓縮 等。
什么是 GraphQL?
GraphQL 是一種用于 API 的查詢語言,由 Meta 在 2015 年發布并開源。現在由 GraphQL 基金會 監督。GraphQL 是一個服務器端運行時環境,使客戶端能夠從 API 請求所需的數據。與傳統的 REST API 不同,后者通常需要多個請求來獲取不同的數據片段,GraphQL 允許您在單個請求中指定所需的所有數據。GraphQL 規范在 2015 年開源。
因為 GraphQL 在向 API 發送查詢時不會過度或不足地獲取結果,它保證了使用 GraphQL 構建的應用程序是 可伸縮、快速和穩定 的。它還允許將多個操作組合成單個 HTTP 請求。
GraphQL API 按照 類型和字段 組織,而不是端點。使用 GraphQL Schema Definition Language (SDL),您將數據定義為模式。這個模式作為客戶端和服務器之間的契約,詳細說明了可以進行哪些查詢、可以獲取哪些類型的數據以及響應將是什么樣子。
GraphQL 的好處:
- 高效的數據獲取: 您只請求確切需要的數據,消除了 REST 可能發生的過度獲取或不足獲取的問題。這可以顯著提高性能,尤其是對于復雜的數據模型。
- 靈活和聲明性: GraphQL 使用定義可用數據及其訪問方式的模式。這個模式允許開發人員編寫清晰、簡潔的查詢,指定他們確切的數據需求。
- 單個請求用于多個資源: 與 REST 不同,后者需要多個 API 調用來從不同端點獲取數據,GraphQL 允許將查詢組合成單個請求以提高效率。
- 版本控制和向后兼容性: 可以通過版本控制實現 GraphQL 模式更改,確保現有客戶端不受影響,同時允許未來增長。
GraphQL 的缺點:
- 查詢結構的復雜性: 雖然靈活性是一個優勢,但編寫復雜的 GraphQL 查詢可能具有挑戰性,并且需要仔細規劃以提高可讀性和可維護性。
- 緩存: 與利用內置 HTTP 緩存機制的 REST API 相比,GraphQL 的數據緩存通常更復雜。
- 安全性: GraphQL 暴露了您的整個數據模式,因此必須采取適當的安全措施以防止未經授權的訪問敏感數據。
- 學習曲線: 對于不熟悉 GraphQL 的開發人員,理解模式和查詢語法涉及學習曲線。
- 錯誤處理: 如果庫不解析響應體中狀態為 200 的錯誤,則客戶端必須使用更復雜的邏輯來處理它們。
它是如何工作的:
- 客戶端使用GraphQL語法定義查詢,精確指定數據應如何結構化以及需要哪些字段。
- GraphQL服務器使用預定義的模式來確定可用的數據及其與其他數據的關系。這個模式定義了類型、字段以及類型之間的關系。
- 服務器根據模式執行查詢。對于查詢中的每個字段,服務器都有一個相應的解析函數來獲取該字段的數據。
- 服務器返回一個JSON對象,其結構直接反映了查詢內容,填充了請求的數據。
GraphQL支持三種核心操作,定義了客戶端如何與服務器交互:
- 查詢(Queries): 用于從服務器檢索數據。這是GraphQL中最常用的操作。
- 變更(Mutations): 在服務器上修改數據。這可能涉及創建新數據、更新現有數據或刪除數據。
- 訂閱(Subscriptions): 用于在客戶端和服務器之間建立實時通信。服務器可以在請求的數據發生變化時更新客戶端。
GraphQL請求的一個示例包括一個操作和你請求或操作的數據,例如:

這個查詢檢索ID為1的用戶的數據。它還獲取了該用戶帖子的嵌套數據,包括它們的ID和標題。
響應是一個JSON對象,包含查詢或變更請求的實際數據和可選錯誤。

要了解更多關于GraphQL的信息,可以查看Eve Porcello和Alex Banks的書籍“Learning GraphQL”。
何時應使用GraphQL、gRPC和REST?
開發者在設計應用程序時可以選擇多種客戶端-服務器通信協議。在當代項目中,使用GraphQL、gRPC和REST相對常見。每種協議根據您的應用程序需求可以提供不同的優勢。
- GraphQL 是一種靈活的數據請求方法,專注于特定請求并僅提供所需數據。它的客戶端驅動特性使其與其他API區別開來。客戶端做出所有決策,而不是處理它們。GraphQL的優勢在于它與語言無關,請求通過單一端點進行,并且是強類型的,因為它有模式。
- REST 是最受歡迎的一個。當一個領域可以被描述為一組資源時,它是一個很好的選擇。REST是一種用于數據傳輸的無狀態架構。它的優勢包括是一個成熟的標準、簡單易用和良好的緩存支持。
- gRPC 是一個輕量級且快速的數據獲取系統。這里的主要區別是它如何描述其合同談判。它依賴于合同;架構不是管理談判的內容;它是服務器和客戶端之間的關系。雖然處理和計算被委托給遠程服務器,但大部分能力用于客戶端。它的主要優勢是它有輕量級客戶端,高效率,使用協議緩沖區來發送/接收數據,而且是開源的。
下圖顯示了最常見的API架構風格的時間線。

API架構風格時間線
因此,何時選擇這些協議中的每一個:
- 如果您正在構建一個CRUD風格的Web應用程序或您處理結構化數據良好,使用REST。它是公共API和需要被廣泛客戶端消費的服務的首選。
- 如果您的API是私有的并且關于行動或性能至關重要,使用gRPC。服務器到服務器通信的低延遲至關重要。它使用HTTP/2和ProtoBuf優化了效率和速度。
- 如果您有一個公共API,需要在定制請求方面靈活,并希望將不同來源的數據添加到公共API中,請使用GraphQL。在客戶端-服務器通信中使用它,我們必須在單次往返中獲取所有數據。

gRPC與REST與GraphQL比較































