RESTful API教程:學習關鍵的Web服務設計原則

RESTful API教程:學習關鍵的Web服務設計原則

摘要:

簡單原則更利於掌握和實踐:有意義的、唯一的URL,GET不進行寫操作,PUT和DELETE要具備冪等性以及審慎的使用POST。

作者:Cameron McKenzie

原題:RESTful APIs tutorial: Learn key web service design principles

原文:https://www.theserverside.com/video/A-RESTful-APIs-tutorial-Learn-key-web-service-design-principles

全文2722字,閱讀約需要10分鐘

白小白:

原文地址另附有一個本文的視頻講解,作者語音清晰,風趣幽默(關於冪等這個詞的讀音,作者並不十分確定,並對自己進行了調侃,2333),詳細內容可點擊閱讀原文查看。

用Java創建一個RESTful Web服務不難。事實上,像Spring Boot、Eclipse MicroProfile和Jakarta EE這些工具使得RESTful Java應用程序的開發相對容易。

但是許多RESTful We服務的問題並不在於開發而在於設計。本文將解決這些Web服務的設計問題,並揭示軟件開發者在創建RESTful API時所犯的常見錯誤。

RESTful API的關鍵原則:URL和HTTP方法

在開發RESTful Java API時,設計人員需要考慮兩個關鍵元素:

URL模式

使用哪種HTTP方法

我們強調的第一個重要原則是,資源應該始終通過惟一標識它們的URL訪問。

對於任何使用過Web瀏覽器的用戶來說,這是一個全新的理念。當我們訪問網頁或下載基於Web的PDF文件時,我們將瀏覽器指向標識該資源的URL。同樣的概念也適用於使用RESTful Java Web服務訪問服務器端資源的時候。如果jQuery或Angular客戶端需要操作資源,則應該有一個唯一的URL,該URL使得相關的JavaScript代碼可以標識定位對應的RESTful資源。

有意義的、唯一的RESTful URL示例

我經常使用一個“剪刀-石頭-布”的小應用來對一些軟件開發理念進行原型驗證。在這個應用中,我會寫一個組件來跟蹤輸(losses)贏(wins)和平局(ties)的得分結果。

RESTful API教程:學習關鍵的Web服務設計原則

一個有效的RESTful API允許用戶與得分(score)進行交互,它的設計將包括以下URL:

www.mcnz.com/rps/score

當用戶通過瀏覽器、通過RESTful JavaScript應用程序或通過Spring Boot MVC組件訪問此URL時,他們將得到當前score的描述。RESTful Java API應該以JSON格式返回以下結果:

{ "wins":"5", "losses":"3", "ties": "0"}

如果RESTful JavaScript客戶端只對wins感興趣,URL應該遵循可預測的格式,其中wins是score的子資源:

www.mcnz.com/rps/score/wins → returns { "wins":"5"}

事實上,返回JSON格式的wins可能有點過頭了。只要將wins的數目以文本格式返回即可,所有客戶端都可以輕鬆地使用該結果,而不管它們是否可以解析JSON。因此,最好採取以下措施:

www.mcnz.com/rps/score/wins → returns "5"

looses和ties應該遵循類似的RESTful URL格式:

www.mcnz.com/rps/score/losses → returns "3"

www.mcnz.com/rps/score/ties → returns "0"

正確的RESTful HTTP方法示例

到目前為止,所有RESTful API示例都設定為簡單的GET調用。事實上,對於通過URL與RESTful資源交互來說,HTTP協議提供了許多不同的方法。當接收到一個URL調用時,服務器通常假定它是GET請求。但是,RESTful API設計者至少應該考慮另外三種HTTP方法,即POST、PUT和DELETE。

RESTful設計規則:GET調用不能改變服務器狀態

要處理HTTP方法,需要遵循重要的RESTful設計規則。RESTful Java API設計者如果違反了這些規則,就會誤入歧途。

首要原則是,GET調用永遠不能改變服務器上任何RESTful資源的狀態。上述的RESTful API完全符合該規則。

RESTful PUT和DELETE方法需要遵守冪等原則

雖然並不是一個嚴格的規則,但PUT和DELETE方法大致映射了保存和刪除的概念。如果設計人員想要從服務器中刪除資源,他們應該使用HTTP DELETE方法。如果需要創建新資源或需要更新現有資源,則應使用PUT方法。

PUT和DELETE方法對於保存和刪除數據來說是相對簡單的。但這也是RESTful Java API設計人員經常遇到麻煩的另一個陷阱。這就引出了第二條規則:HTTP方法要具備冪等性。

如果某件事是冪等的,意味著它可以重複進行,但結果總是一樣的。

例如,假設客戶端發出RESTful DELETE請求刪除編號為271的記錄。這個調用可進行一次,也可能進行100次。無論如何,最終的結果必須是一樣的,即編號271的壽終正寢。下面的場景就是冪等的。

HTTP DELETE || www.mcnz.com/rps/score?record=271 #Good RESTful Java design

反例是,刪除數據庫中最老的10條記錄的請求。

HTTP DELETE || www.mcnz.com/rps/score?oldRecordsToDelete=10 #Bad RESTful Java design

在反例中,RESTful URL將使數據庫在每次新調用時處於不同的狀態,直至刪除數據庫中的每條記錄。這個方法不是冪等的,因此違反了基本的RESTful API原則。

PUT方法也必須是冪等的。因此,如果需要將wins的數量從數據庫中的當前值更改為10,那麼一個好的RESTful Java API將如下所示:

HTTP PUT || www.mcnz.com/rps/score/wins?value=10

我們可以一次又一次地調用此方法,每次調用之後,服務器將處於相同的狀態:wins的得分是10。這個RESTful Java API是冪等的。反例是,每次調用該方法時添加10次win:

HTTP PUT || www.mcnz.com/rps/score/wins?add=10

這個方法不是冪等的,因為每次調用時,wins的數目會跳轉到一個新的值。wins的得分開始時是10,第二次調用時20次,下一次30次。使用此方法,資源的最終狀態是不可預測的。它不是冪等的,也不是好的RESTful API設計。

從技術上講,URL末尾的查詢參數應該僅用於查詢。在本例中,我們使用查詢參數向服務器傳遞有效負載。這樣做使示例更簡單,但也突破了查詢參數本來的用途。在未來的RESTful API設計教程中,我們將演示如何在PUT調用期間將JSON字符串作為有效負載的一部分來進行傳遞,這是比使用查詢參數更好的設計。

保守的使用RESTful API設計的瑞士軍刀:POST方法

我們已經知道,從數據庫中刪除10條最老的記錄是對DELETE方法的錯誤使用,而簡單的數字增量則是PUT方法的糟糕應用,這是否意味著我們不能用RESTful API來完成這些事情?當然不是。

目前為止,我們建立了兩個非常重要的規則:

GET調用不能更改資源的狀態。

PUT和DELETE方法必須是冪等的。

但是請注意,我們還沒有提到POST方法。在上述規則之外的任何場景中,都可以使用POST方法。因此,如果要從數據庫中刪除10條最老的記錄,可以使用POST方法。如果想將wins得分加10,同樣可以使用POST方法。POST方法,從某種意義上講,是RESTful設計的瑞士軍刀。

HTTP POST || www.mcnz.com/rps/score/wins?add=10

HTTP POST || www.mcnz.com/rps/score?oldRecordsToDelete=10

當然,如果將POST方法作為一種普適的方法,來應對RESTful API設計的所有挑戰,還是存在風險的。僅僅因為沒有違反關於冪等性的規則或濫用GET、PUT和DELETE方法,並不意味著已經正確地設計了RESTful API。過度使用POST方法本身也是RESTful設計的誤區之一。

通常,我們會看到一個被認為是RESTful的系統中,設計人員投機取巧地將API的所有排列都設計為POST調用。僅僅因為沒有違反重要的RESTful原則,並不意味著已經開發了一個有效的RESTful API。當RESTful API設計者對他們的問題域採取“基於服務”的方法時,經常會出現頻繁使用POST方法的趨勢。創建RESTful API時,始終在系統中應用“基於資源”的方式十分重要。

白小白:

此處實際上稍微令人費解,原因在於基於服務和基於資源的概念在本文中並未明確的給出解釋。其實可以將此區別理解為傳統的SOAP與REST的區別之一,這裡有一篇文章我覺得寫的很好( https://blog.csdn.net/caisini_vc/article/details/48465731 )。比如,一個刪除用戶的操作,在基於服務的模式下,所有的 SOAP 消息經過代理服務器,只能看到(http://localhost:8182/v1/soap/servlet/messagerouter, HTTP POST)這樣的信息,如果代理服務器想知道當前的 HTTP 請求具體做的是什麼,必須對 SOAP 的消息體解碼。而在基於資源的模式下,URL的描述是(http://localhost:8182/v1/users/{username},DELETE),這不僅有利於服務器的識別,更可以實現安全控制。

還有很多需要學習的東西,比如將有效負載數據傳遞給服務器的最佳實踐,如何構造URL以識別資源,以及如何避免在“基於資源的設計”中應用了“基於服務的方法”這樣的誤區。我們將在隨後的RESTful API教程中介紹這些內容。但是,構建URL和正確使用HTTP方法是每一個優雅的“基於資源的API”設計的堅實基礎。

RESTful API教程:學習關鍵的Web服務設計原則

關於作者:Cameron McKenzie from TechTarget, TheServerSide.作為JavaEE軟件工程師,Cameron McKenzie已經有20年的從業經驗。他目前的專注于敏捷開發、DevOps和基於容器的技術,如Docker、Swing和Kubernetes。

關於EAWorld:微服務,DevOps,數據治理,移動架構原創技術分享,長按二維碼關注


分享到:


相關文章: