精讀《REST, GraphQL, Webhooks, & gRPC 如何選型》

發表於2018-09-15

1 引言

每當專案進入聯調階段,或者提前約定介面時,前後端就會聚在一起熱火朝天的討論起來。可能 99% 的場景都在約定 Http 介面,討論 URL 是什麼,入參是什麼,出參是什麼。

有的團隊前後端介面約定更加高效,後端會拿出介面定義程式碼,前端會轉換成(或自動轉成)Typescript 定義檔案。

但這些工作都針對於 Http 介面,今天通過 when-to-use-what-rest-graphql-webhooks-grpc 一文,拋開聯調時千遍一律的 Http 介面,一起看看介面還可以怎麼約定,分別適用於哪些場景,你現在處於哪個場景。

2 概述

本文主要講了四種介面設計方案,分別是:REST、gRPC、GraphQL、Webhooks,下面分別介紹一下。

REST

REST 也許是最通用,也是最常用的介面設計方案,它是 無狀態的,以資源為核心,針對如何操作資源定義了一系列 URL 約定,而操作型別通過 GET POST PUT DELETE 等 HTTP Methods 表示。

REST 基於原生 HTTP 介面,因此改造成本很小,而且其無狀態的特性,降低了前後端耦合程度,利於快速迭代。

隨著未來發展,REST 可能更適合提供微服務 API。

使用舉例:

gRPC

gRPC 是對 RPC 的一個新嘗試,最大特點是使用 protobufs 語言格式化資料。

RPC 主要用來做伺服器之間的方法呼叫,影響其效能最重要因素就是 序列化/反序列化 效率。RPC 的目的是打造一個高效率、低消耗的服務呼叫方式,因此比較適合 IOT 等對資源、頻寬、效能敏感的場景。而 gRPC 利用 protobufs 進一步提高了序列化速度,降低了資料包大小。

使用舉例:

gRPC 主要用於服務之間傳輸,這裡拿 Nodejs 舉例:

1.定義介面。由於 gRPC 使用 protobufs,所以介面定義檔案就是 helloword.proto:

這裡定義了服務 Greeter,擁有兩個方法:SayHelloSayHelloAgain,通過 message 關鍵字定義了入參與出參的結構。

事實上利用 protobufs,傳輸資料時僅傳送很少的內容,作為代價,雙方都要知道介面定義規則才能序列化/反序列化。

2.定義伺服器:

我們在 50051 埠支援了 gRPC 服務,並註冊了服務 Greeter,並對 sayHello sayHelloAgain 方法做了一些業務處理,並返回給呼叫方一些資料。

3.定義客戶端:

可以看到,客戶端和服務端同時需要拿到 proto 結構,客戶端資料傳送也要依賴 proto 包提供的方法,框架會內建做掉序列化/反序列化的工作。

也有一些額外手段將 gRPC 轉換為 http 服務,讓網頁端也享受到其高效、低耗的好處。但是不要忘了,RPC 最常用的場景是 IOT 等硬體領域,網頁場景也許不會在乎節省幾 KB 的流量。

GraphQL

GraphQL 不是 REST 的替代品,而是另一種互動形式:前端決定後端的返回結果。

GraphQL 帶來的最大好處是精簡請求響應內容,不會出現冗餘欄位,前端可以決定後端返回什麼資料。但要注意的是,前端的決定權取決於後端支援什麼資料,因此 GraphQL 更像是精簡了返回值的 REST,而後端介面也可以一次性定義完所有功能,而不需要逐個開發。

再次強調,相比 REST 和 gRPC,GraphQL 是由前端決定返回結果的反模式。

使用舉例:

原文推薦參考 GitHub GraphQL API

比如查詢某個組織下的成員,REST 風格介面可能是:

含義很明確,但問題是返回結果不明確,必須實際除錯才知道。換成等價的 GraphQL 是這樣的

返回的結果和約定的格式結構一致,且不會有多餘的欄位:

但是能看出來,這樣做需要一個系統幫助你寫 query,很多框架都提供這個功能,比如 apollo-client

Webhooks

如果說 GraphQL 顛覆了前後端互動模式,那 Webhooks 可以說是徹頭徹尾的反模式了,因為其定義就是,前端不主動傳送請求,完全由後端推送。

它最適合解決輪詢問題。或者說輪詢就是一種妥協的行為,當後端不支援 Webhooks 模式時。

使用舉例:

Webhooks 本身也可以由 REST 或者 gRPC 實現,所以就不貼程式碼了。舉個常用例子,比如你的好友發了一條朋友圈,後端將這條訊息推送給所有其他好友的客戶端,就是 Webhooks 的典型場景。


最後作者給出的結論是,這四個場景各有不同使用場景,無法相互替代:

  • REST:無狀態的資料傳輸結構,適用於通用、快速迭代和標準化語義的場景。
  • gRPC:輕量的傳輸方式,特殊適合對效能高要求或者環境苛刻的場景,比如 IOT。
  • GraphQL: 請求者可以自定義返回格式,某些程度上可以減少前後端聯調成本。
  • Webhooks: 推送服務,主要用於伺服器主動更新客戶端資源的場景。

3 精讀

REST 並非適用所有場景

本文給了我們一個更大的視角看待日常開發中的介面問題,對於奮戰在一線的前端同學,接觸到 90% 的介面都是非 REST 規則的 Http 介面,能真正落實 REST 的團隊其實非常少。這其實暴露了一個重要問題,就是 REST 所帶來的好處,在整套業務流程中到底佔多大的比重?

不僅介面設計方案的使用要分場景,針對某個介面方案的重要性也要再繼續細分:在做一個開放介面的專案,提供 Http 介面給第三方使用,這時必須好好規劃介面的語義,所以更容易讓大家達成一致使用 REST 約定;而開發一個產品時,其實前後端不關心介面格式是否規範,甚至在開發內網產品時,效能和冗餘都不會考慮,效率放在了第一位。所以第一點啟示是,不要埋冤當前團隊業務為什麼沒有使用某個更好的介面約定,因為介面約定很可能是業務形態決定的,而不是憑空做技術對比從而決定的。

gRPC 是服務端互動的首選

前端同學轉 node 開發時,很喜歡用 Http 方式進行伺服器間通訊,但可能會疑惑,為什麼公司內部 Java 或者 C++ 寫的服務都不提供 Http 方式呼叫,而是另外一個名字。瞭解 gRPC 後,可以認識到這些平臺都是對 RPC 方式的封裝,伺服器間通訊對效能和延時要求非常高,所以比較適合專門為效能優化的 gRPC 等服務。

GraphQL 需要配套

GraphQL 不是 REST 的替代品,所以不要想著團隊從 Http 介面遷移到 GraphQL 就能提升 X% 的開發效率。GraphQL 方案是一種新的前後端互動約定,所以上手成本會比較高,同時,為了方便前端同學拼 query,等於把一部分後端工作量轉移給了前端,如果此時沒有一個足夠好用的平臺快速查閱、生成、維護這些定義,開發效率可能不升反降。

總的來說,對外開放 API 或者擁有完整配套的場景,使用 GraphQL 是比較理想的,但對於快速迭代,平臺又不夠成熟的團隊,繼續使用標準 Http 介面可以更快完成專案。

Webhooks 解決特殊場景問題

對於第三方平臺驗權、登陸等 沒有前端介面做中轉的場景,或者強安全要求的支付場景等,適合用 Webhooks 做資料主動推送。說白了就是在前端無從參與,或者因為前端安全問題不適合參與時,就是 Webhooks 的場景。很顯然 Webhooks 也不是 Http 的替代品,不過的確是一種新的前後端互動方式。

對於慢查詢等場景,前端普遍使用輪詢完成,這和 Socket 相比體驗更弱,但無狀態的特性反而會降低伺服器負擔,所以慢查詢和即時通訊要區分對待,使用者對訊息及時性的敏感程度決定了使用哪種方案。

4 總結

最後,上面總結的內容一定還有許多疏漏,歡迎補充。

5 更多討論

討論地址是:精讀《REST, GraphQL, Webhooks, & gRPC 如何選型》 · Issue #102 · dt-fe/weekly

如果你想參與討論,請點選這裡,每週都有新的主題,週末或週一釋出。

相關文章