2020年的REST和超媒體

時下隨著架構解耦和微服務架構的興起,每一個開發者都不可避免要用到REST構建API和用REST交互。然而我們真正瞭解並善用了當代REST和超媒體的好處麼?本文就和大家一起學習了,2020年的REST和超媒體。

2020年的REST和超媒體

概述

REST被認為是一堆抽象層,可幫助減少與客戶端開發人員的交流,同時使能夠構建更堅固和一致的應用程序。

這可以通過幾種方式來實現,主要是依靠REST API存在的協議的現有語義,通常是HTTP。在HTTP中構建REST API就要遵循現有的HTTP語義來實現REST提出要實現的概念,而不是發明自己的約定。

客戶端可以查詢Retry-After標頭,而不是編寫一堆代碼來了解API可能會響應的每個應用程序錯誤,並自己處理錯誤的代碼。

開發者抱怨REST很難,因為必須要了解HTTP方法及其含義以及不同的狀態代碼。雖然學習HTTP可能需要一些時間,但HTTP的約定與龐大的工具生態系統共享。

開發者一致對這些技術很排斥,很多時候他們更喜歡RPC。對於許多開發人員來說,可以在互聯網上運行這些API就足矣,他們可以在上面自己添加操作和約定,這樣他們雖然也獲得了一些需要的功能CRUD(POST, GET, PUT, DELETE = Create, Read, Update, Delete)增刪改查,並丟了REST架構可以提供的大量的好處。

"REST是RPC之上的一堆抽象層"嗎?

Richardson的成熟度模型結構圖示如下:

2020年的REST和超媒體


這是Martin Fowler在介紹《Richardson成熟度模型》的文章的總結圖示。該模型以Leonard Richardson的名字命名,討論API的成熟度。

該圖有一些常見的問題,主要是頂部是" Glory of REST",底部亂成一團。不幸的是,這使REST API看起來像是個迷宮,而其他所有事物都很亂的。

REST的帶來好處是很明顯的:

網絡上的所有事物都可被抽象為資源(Unify);

每個資源都有統一唯一的資源標識符(URI);

使用標準方法操作資源;

所有的操作都是無狀態的;

可以通過緩存來提高性能。

2020年的REST和超媒體

另一個問題是Martin談論的是Plain Old XML,如今,有些人談論的是POJO(Plain old JSON Objects)。

所有API開發人員都可以使用API規範(用於描述數據模型的元數據),無論他們的範例或選擇的實現方式如何,因此都應將其考慮在內。REST人員使用JSON Schema,gRPC人員使用Protobuf,而GraphQL用戶具有GraphQL類型。

改進Richardson成熟度模型

我們對上面提到的Richardson成熟度模型進行改進,每層簡要地提到了它啟用的一些功能。

2020年的REST和超媒體

RPC

真正遇到的問題是,最基本形式的RPC通常會忽略許多HTTP概念。它不會使用HTTP的統一接口及其完整語義,也不使用HTTP作為傳輸協議,而僅使用傳輸方面。傳輸協議可以幫助您知道何時或是否需要發出請求,而不僅僅是在網絡上傳送數據。大多數RPC實現都與單個端點交互,並且大多數交互都使用單個HTTP方法。很少有通用的HTTP約定只能用於最基本的RPC。

如果RPC遵循特定標準,則可以使用為該標準構建的工具,但是通用HTTP約定不適用。

資源

這裡有兩個常見的困惑,首先這不是關於擁有/bikes, /bikes/abc123而是經常使用的標準集合,複數和資源CRUD模式。

從技術上講,資源與端點是一樣的東西,但是有一個故意的區別。端點通常被認為更像是函數,其目的是在想做某事時調用一個函數,但這又是傳輸的大多數傳輸方式,通常是RPC思維的標誌:調用某事並執行一個事情。

資源更像是標識符,它是在特定位置的唯一事物,可以被該事物識別。它是HTTP世界中最終的唯一標識符,儘管可能會有具有相同字母/數字ID的不同產品,也有可能UUID也會衝突。

URI(統一資源標識符)是擁有適用於所有內容的唯一。這樣我們可以將特定的標頭添加到不同的資源中,這些標頭可以與響應一起作為元數據存儲。

這樣資源可以聲明自己的可緩存性,這是REST談論的重要內容之一。

緩存約束要求對請求的響應中的數據被隱式或顯式標記為可緩存或不可緩存。如果響應是可緩存的,則授予客戶端緩存以將響應數據重新用於以後的等效請求的權限。

添加緩存約束的優勢是可以部分或完全消除某些交互,從而通過減少一系列交互的平均延遲來提高效率,提高系統的可伸縮性和用戶感知的性能。

HTTP/1.1中緩存的目標是通過重用先前的響應消息來滿足當前請求,從而顯著提高性能。如果可以在沒有"驗證"的情況下重用響應,則存儲的響應被視為"新鮮的"(與原始服務器進行檢查,以瞭解緩存的響應是否對該請求仍然有效)。因此,每次重新使用響應時,新響應都可以減少延遲和網絡開銷。當緩存的響應不"新鮮"時,如果可以通過驗證將其刷新或原始不可用,則該響應可以重用。

如果具有唯一的URI,則在HTTP/2中也無痛升級使用。

HTTP方法

方法為請求中發生的事情的類型添加了許多重要的語義。如果使用了緩存,則緩存組件將知道它可以緩存GET請求,但是如果對同一個資源執行POST或DELETE操作,它將知道它應該避開它。

像自動重試這樣的客戶端邏輯現在成為可能。當API花費很長時間進行響應時,重試可以提供幫助,客戶端應用程序可能會針對請求進行保釋,然後重試。使用GET幾乎沒有什麼缺點,它是冪等請求,不應具有任何破壞性動作。

重試POST可能很危險,因為可能在達到超時之前,它可能會更改數據庫中的某些記錄,發送一些電子郵件,從信用卡中收取費用等。

PUT和PATCH會很好,PUT也是冪等的,只會消除結果,並且PATCH通常具有"from"和"to",這意味著如果第二次發出請求,則"from"可能會不匹配。

對RPC的忠實擁護者,!gRPC"HTTP橋"添加了這兩個抽象層,使其更加像HTTPish。

超媒體控件

超媒體控件是"超媒體作為應用程序狀態引擎"(HATEOAS)的簡寫,它是一個非常簡單的概念。API不僅僅是HTTP上的數據存儲,而是成為HTTP上的狀態機。它仍然有數據,但是它也可以以自我描述的方式提供"下一個可用動作"。

考慮一張發票,說它是可付款的,而不是需要根據缺少來確定是否可以付款paid_date,或者可能有status: pending,但是可能會添加新的狀態並等待處理並不意味著可以付款。客戶應用程序中斷或需要版本控制,這兩者都會浪費開發人員時間和公司資金。

如果發票是應付賬款,則會顯示一個名為"付款"的鏈接,這表示客戶端應用程序知道何時付款,並且只要使用了良好的超媒體格式,客戶端應用程序就會知道如何付款,因為控件可以向服務器發送HTTP請求之前驗證數據客戶端,給出哪些數據是必須要提供的。

超媒體的最基本層次是將鏈接推到響應主體中,但是客戶端必須做很多驗證工作才能弄清楚下一步該做什麼。此前,只會是:"你有一個URL和一個鏈接關係,這是一個很好的開始",但是如今,有很多流行的Hypermedia Formats使這一切變得容易得多。

REST

大多數自稱為REST的API都沒有最後一層,這意味著它們使用的僅僅是RESTish,或者僅僅是HTTP API。因為沒有超媒體控件,就不能叫REST API,這很重要。

可能開發人員根本不知道HATEOAS(超媒體即應用狀態引擎或超媒體約束)是什麼。還有一些人知道,但是認為HATEOAS就是要強迫進行HTTP請求負載以獲取相同數量的數據。這時他們考慮的是傳輸而不是轉移,到了時下快要普及的HTTP/2,即使需要進行"更多調用",性能影響也可以忽略不計。

即使到了REST這一層,也不意味著API會在所有方面都永遠可靠且完美。粗劣的資源設計會使任何API都難以使用,不論你使用的是哪種範例。GraphQL開發人員現在開始注意到這一點 。

專注於滿足客戶需求的模型設計非常重要,API會隨著時間的推移而發展,修剪掉無用的數據,並創建複合資源以最大程度地減少不必要的網絡延誤。JSON Schema也剛剛棄用了一個關鍵字,這可以使API的開發變得更加容易。

超媒體和gRPC或GraphQL

在談論超媒體控件時,常有這樣的觀點,比如 "這不僅是REST可以做的事情,如果使用HTTP Bridge並添加了鏈接,gRPC可以做到這一點!"

一段時間以來,著名的GraphQL開發人員一直在嘗試找到一種將超媒體控件引入GraphQL的方法。如果他們能解決這個問題,GraphQL不會準確地遵循下面這個圖,但我們可以調用query和mutation他們分享有或沒有語義足夠靠近HTTP方法和唯一缺少的是資源(URI)來。

對於GraphQL,缺少URI是一個更大的問題,這幾乎破壞了他們直接使用HTTP/2 Server Push的機會,他們不需要向供應商尋求特定的解決方案,例如Apollo訂閱和其他非標準@defer類型的東西。

總結

無論如何,API並不總是需要超媒體控件。例如,全棧開發人員經常認為REST浪費時間,因為他們只是想要查詢數據庫並將信息傳遞到表示層。他們不需要將緩存控件附加到消息本身中,他們只需要在客戶端應用程序中設置緩存即可,該客戶端應用程序可能在其計算機上的另一個窗口中打開。他們知道何時使用重試,因為他們編寫了應用程序代碼並知道它們的含義,因此他們不在乎是否使用了HTTP語義。這些開發人員與試圖向可能位於不同樓層或不同大陸的各種客戶團隊提供一致功能的開發人員完全沒有共同之處,在這些客戶團隊中,傳達變更或如何推斷狀態可能是一個代價高昂的問題。這些團隊可能正在使用各種網絡和客戶端工具,例如緩存中間件,服務監控,代理檢查,並且不能限制他們可以使用的工具,因為這可能會使他們丟掉業務。

兩者之間還有其他所有完全有效的方案。並不是所有的汽車都需要防彈玻璃,並非所有的對話都要有麥克風,不是所有的內衣都需要有吊帶。同理,也不是所有的API都需要是REST。


分享到:


相關文章: