兩個獨立的應(yīng)用程序需要中介程序才能相互通信。 因此,開發(fā)人員經(jīng)常建立橋梁-應(yīng)用程序編程接口-來允許一個系統(tǒng)訪問另一個系統(tǒng)的信息或功能。
為了快速,大規(guī)模地集成應(yīng)用程序,使用協(xié)議和/或規(guī)范來定義通過導(dǎo)線傳遞的消息的語義和語法的API。 這些規(guī)范構(gòu)成了API體系結(jié)構(gòu)。
隨著時間的流逝,已經(jīng)發(fā)布了不同的API架構(gòu)樣式。 它們每個都有自己的標(biāo)準(zhǔn)化數(shù)據(jù)交換模式。 選擇的余地引發(fā)了關(guān)于哪種建筑風(fēng)格最好的爭論。
> API styles over time, Source: Rob Crowley
如今,許多API使用者將REST稱為" REST和平",并為GraphQL歡呼,而十年前,REST取代SOAP成為贏家,這是一個相反的故事。 這些觀點的問題在于,他們只是一方面選擇一種技術(shù),而不是考慮其實際屬性和特性如何與當(dāng)前情況相匹配。
在本文中,我們將保持客觀,并按外觀順序討論四種主要的API樣式,比較它們的優(yōu)缺點,并重點介紹每種情況下最適合的情況。
> Four major API styles compared
遠(yuǎn)程過程調(diào)用(RPC):在另一個系統(tǒng)上調(diào)用功能
遠(yuǎn)程過程調(diào)用是一種允許在不同上下文中遠(yuǎn)程執(zhí)行功能的規(guī)范。 RPC擴(kuò)展了本地過程調(diào)用的概念,但將其放在HTTP API的上下文中。
最初的XML-RPC存在問題,因為很難確保XML有效負(fù)載的數(shù)據(jù)類型。 因此,后來RPC API開始使用更具體的JSON-RPC規(guī)范,該規(guī)范被認(rèn)為是SOAP的更簡單替代方案。 gRPC是google在2015年開發(fā)的最新RPC版本。gRPC可插拔支持負(fù)載平衡,跟蹤,運行狀況檢查和身份驗證,非常適合連接微服務(wù)。
RPC如何運作
客戶端調(diào)用遠(yuǎn)程過程,將參數(shù)和其他信息序列化為消息,然后將消息發(fā)送到服務(wù)器。 在接收到消息時,服務(wù)器反序列化其內(nèi)容,執(zhí)行所請求的操作,然后將結(jié)果發(fā)送回客戶端。 服務(wù)器存根和客戶端存根負(fù)責(zé)參數(shù)的序列化和反序列化。
> Remote Procedure Calling Mechanism, Source: Guru99
RPC優(yōu)點
簡單直接的互動。 RPC使用GET來獲取信息,并使用POST進(jìn)行其他所有操作。 服務(wù)器與客戶端之間的交互機(jī)制歸結(jié)為調(diào)用端點并獲得響應(yīng)。
易于添加的功能。 如果對API提出了新要求,我們可以輕松添加另一個執(zhí)行此要求的端點:1)編寫一個新函數(shù)并將其扔到端點后面; 2)現(xiàn)在,客戶可以訪問該端點并獲取符合設(shè)置要求的信息 。
高性能。 輕量級有效負(fù)載在網(wǎng)絡(luò)上變得容易,可提供高性能,這對于共享服務(wù)器和在工作站網(wǎng)絡(luò)上執(zhí)行的并行計算非常重要。 RPC能夠優(yōu)化網(wǎng)絡(luò)層,并通過每天在不同服務(wù)之間發(fā)送大量消息來使其變得非常高效。
RPC缺點
與底層系統(tǒng)緊密耦合。 API的抽象級別有助于其可重用性。 它與基礎(chǔ)系統(tǒng)越緊密,對其他系統(tǒng)的可重用性就越差。 RPC與基礎(chǔ)系統(tǒng)的緊密耦合不允許在系統(tǒng)功能和外部API之間建立抽象層。 這很容易引起安全問題,因為很容易將有關(guān)基礎(chǔ)系統(tǒng)的實施細(xì)節(jié)泄漏到API中。 RPC的緊密耦合使得可伸縮性要求和松散耦合的團(tuán)隊難以實現(xiàn)。 因此,客戶端要么擔(dān)心調(diào)用特定端點的任何可能的副作用,要么嘗試弄清楚要調(diào)用的端點,因為它不了解服務(wù)器如何命名其功能。
發(fā)現(xiàn)性低。 在RPC中,無法對API進(jìn)行自省或發(fā)送請求,也無法根據(jù)其請求開始理解要調(diào)用的函數(shù)。
功能爆炸。 創(chuàng)建新功能非常容易。 因此,我們不用編輯現(xiàn)有功能,而是創(chuàng)建新功能,最后添加大量難以理解的重疊功能。
RPC用例
RPC模式在80年代左右開始使用,但這并不會自動使其過時。 諸如Google,F(xiàn)acebook(Apache Thrift)和Twitch(Twirp)之類的大公司正在內(nèi)部使用RPC高性能變量來執(zhí)行非常高性能,低開銷的消息傳遞。 他們龐大的微服務(wù)系統(tǒng)要求內(nèi)部通信在安排短消息時保持清晰。
命令A(yù)PI。 RPC是將命令發(fā)送到遠(yuǎn)程系統(tǒng)的正確選擇。 例如,Slack API非常注重命令:加入頻道,離開頻道,發(fā)送消息。 因此,Slack API的設(shè)計人員以類似于RPC的樣式對其進(jìn)行了建模,使其小巧,緊湊且易于使用。
內(nèi)部微服務(wù)的客戶特定API。 由于在單個提供商和使用者之間進(jìn)行了直接集成,我們不想像REST API那樣花費大量時間通過網(wǎng)絡(luò)傳輸大量元數(shù)據(jù)。 憑借高消息速率和消息性能,gRPC和Twirp是微服務(wù)的強(qiáng)大案例。 在后臺使用HTTP 2,gRPC能夠優(yōu)化網(wǎng)絡(luò)層并使其非常高效,每天在不同服務(wù)之間發(fā)送大量消息。 但是,如果您不是要著眼于提高網(wǎng)絡(luò)性能,而是要在發(fā)布高度獨特的微服務(wù)的團(tuán)隊之間建立穩(wěn)定的API聯(lián)系,REST將確保這一點。
簡單對象訪問協(xié)議(SOAP):使數(shù)據(jù)作為服務(wù)可用
SOAP是XML格式的高度標(biāo)準(zhǔn)化的Web通信協(xié)議。 SOAP在Microsoft于XML-RPC發(fā)行一年后發(fā)布,從中繼承了很多東西。 當(dāng)REST緊隨其后時,它們首次并行使用,但很快REST贏得了流行度競賽。
SOAP如何工作
XML數(shù)據(jù)格式拖累了許多形式。 配合龐大的消息結(jié)構(gòu),它使SOAP成為最冗長的API樣式。
SOAP消息包括:
· 包含請求或響應(yīng)的正文
· 標(biāo)頭(如果消息必須確定任何具體要求或額外要求),以及
· 故障通知在整個請求處理過程中可能發(fā)生的任何錯誤。
> An example of the SOAP message. Source: IBM
SOAP API邏輯以Web服務(wù)描述語言(WSDL)編寫。 該API描述語言定義了端點并描述了可以執(zhí)行的所有過程。 這允許不同的編程語言和IDE快速建立通信。
SOAP支持有狀態(tài)和無狀態(tài)消息傳遞。 在有狀態(tài)的情況下,服務(wù)器存儲接收到的信息可能非常重。 但這對于涉及多方和復(fù)雜交易的操作是合理的。
SOAP優(yōu)點
與語言和平臺無關(guān)。 創(chuàng)建基于Web的服務(wù)的內(nèi)置功能允許SOAP處理通信并做出與語言和平臺無關(guān)的響應(yīng)。
綁定到各種傳輸協(xié)議。 SOAP在傳輸協(xié)議方面很靈活,可以適應(yīng)多種情況。
內(nèi)置錯誤處理。 SOAP API規(guī)范允許返回帶有錯誤代碼及其說明的Retry XML消息。
許多安全擴(kuò)展。 SOAP與WS-Security協(xié)議集成,可滿足企業(yè)級事務(wù)質(zhì)量。 它在事務(wù)內(nèi)部提供隱私和完整性,同時允許在消息級別進(jìn)行加密。
> SOAP message-level security: authentication data in the header element and encrypted body
SOAP缺點
如今,由于多種原因,許多開發(fā)人員對必須集成SOAP API的想法感到不安。
僅XML。 SOAP消息包含大量元數(shù)據(jù),并且僅支持請求和響應(yīng)的詳細(xì)XML結(jié)構(gòu)。
重量級的。 由于XML文件的大小,SOAP服務(wù)需要很大的帶寬。
狹義的知識。 構(gòu)建SOAP API服務(wù)器需要深入了解所有涉及的協(xié)議及其嚴(yán)格的規(guī)則。
乏味的消息更新。 需要額外的努力來添加或刪除消息屬性,嚴(yán)格的SOAP模式會減慢采用速度。
SOAP用例
目前,SOAP體系結(jié)構(gòu)最常用于企業(yè)內(nèi)部或與其信任的合作伙伴的內(nèi)部集成。
高度安全的數(shù)據(jù)傳輸。 SOAP的嚴(yán)格結(jié)構(gòu),安全性和授權(quán)功能使其成為執(zhí)行API與客戶端之間的正式軟件合同,同時又遵守API提供者與API使用者之間的合法合同的最合適的選擇。 這就是為什么金融組織和其他公司用戶選擇SOAP的原因。
REST:使數(shù)據(jù)可用作資源
REST是一種不言自明的API架構(gòu)樣式,由一組架構(gòu)約束定義,旨在供許多API使用者廣泛采用。
當(dāng)今最常見的API樣式最初是由Roy Fielding于2000年在其博士論文中描述的。 REST使服務(wù)器端數(shù)據(jù)可用,以簡單格式(通常為JSON和XML)表示它。
REST如何工作
REST的定義不像SOAP那樣嚴(yán)格。 RESTful體系結(jié)構(gòu)應(yīng)遵守六個體系結(jié)構(gòu)約束:
· 統(tǒng)一接口:無論設(shè)備或應(yīng)用程序類型如何,都可以采用統(tǒng)一的方式與給定服務(wù)器進(jìn)行交互
· 無狀態(tài):處理請求本身所包含的請求的必要狀態(tài),并且服務(wù)器不存儲與會話相關(guān)的任何內(nèi)容
· 快取
· 客戶端-服務(wù)器體系結(jié)構(gòu):允許雙方的獨立發(fā)展
· 應(yīng)用程序的分層系統(tǒng)
· 服務(wù)器向客戶端提供可執(zhí)行代碼的能力
實際上,某些服務(wù)僅在一定程度上是RESTful的。 它們以RPC樣式為核心,將較大的服務(wù)分解為資源,并有效地使用HTTP基礎(chǔ)結(jié)構(gòu)。 但是關(guān)鍵部分是使用超媒體(又稱HATEOAS),是超文本作為應(yīng)用程序狀態(tài)引擎的縮寫。 基本上,這意味著REST API在每個響應(yīng)中都提供元數(shù)據(jù)鏈接,該元數(shù)據(jù)鏈接到有關(guān)如何使用該API的所有相關(guān)信息。 這樣便可以使客戶端和服務(wù)器脫鉤。 結(jié)果,API提供者和API使用者都可以獨立發(fā)展,而不會阻礙他們的交流。
> Richardson Maturity Model as a goalpost to achieving truly complete and useful APIs, Source: Krist
" HATEOAS是REST的關(guān)鍵功能。 真正使REST成為REST的原因。 由于大多數(shù)人不使用HATEOAS,因此實際上是在使用HTTP RPC,"這是Reddit上表達(dá)的一些激進(jìn)觀點。 實際上,HATEOAS是REST的最成熟版本。 但是,要實現(xiàn)比當(dāng)今通常使用和構(gòu)建的API客戶端更為先進(jìn)和智能的API客戶端要困難得多。 因此,即使是當(dāng)今非常好的REST API也不一定總是做到這一點。 這就是為什么HATEOAS主要用作RESTful API設(shè)計的長期開發(fā)的愿景。
當(dāng)服務(wù)實現(xiàn)REST的某些功能和RPC的某些功能時,在REST和RPC之間確實可能存在一個灰色區(qū)域。 REST基于資源或名詞,而不是基于動作或動詞。
> Opposing operations in verb-centric RPC to the ones in noun-centric REST
在REST中,使用GET,POST,PUT,DELETE,OPTIONS和PATCH等HTTP方法完成操作。
> Source: Thomas Davis
REST的優(yōu)點
客戶端和服務(wù)器解耦。 REST盡可能使客戶端和服務(wù)器脫鉤,與RPC相比,REST可以提供更好的抽象性。 具有抽象級別的系統(tǒng)能夠封裝其詳細(xì)信息,以更好地標(biāo)識和維持其屬性。 這使得REST API足夠靈活,可以隨著時間的推移而發(fā)展,同時保持穩(wěn)定的系統(tǒng)。
可發(fā)現(xiàn)性。 客戶端與服務(wù)器之間的通信描述了所有內(nèi)容,因此不需要外部文檔即可了解如何與REST API進(jìn)行交互。
緩存友好。 REST重用了許多HTTP工具,是唯一一種可以在HTTP級別上緩存數(shù)據(jù)的樣式。 相反,在任何其他API上進(jìn)行緩存實現(xiàn)將需要配置其他緩存模塊。
多種格式支持。 支持多種格式用于存儲和交換數(shù)據(jù)的能力是REST當(dāng)前成為構(gòu)建公共API的主要選擇的原因之一。
REST缺點:
沒有單一的REST結(jié)構(gòu)。 沒有建立REST API的正確方法。 如何對資源進(jìn)行建模以及要對哪些資源進(jìn)行建模將取決于每種情況。 這使得REST在理論上很簡單,但在實踐中卻很困難。
大負(fù)載。 REST返回很多豐富的元數(shù)據(jù),以便客戶端可以僅從響應(yīng)中了解有關(guān)應(yīng)用程序狀態(tài)的所有必要信息。 對于具有大量帶寬容量的大型網(wǎng)絡(luò)管道而言,這種聊天狀態(tài)并不重要。 但這并非總是如此。 這是Facebook在2012年提出GraphQL樣式的關(guān)鍵驅(qū)動因素。
過度獲取和不足獲取問題。 REST響應(yīng)包含的數(shù)據(jù)過多或不足,通常會導(dǎo)致需要另一個請求。
REST用例
管理API。 專注于管理系統(tǒng)中對象并面向許多使用者的API是最常見的API類型。 REST幫助此類API具有強(qiáng)大的可發(fā)現(xiàn)性,良好的文檔編制,并且非常適合此對象模型。
簡單的資源驅(qū)動型應(yīng)用程序。 REST是一種非常有用的方法,用于連接不需要查詢靈活性的資源驅(qū)動型應(yīng)用。
GraphQL:僅查詢所需的數(shù)據(jù)
它需要多次調(diào)用REST API才能返回所需的人員。 因此,GraphQL被發(fā)明為改變游戲規(guī)則的人。
GraphQL是一種語法,描述了如何進(jìn)行精確的數(shù)據(jù)請求。 對于具有許多相互引用的復(fù)雜實體的應(yīng)用程序數(shù)據(jù)模型而言,實現(xiàn)GraphQL是值得的。
> How to retrieve only the needed data from the GraphQL endpoint, Source: Mohit Tikoo
如今,GraphQL生態(tài)系統(tǒng)正在通過庫和強(qiáng)大的工具(如Apollo,GraphiQL和GraphQL Explorer)進(jìn)行擴(kuò)展。
GraphQL如何工作
GraphQL從構(gòu)建模式開始,該模式是對您可以在GraphQL API中進(jìn)行的所有查詢及其返回的所有類型的描述。 模式構(gòu)建非常困難,因為它需要使用模式定義語言(SDL)進(jìn)行強(qiáng)類型化。
在查詢之前具有架構(gòu),客戶端可以驗證其查詢,以確保服務(wù)器能夠?qū)ζ溥M(jìn)行響應(yīng)。 在到達(dá)后端應(yīng)用程序時,將針對整個模式解釋GraphQL操作,并使用前端應(yīng)用程序的數(shù)據(jù)進(jìn)行解析。 該API向服務(wù)器發(fā)送一個龐大的查詢后,會返回一個JSON響應(yīng),其中包含我們所需數(shù)據(jù)的確切形狀。
> Query execution in GraphQL, Source: Jonas Helfer
除了RESTful CRUD操作之外,GraphQL的訂閱還允許來自服務(wù)器的實時通知。
GraphQL的優(yōu)點
鍵入的架構(gòu)。 GraphQL會提前發(fā)布其功能,從而提高其可發(fā)現(xiàn)性。 通過將客戶端指向GraphQL API,我們可以找出可用的查詢。
非常適合類似圖形的數(shù)據(jù)。 數(shù)據(jù)關(guān)系很深,但不適合平面數(shù)據(jù)。
沒有版本控制。 版本控制的最佳做法是根本不對API進(jìn)行版本控制。
REST提供了多個API版本,而GraphQL使用的是一個不斷發(fā)展的版本,它可以持續(xù)訪問新功能,并有助于提供更清潔,更可維護(hù)的服務(wù)器代碼。
詳細(xì)的錯誤消息。 GraphQL以類似于SOAP的方式提供發(fā)生錯誤的詳細(xì)信息。 它的錯誤消息包括所有解析器,并引用發(fā)生故障時的確切查詢部分。
靈活的權(quán)限。 GraphQL允許選擇性地公開某些功能,同時保留私人信息。 同時,REST體系結(jié)構(gòu)不會部分顯示數(shù)據(jù)。 全部或全無。
GraphQL的缺點
性能問題。 GraphQL權(quán)衡了復(fù)雜性。 一個請求中的嵌套字段太多會導(dǎo)致系統(tǒng)過載。 因此,對于復(fù)雜的查詢,REST仍然是更好的選擇。
緩存復(fù)雜度。 由于GraphQL不再使用HTTP緩存語義,因此需要自定義緩存工作。
很多預(yù)開發(fā)教育。 由于沒有足夠的時間來了解GraphQL利基操作和SDL,因此許多項目決定采用眾所周知的REST路徑。
GraphQL用例
移動API。 在這種情況下,網(wǎng)絡(luò)性能和單個消息有效負(fù)載優(yōu)化很重要。 因此,GraphQL為移動設(shè)備提供了更有效的數(shù)據(jù)加載。
復(fù)雜的系統(tǒng)和微服務(wù)。 GraphQL能夠隱藏其API背后的多個系統(tǒng)集成的復(fù)雜性。 從多個位置聚合數(shù)據(jù),它將它們合并為一個全局模式。 這對于隨時間推移而擴(kuò)展的舊式基礎(chǔ)結(jié)構(gòu)或第三方API尤其重要。
哪種API模式最適合您的場景?
每個API項目都有不同的要求和需求。 通常,架構(gòu)選擇取決于
· 使用的編程語言
· 您正在開發(fā)的環(huán)境,以及
· 您必須保留的人力和財力資源。
知道了每種設(shè)計風(fēng)格的所有權(quán)衡之后,API設(shè)計人員可以選擇最適合該項目的一種。
由于RPC緊密耦合,因此可用于內(nèi)部微服務(wù),但對于強(qiáng)大的外部API或API服務(wù)而言,它不是一種選擇。
SOAP很麻煩,但是其豐富的安全功能對于計費操作,預(yù)訂系統(tǒng)和付款仍然是不可替代的。
REST具有API的最高抽象度和最佳建模。 但是在網(wǎng)絡(luò)和聊天環(huán)境中,這往往會比較沉重-如果您正在使用移動設(shè)備,這將是不利的一面。
GraphQL在數(shù)據(jù)獲取方面邁出了一大步,但并不是每個人都有足夠的時間和精力來掌握它。
歸根結(jié)底,嘗試一些具有特定樣式的小型用例,并查看它是否適合您的用例并解決您的問題是有意義的。 如果可以,請嘗試擴(kuò)展并查看它是否適合更多用例。
最初發(fā)布于AltexSoft技術(shù)博客"比較API體系結(jié)構(gòu)樣式:SOAP vs REST vs GraphQL vs RPC"
(本文翻譯自Sanjeet Chatterjee的文章《Comparing API Architectural Styles: SOAP vs REST vs GraphQL vs RPC》,參考:https://levelup.gitconnected.com/comparing-api-architectural-styles-soap-vs-rest-vs-graphql-vs-rpc-84a3720adefa)






