咱們知道,兩個單獨的應用程序須要中介程序才能相互通訊。所以,開發人員一般會搭建橋樑(應用程序編程接口),以容許一個系統訪問另外一個系統的信息或功能。前端
爲了快速、大規模地集成應用程序,API是使用協議或規範實現的,這些協議或規範定義了經過網絡傳遞的消息的語義和語法。這些規範組成了API體系結構。編程
隨着時間的推移,不一樣的API架構風格已經發布。 每一種都有本身的標準化數據交換模式,選擇的豐富引起了關於哪一種架構風格是最好的無休止的爭論。後端
今天,許多API消費者稱REST爲「安息」,併爲GraphQL歡呼,而十年前則相反,REST是取代SOAP的贏家。這些觀點的問題在於,他們是片面地選擇一種技術自己,而不是考慮它的實際屬性和特性如何與當前的狀況相匹配。緩存
在本文中,咱們將保持客觀的態度,討論四大API風格的出場順序,比較它們的強弱面,並強調它們各自最適合的場景。安全
遠程過程調用是一種規範,它容許在不一樣的上下文中遠程執行一個函數。RPC擴展了本地過程調用的概念,但將其放在HTTP API的上下文中。服務器
最初的XML-RPC存在問題,由於確保XML有效載荷的數據類型很是困難。因此,後來一個RPC API開始使用更具體的JSON-RPC規範,它被認爲是比SOAP更簡單的替代品。 gRPC是Google在2015年開發的最新RPC版本,gRPC對負載均衡、跟蹤、健康檢查和認證的支持可插拔,很是適合鏈接微服務。網絡
客戶端調用一個遠程過程,將參數和附加信息序列化爲消息,並將消息發送到服務器。服務器在收到消息後,對其內容進行反序列化,執行請求的操做,並將結果發回給客戶端。服務器存根和客戶端存根負責參數的序列化和反序列化。架構
簡單直接的互動。 RPC使用GET來獲取信息,並使用POST進行其餘全部操做。服務器和客戶端之間的交互機制歸根結底是調用一個端點並得到響應。負載均衡
易於添加的功能。 若是咱們對API有了新的需求,咱們能夠很容易地添加另外一個端點來執行這個需求:編程語言
高性能。 在提供高性能的網絡上,輕量級有效載荷很容易實現,這對於共享服務器和在工做站網絡上執行的並行計算很是重要。RPC可以優化網絡層,天天在不一樣服務之間發送大量的消息,效率很是高。
與底層系統緊密耦合。一個API的抽象層次有助於其可重用性。它與底層系統的關係越緊密,對其餘系統的可重用性就越低。 RPC與底層系統的緊密耦合,不容許在系統中的函數和外部API之間創建抽象層,這就引起了安全問題,由於很容易將底層系統的實現細節泄露到API中。RPC的緊密耦合使得可擴展性要求和鬆散耦合的團隊很難實現,所以,客戶端要麼擔憂調用特定端點的任何可能的反作用,要麼試圖弄清楚調用哪一個端點,由於它不理解服務器是如何命名其函數的。
發現性低。在RPC中,沒法內省API或發送請求,也沒法根據請求理解調用什麼函數。
函數爆炸。建立新函數很容易。所以,咱們不是編輯現有的函數,而是建立新的函數,並以一大堆難以理解的重疊函數結束。
RPC模式大約在80年代開始使用,但這並不會自動使其過期。像Google、Facebook (Apache Thrift)和Twitch (Twirp)這樣的大公司在內部使用RPC高性能變體來執行高性能、低開銷的消息傳遞。他們龐大的微服務系統要求內部通訊在安排短消息時要清晰。
指令API。 RPC是向遠程系統發送指令的正確選擇。 例如,Slack的API是很是注重指令的,加入一個頻道,離開一個頻道,發送一條消息。因此,Slack API的設計者將其建模爲相似RPC的風格,使其小巧、緊密、易於使用。
內部微服務的客戶特定API。 經過在單個提供者和消費者之間進行直接集成,咱們不但願像REST API那樣,花費大量時間在網絡上傳輸大量元數據。gRPC和Twirp具備較高的消息速率和消息性能,是微服務的有力案例。在HTTP 2的支持下,gRPC可以優化網絡層,天天在不一樣服務之間發送大量的消息,效率很是高。可是,若是您的目標不是高網絡性能,而是發佈高度獨特微服務的團隊之間的穩定API聯繫,REST將確保這一點。
SOAP是一種XML格式的、高度標準化的網絡通訊協議。 SOAP在Microsoft於XML-RPC發行一年後發佈,從中繼承了不少東西。 當REST緊隨其後時,它們首次並行使用,但很快REST贏得了流行度競賽。
XML數據格式背後拖着不少形式化的東西,配合龐大的消息結構,使得SOAP成爲最囉嗦的API風格。
SOAP消息包括:
SOAP API邏輯是用Web服務描述語言(WSDL)編寫的。這種API描述語言定義了端點,描述了全部能夠執行的過程,這使得不一樣的編程語言和IDE能夠快速創建通訊。
SOAP支持有狀態和無狀態消息傳遞。在有狀態的狀況下,服務器存儲接收到的信息可能很是繁重。但這對於涉及多方和複雜交易的操做是合理的。
與語言和平臺無關。建立基於Web的服務的內置功能容許SOAP處理通訊並作出與語言和平臺無關的響應。
綁定到各類傳輸協議。SOAP在傳輸協議方面很靈活,能夠適應多種狀況。
內置錯誤處理。SOAP API規範容許返回帶有錯誤代碼和解釋的重試XML消息。
許多安全擴展。與WS-Security協議集成後,SOAP能夠知足企業級的事務質量。它提供了交易內部的隱私和完整性,同時容許在消息層面進行加密。
現在,因爲多種緣由,許多開發人員對必須集成SOAP API的想法感到不安。
僅XML。 SOAP消息包含大量元數據,而且僅支持請求和響應的詳細XML結構。
重量級的。 因爲XML文件的大小,SOAP服務須要很大的帶寬。
狹義的專業知識。構建SOAP API服務器須要深刻了解所涉及的全部協議及其高度限制的規則。
乏味的消息更新。 須要額外的努力來添加或刪除消息屬性,嚴格的SOAP模式會減慢採用速度。
目前,SOAP架構最多見的是用於企業內部或與其信任的合做夥伴的集成。
高度安全的數據傳輸。SOAP嚴格的結構、安全和受權能力使它成爲在API和客戶端之間執行正式軟件契約的最合適的選擇,同時遵照API提供者和API消費者之間的合法契約。這就是爲何金融組織和其餘企業用戶選擇SOAP的緣由。
REST是一種由一組架構約束定義的自解釋API架構風格,旨在爲許多API消費者普遍採用。
今天最多見的API風格最初是由Roy Fielding在2000年的博士論文中描述的。REST使服務器端數據可用簡單的格式表示,一般是JSON和XML。
REST並不像SOAP那樣嚴格定義,RESTful架構應該遵照六個架構約束。
事實上,有些服務只是在必定程度上是RESTful的。它們以RPC風格爲核心,將較大的服務分解爲資源,並有效地使用HTTP基礎設施。但關鍵部分是使用超媒體又名HATEOAS,即Hypertext As The Engine of Application State的縮寫。基本上,這意味着每個響應,REST API都會提供元數據,連接到全部關於如何使用API的相關信息。這就是實現客戶端和服務器解耦的緣由。所以,API提供者和API消費者均可以獨立發展而不妨礙他們的交流。
「HATEOAS是REST的一個關鍵特性。它是真正的REST REST的緣由。由於大多數人沒有使用HATEOAS,他們其實是在使用HTTP RPC。」這是Reddit上表達的一些激進意見。事實上,HATEOAS是REST最成熟的版本。然而,要實現這一目標,須要比目前一般使用和構建的API客戶端先進得多的智能API是很困難的。因此,現在即便是很是好的REST API也不必定能作到。這也是爲何HATEOAS主要做爲RESTful API設計的長期發展願景。
當一個服務實現了REST的一些功能和RPC的一些功能時,REST和RPC之間確實可能存在一個灰色地帶。REST是基於資源或名詞,而不是基於動做或動詞。
在REST中,使用HTTP方法,如GET、POST、PUT、DELETE、OPTIONS,以及但願的PATCH,來完成事情。
解耦客戶端和服務器。儘量地將客戶端和服務器解耦,REST能夠實現比RPC更好的抽象。一個具備抽象層次的系統,可以對其細節進行封裝,以更好地識別和維持其屬性。這使得REST API具備足夠的靈活性,能夠隨着時間的推移而發展,同時保持一個穩定的系統。
可發現性。客戶端和服務器之間的通訊描述了一切,所以不須要外部文檔就能理解如何與REST API交互。
緩存友好。重用了不少HTTP工具,REST是惟一容許在HTTP層面上緩存數據的風格。相比之下,在任何其餘API上實現緩存都須要配置一個額外的緩存模塊。
支持多種格式。支持多種格式存儲和交換數據的能力是目前REST成爲構建公共API的主流選擇的緣由之一。
沒有單獨的REST結構。構建REST API沒有確切的正確方法。如何對資源進行建模,對哪些資源進行建模,將取決於每一個場景。這使得REST在理論上很簡單,但在實踐中卻很難。
大載荷。REST會返回不少豐富的元數據,這樣客戶端就能夠僅僅從它的響應中瞭解應用狀態的一切必要信息。對於一個擁有大量帶寬容量的大型網絡管道來講,這種豐富的元數據並非什麼大問題。但狀況並不老是這樣,這是Facebook在2012年推出GraphQL風格描述的關鍵驅動因素。
過分獲取和獲取不足問題。REST響應包含的數據要麼太多,要麼不夠,常常會產生對另外一個請求的需求。
管理API。最多見的API類型是專一於管理系統中的對象並面向許多使用者的API。REST使此類API具備強大的可發現性和良好的文檔,而且很是適合這種對象模型。
簡單的資源驅動型應用程序。REST是鏈接不須要靈活查詢的資源驅動型應用的寶貴方法。
要調用REST API屢次才能返回所需信息,因此GraphQL的發明是爲了改變遊戲規則。
GraphQL是一種描述如何進行精確數據請求的語法。對於具備大量相互引用的複雜實體的應用程序數據模型來講,實現GraphQL是值得的。
現在,GraphQL的生態系統正在經過Apollo、GraphiQL和GraphQL Explorer等庫和強大的工具進行擴展。
GraphQL從構建一個模式開始,它是對你在GraphQL API中可能進行的全部查詢以及它們返回的全部類型的描述。構建模式很困難,由於它須要在模式定義語言(SDL)中使用強類型。
在查詢以前有了模式,客戶能夠根據模式來驗證他們的查詢,以確保服務器可以響應它。在到達後端應用時,GraphQL操做會針對整個模式進行解釋,並與前端應用的數據進行解析。API向服務器發送一個大型查詢,返回一個JSON響應,其中包含咱們請求的數據的確切形狀。
除了RESTful CRUD操做外,GraphQL還有訂閱功能,能夠從服務器上得到實時通知。
類型化的模式。GraphQL提早公佈了它能作的事情,這提升了它的可發現性,經過將客戶端指向GraphQL API,咱們能夠發現有哪些查詢。
能很好地適應圖形類數據。數據關係很深,但不適合平面數據。
沒有版本控制。版本化的最佳實踐是徹底不對API進行版本化。
雖然REST提供了多個API版本,但GraphQL使用的是一個單一的、不斷髮展的版本,能夠持續地訪問新的功能,並有助於更乾淨、更可維護的服務器代碼。
詳細的錯誤消息。與SOAP相似,GraphQL提供了發生錯誤的細節。它的錯誤信息包括了全部的解析器,並提到了出錯的具體查詢部分。
靈活的權限。GraphQL容許有選擇地暴露某些功能,同時保留私人信息。同時,REST架構並不顯示數據的部分。要麼全有,要麼全無。
性能問題。GraphQL以複雜度換取其強大的功能。在一個請求中擁有過多的嵌套字段會致使系統過載。因此,對於複雜的查詢,REST仍然是一個更好的選擇。
緩存複雜。因爲GraphQL並無重用HTTP緩存語義,因此須要進行自定義緩存工做。
大量的開發前教育。因爲沒有足夠的時間來了解GraphQL的小衆操做和SDL,許多項目決定採用衆所周知的REST方法。
移動設備API。在這種狀況下,網絡性能和單條消息的有效載荷優化是很重要的。因此,GraphQL爲移動設備提供了更高效的數據加載。
複雜的系統和微服務。GraphQL可以將多個系統集成的複雜性隱藏在其API背後。它從多個地方聚合數據,而後將它們合併到一個全局模式中。這對於傳統的基礎設施或隨着時間的推移而擴展的第三方API來講,尤爲重要。
每一個API項目都有不一樣的要求和需求。一般狀況下,架構的選擇取決於:
瞭解每一種設計風格的全部權衡,API設計師就能夠選擇最適合項目的那一種。
憑藉其緊密的耦合性,RPC適用於內部微服務,但對於強大的外部API或API服務來講,它不是一個好選擇。
SOAP雖然麻煩,但其豐富的安全功能對於計費業務、預訂系統和支付來講,仍然是不可替代的。
REST具備API的最高抽象和最佳建模。但這每每會增長在線和聊天的負擔——若是您使用的是移動設備,這是不利的一面。
GraphQL是數據獲取方面的一大進步,但並非每一個人都有足夠的時間和精力去掌握它。
在一天結束的時候,用一個特定的風格嘗試幾個小的用例是有意義的,看看它是否適合你的用例並解決你的問題。若是確實如此,就嘗試擴展,看看它是否適合更多的用例。