4 種主流的 API 架構(gòu)風(fēng)格對(duì)比

作者 | AltexSoft 譯者 | 朱琪珊;策劃 | 萬佳
本文討論了四種主要的 API 架構(gòu)風(fēng)格,比較它們的優(yōu)缺點(diǎn),并重點(diǎn)介紹每種情況下最適合的 API 架構(gòu)風(fēng)格。

不同時(shí)間的 API 架構(gòu)風(fēng)格,圖源:Rob Crowley

四種 API 架構(gòu)風(fēng)格
1
RPC:調(diào)用另一個(gè)系統(tǒng)的函數(shù)
遠(yuǎn)程過程調(diào)用是一種允許在不同上下文中遠(yuǎn)程執(zhí)行函數(shù)的規(guī)范。RPC 擴(kuò)展了本地過程調(diào)用的概念,并將其放在 HTTP API 的上下文中。
最初的 XML-RPC 是存在問題的,因?yàn)楹茈y確保 XML 有效負(fù)載的數(shù)據(jù)類型。因此,后來 RPC API 開始使用一個(gè)更具體的 JSON-RPC 規(guī)范,該規(guī)范被認(rèn)為是 SOAP 的更簡單的替代方案。gRPC 是 Google 在 2015 年開發(fā)的最新 RPC 版本。gRPC 可插拔支持負(fù)載均衡、追蹤、運(yùn)行狀況檢查和身份驗(yàn)證,它非常適合連接不同的微服務(wù)。
?RPC 的工作機(jī)制
客戶端調(diào)用一個(gè)遠(yuǎn)程的過程,將參數(shù)和附加信息序列化為消息,然后將消息發(fā)送到服務(wù)端。服務(wù)端在接受到消息后,將信息的內(nèi)容反序列化,執(zhí)行所請(qǐng)求的操作,然后將結(jié)果發(fā)送回客戶端??蛻舳撕头?wù)端各自負(fù)責(zé)參數(shù)的序列化和反序列化。

遠(yuǎn)程過程調(diào)用的機(jī)制,圖源:Guru99
?RPC 的優(yōu)勢
簡單直接的交互。RPC 使用 GET 來獲取信息,使用 POST 來處理其他所有操作。服務(wù)端和客戶端之間交互的機(jī)制歸結(jié)為調(diào)用端點(diǎn)并獲得響應(yīng)。
易于添加新函數(shù)。 如果 API 有了新的需求,我們可以輕松地添加另一個(gè)執(zhí)行這個(gè)需求的端點(diǎn):1)編寫一個(gè)新函數(shù),并將其放在一個(gè)新端點(diǎn)之后;2)現(xiàn)在,客戶可以訪問這個(gè)端點(diǎn),并獲取符合其需求的信息。
高性能。輕量級(jí)的有效負(fù)載不會(huì)對(duì)網(wǎng)絡(luò)產(chǎn)生壓力,以此提供高性能,這對(duì)于共享服務(wù)器和在工作站網(wǎng)絡(luò)上執(zhí)行并行計(jì)算非常重要。RPC 還能夠優(yōu)化網(wǎng)絡(luò)層,使得不同服務(wù)之間每天發(fā)送海量消息變得非常高效。
?RPC 的不足
和底層系統(tǒng)緊密耦合。API 的抽象級(jí)別有助于其可重用性。API 與基礎(chǔ)系統(tǒng)的耦合越緊密,對(duì)其他系統(tǒng)的可重用性就越差。RPC 與基礎(chǔ)系統(tǒng)的緊密耦合不允許其在系統(tǒng)函數(shù)和外部 API 之間建立抽象層。這很容易引起安全問題,因?yàn)殛P(guān)于基礎(chǔ)系統(tǒng)的細(xì)節(jié)實(shí)現(xiàn)很容易會(huì)泄漏到 API 中。
RPC 的緊密耦合使得可伸縮性要求和松散耦合的團(tuán)隊(duì)難以實(shí)現(xiàn)。因此,客戶端要么會(huì)擔(dān)心調(diào)用特定端點(diǎn)的帶來的任何可能的副作用,要么需要嘗試弄清楚要調(diào)用的端點(diǎn),因?yàn)榭蛻舳瞬涣私夥?wù)器如何命名其函數(shù)。
可發(fā)現(xiàn)性低。 在 RPC 中,無法對(duì) API 進(jìn)行檢驗(yàn)總結(jié),或者發(fā)送請(qǐng)求來開始理解根據(jù)需求應(yīng)該調(diào)用哪個(gè)函數(shù)。
函數(shù)爆炸性增長。創(chuàng)建新函數(shù)非常容易。因此,相較于重新編輯現(xiàn)有的函數(shù),我們會(huì)傾向于創(chuàng)建新的功能,最終產(chǎn)生大量難以理解的、功能重疊的函數(shù)。
?RPC 的用例
RPC 模式在八十年代開始使用,但這并不意味著它已經(jīng)過時(shí)了。諸如 Google、Facebook(Apache Thrift)和 Twitch(Twirp)這樣的大公司如今正在內(nèi)部使用高性能的 RPC 版本,來執(zhí)行極高性能、低開銷的消息傳遞。它們龐大的微服務(wù)系統(tǒng)要求內(nèi)部通信在使用短消息的情況下也保持清晰。
命令 API。RPC 是用于將命令發(fā)送到遠(yuǎn)程系統(tǒng)的正確選擇。例如,Slack API 是非常以命令為中心的:加入頻道、離開頻道、發(fā)送消息。因此,Slack API 的設(shè)計(jì)者以類似于 RPC 的樣式對(duì)其進(jìn)行了建模,使其小巧、緊湊并且易于使用。
用于內(nèi)部微服務(wù)的客戶特定的 API。由于是在單個(gè)提供者和單個(gè)使用者之間建立直接的集成,我們不想像 REST API 那樣,花太多時(shí)間通過網(wǎng)絡(luò)傳輸大量的元數(shù)據(jù)。憑借高消息速率和消息性能,gRPC 和 Twirp 成為了用于微服務(wù)的可靠用例。通過在底層使用 HTTP 2,gRPC 能優(yōu)化網(wǎng)絡(luò)層,使其非常高效地在不同服務(wù)之間每天傳送大量信息。然而,如果你并不是要著眼于提高網(wǎng)絡(luò)性能,而是要在發(fā)布高度獨(dú)立的微服務(wù)團(tuán)隊(duì)之間建立一個(gè)穩(wěn)定的 API 聯(lián)系。REST 就能做到。
2
SOAP:使數(shù)據(jù)作為服務(wù)可用
SOAP 是一個(gè) XML 格式的、高度標(biāo)準(zhǔn)化的網(wǎng)絡(luò)通訊協(xié)議。在 XML-RPC 發(fā)布的一年后,SOAP 由微軟發(fā)布、并繼承了許多 XML-RPC 的特性。在 REST 緊隨其后發(fā)布,一開始它們是被同時(shí)使用,但很快 REST 贏得了這次比賽,成為了更流行的協(xié)議。
?SOAP 的工作機(jī)制
XML 數(shù)據(jù)格式拖累了很多數(shù)據(jù)規(guī)范。伴隨著大量的消息結(jié)構(gòu),XML 數(shù)據(jù)格式使得 SOAP 成為了最冗長的 API 架構(gòu)風(fēng)格。
SOAP 的消息由這些部件組成:
一個(gè)信封標(biāo)簽:用于開始和結(jié)束每條消息
包含請(qǐng)求或響應(yīng)的正文
一個(gè)標(biāo)頭:用于表示消息是否由某些規(guī)范或額外要求的來確認(rèn)
故障通知:包含了可能在請(qǐng)求處理過程只能夠發(fā)生的任何錯(cuò)誤

一個(gè) SOAP 消息的例子,圖源:IBM
SOAP API 的邏輯由 Web 服務(wù)描述語言(WSDL)編寫。該 API 描述語言定義了端點(diǎn)并描述了可以執(zhí)行的所有過程。這使得不同的編程語言和 IDE 能夠快速建立通信。
SOAP 支持有狀態(tài)和無狀態(tài)消息傳遞。在有狀態(tài)的情況下,服務(wù)器存儲(chǔ)接收到的信息可能非常繁瑣復(fù)雜。但這對(duì)于涉及多方和復(fù)雜交易的操作是合理的。
?SOAP 的優(yōu)勢
獨(dú)立于語言和平臺(tái)。內(nèi)置創(chuàng)建 Web 服務(wù)的功能使得 SOAP 能夠處理消息通信的同時(shí)發(fā)送獨(dú)立于語言和平臺(tái)響應(yīng)。
綁定到各種協(xié)議。SOAP 在適用于多種場景的傳輸協(xié)議方面是十分靈活的。
內(nèi)置錯(cuò)誤處理。SOAP API 規(guī)范允許返回帶有錯(cuò)誤碼及其說明的的 XML 重試消息。
一系列的安全拓展。SOAP 與 ES-Security 集成,因此 SOAP 可滿足企業(yè)級(jí)事務(wù)要求。它在事務(wù)內(nèi)部提供了隱私和完整性,同時(shí)允許在消息級(jí)別進(jìn)行加密。

SOAP 消息級(jí)別的安全性:在標(biāo)頭元素的認(rèn)證數(shù)據(jù)以及加密的正文
?SOAP 的不足
如今,由于如下幾種原因,許多開發(fā)人員在聽到必須集成 SOAP API 的想法后都會(huì)感到不安。
僅使用 XML。SOAP 消息包含大量的元數(shù)據(jù),并且在請(qǐng)求和響應(yīng)時(shí)僅支持繁冗的 XML 格式。
重量級(jí)。由于 XML 文件的大小,SOAP 服務(wù)需要很大的帶寬。
非常專業(yè)化的知識(shí)。構(gòu)建 SOAP API 服務(wù)器需要對(duì)所有涉及到的協(xié)議以及它們及其嚴(yán)格的限制都有很深的了解。
乏味的消息更新。由于需要額外的工作來添加或者刪除某個(gè)消息屬性,這種死板的 SOAP 模式減慢了其被采用的速度。
?SOAP 的用例
目前,SOAP 體系結(jié)構(gòu)最常用于企業(yè)內(nèi)部或與其信任的合作伙伴的內(nèi)部集成。
高度安全的數(shù)據(jù)傳輸。SOAP 嚴(yán)格的消息結(jié)構(gòu),安全性和授權(quán)功能使其成為在 API 和客戶端之間執(zhí)行正式軟件協(xié)議的最合適的選擇,同時(shí)又符合 API 提供者與 API 使用者之間的法律合同。這就是為什么金融組織和其他企業(yè)用戶選擇適用 SOAP 的原因。
3
REST:使數(shù)據(jù)作為資源可用
REST 如今是一種無需解釋的 API 架構(gòu)風(fēng)格,它由一系列的架構(gòu)約束所定義,旨在被廣泛 API 使用者采用。
當(dāng)前最常見的 API 架構(gòu)風(fēng)格最初時(shí)由 Roy Fielding 在其博士論文中提出的。REST 使得服務(wù)端的數(shù)據(jù)可用,并以簡單的格式(通常是 JSON 和 XML)來表示它。
?REST 的工作機(jī)制
REST 的定義并不像 SOAP 那樣嚴(yán)格。RESTful 體系結(jié)構(gòu)應(yīng)該遵守如下六個(gè)體系結(jié)構(gòu)約束:
統(tǒng)一接口:無論設(shè)備或應(yīng)用程序類型如何,都可以采用統(tǒng)一的方式與給定的服務(wù)端進(jìn)行交互。
無狀態(tài):請(qǐng)求本身包含處理該請(qǐng)求所需要的狀態(tài),并且服務(wù)端不存儲(chǔ)與會(huì)話相關(guān)的任何內(nèi)容。
緩存
客戶端 - 服務(wù)器體系結(jié)構(gòu):允許雙方獨(dú)立發(fā)展
應(yīng)用程序的層級(jí)系統(tǒng)
服務(wù)端向客戶端提供可執(zhí)行代碼的能力

理查森成熟度模型作為實(shí)現(xiàn)真正完整且有用的 API 架構(gòu)的目標(biāo)。圖源:Kristopher Sandoval

以動(dòng)詞為中心的 RPC 模型和以名詞為中心的 REST 模型中的操作對(duì)比
在 REST 中,使用例如 GET、POST、PUT、DELETE、OPTIONS 可能還有 PATCH 等 HTTP 方法來完成操作。

圖源:Thomas David
?REST 的優(yōu)勢
4
GraphQL:僅請(qǐng)求所需要的數(shù)據(jù)
REST API 需要被多次調(diào)用才能返回所需要的資源。所以,GraphQL 被發(fā)明了,并改變了這一切游戲的規(guī)則。
GraphQL 是一種語法,它描述了如何進(jìn)行精確的數(shù)據(jù)請(qǐng)求。有些應(yīng)用程序的數(shù)據(jù)模型具有許多相互引用的復(fù)雜實(shí)體,在這種情況下,實(shí)現(xiàn) GraphQL 是值得的。

如何從 GraphQL 端點(diǎn)僅獲取所需要的數(shù)據(jù),圖源:Mohit Tikoo
如今,GraphQL 的生態(tài)系統(tǒng)正在蓬勃發(fā)展,出現(xiàn)了例如 Apollo、GraphiQL 和 GraphQL Explorer 等強(qiáng)大的庫和工具。
?GraphQL 的工作機(jī)制
GraphQL 從構(gòu)建模式(Schema)開始。模式是對(duì)于用戶可以在 GraphQL API 中進(jìn)行的所有查詢及其返回的所有類型的描述。模式構(gòu)建非常困難,因?yàn)樗枰褂媚J蕉x語言(SDL)進(jìn)行強(qiáng)類型化。
因?yàn)樵诳蛻舳诉M(jìn)行查詢之前已經(jīng)定義好了模式,所以客戶端可以驗(yàn)證其查詢語句,以確保服務(wù)端能夠?qū)Σ樵冋Z句進(jìn)行響應(yīng)。在查詢語句到達(dá)后端應(yīng)用程序時(shí),GraphQL 操作將根據(jù)整個(gè)模式進(jìn)行解釋,并向前端應(yīng)用程序返回解析到的數(shù)據(jù)。API 向服務(wù)端發(fā)送一個(gè)龐大的查詢,該 API 返回一個(gè)僅包含我們所需數(shù)據(jù)的 JSON 響應(yīng)。

GraphQL 的查詢語句執(zhí)行,圖源:Jonas Helfer
除了包含 RESTful 的 CRUD 操作,GraphQL 還有訂閱(subscriptions)機(jī)制,允許接收來自服務(wù)端的實(shí)時(shí)通知。
?GraphQL 的優(yōu)勢
具有類型的模式:GraphQL 提前公開了它能做什么,從而提高了其可發(fā)現(xiàn)性。通過將客戶端指向 GraphQL API,我們可以發(fā)現(xiàn)什么查詢語句是可用的。
沒有版本控制:版本控制的最佳實(shí)踐是不要對(duì) API 進(jìn)行版本控制。
盡管 REST 提供了不同的 API 版本,GraphQL 使用的是不斷更新的單一版本,這使用戶可以持續(xù)訪問新功能,并有助于提供更整潔、更可維護(hù)的服務(wù)器代碼。
詳細(xì)的錯(cuò)誤消息:GraphQL 以類似于 SOAP 的方式提供所發(fā)生錯(cuò)誤的詳細(xì)信息。它的錯(cuò)誤消息包括所有解析器,并指向確切的發(fā)生故障時(shí)的查詢部分。
靈活的權(quán)限:GraphQL 允許選擇性地公開某些功能,同時(shí)保留私人信息。而相對(duì)應(yīng)的是,REST 體系架構(gòu)不能僅顯示部分?jǐn)?shù)據(jù),要么是全部數(shù)據(jù),要么是沒有數(shù)據(jù)。
?GraphQL 的不足
性能問題。GraphQL 權(quán)衡了復(fù)雜性,來實(shí)現(xiàn)其強(qiáng)大功能。一個(gè)請(qǐng)求中的嵌套字段太多會(huì)導(dǎo)致系統(tǒng)過載。因此,對(duì)于復(fù)雜的查詢,REST 仍然是更好的選擇。
緩存復(fù)雜度。由于 GraphQL 不再使用 HTTP 緩存語義,因此使用者需要額外自定義緩存。
大量的預(yù)開發(fā)教育。由于沒有足夠的時(shí)間來了解 GraphQL 的某個(gè)操作和 SDL,因此許多項(xiàng)目決定采用眾所周知的 REST 方法。
?GraphQL 的用例
移動(dòng) API。在這種情況下,網(wǎng)絡(luò)性能和單個(gè)消息有效負(fù)載優(yōu)化很重要。因此,GraphQL 為移動(dòng)設(shè)備提供了更有效的數(shù)據(jù)加載方式。
復(fù)雜的系統(tǒng)和微服務(wù)。GraphQL 能夠隱藏其 API 背后的多個(gè)系統(tǒng)集成的復(fù)雜性。GraphQL 從多個(gè)地方聚合數(shù)據(jù),并將它們合并為一個(gè)全局的模式。對(duì)于隨時(shí)間推移而逐漸擴(kuò)展的遺留基礎(chǔ)架構(gòu)或第三方 API 來說,這尤其重要。
5
哪種 API 模式最適用你的用例?
每個(gè) API 項(xiàng)目都有不同的限制和需求。通常,API 架構(gòu)的選擇取決于:
所使用的編程語言,
你的開發(fā)環(huán)境,以及
你的資源預(yù)算,包括人力資源和財(cái)務(wù)資源。
在了解了每種設(shè)計(jì)風(fēng)格的利與弊之后,API 設(shè)計(jì)人員可以選擇最適合項(xiàng)目的那一種。
具有強(qiáng)耦合性的 RPC 很適用于內(nèi)部微服務(wù),但它對(duì)外部 API 或者 API 服務(wù)而言不是一個(gè)好的選擇。
SOAP 的使用有些麻煩,但它強(qiáng)大的安全拓展使它在計(jì)費(fèi)操作、預(yù)訂系統(tǒng)和支付方面是無可替代的。
REST 是針對(duì) API 的最高級(jí)別的抽象和最佳模型。但它往往會(huì)有些“啰嗦”而增加系統(tǒng)的負(fù)擔(dān) —— 如果你使用的是移動(dòng)設(shè)備,這是個(gè)問題。
GraphQL 在數(shù)據(jù)獲取方面向前邁出了一大步,但并不是每個(gè)人都有足夠的時(shí)間后精力來掌握它。
歸根結(jié)底,去針對(duì)一些小型的用例來嘗試某種特定 API 架構(gòu),并去了解它是否適合你的用例以及是否解決了你的問題,這樣做是比較合適的。如果它適用于你的用例,就可以嘗試擴(kuò)展并查看它是否適用于更多的用例。
原文鏈接:
https://levelup.gitconnected.com/comparing-api-architectural-styles-soap-vs-rest-vs-graphql-vs-rpc-84a3720adefa
逆鋒起筆是一個(gè)專注于程序員圈子的技術(shù)平臺(tái),你可以收獲最新技術(shù)動(dòng)態(tài)、最新內(nèi)測資格、BAT等大廠的經(jīng)驗(yàn)、精品學(xué)習(xí)資料、職業(yè)路線、副業(yè)思維,微信搜索逆鋒起筆關(guān)注!
推薦閱讀
點(diǎn)個(gè)?在看?
喜歡是一種感覺
在看是一種支持
↘↘↘
