1. 問題
不斷演進 REST API 是一項困難的問題——存在許多可選項。本文討論其中一些選項。2. 合同內容是什麼?
在其他任何事情之前,我們需要回答一個簡單的問題:
首先,讓我們考慮
如果是這樣,那麼客户端與 REST 服務之間的交互將不再由服務本身驅動,而是由 Roy Fielding 稱之為
A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience…Failure here implies that out-of-band information is driving interaction instead of hypertext.
因此,
關於用於表示資源的 Media Type 信息——這些是否是客户端和服務之間合同的一部分?
因此,REST 服務應該將重點放在這裏:
A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types.
因此,
我們現在對合同有了大致的瞭解,接下來讓我們看看如何解決版本問題。
3. 高級選項
現在我們來討論 REST API 版本化的高層方法:
- URI 版本化 – 使用版本指示符版本化 URI 空間
- 媒體類型版本化 – 版本化資源的表示
當我們引入 URI 空間中的版本時,資源的表示被認為是不可變的。 因此,當 API 中需要引入更改時,需要創建一個新的 URI 空間。
例如,假設一個 API 發佈以下資源 - 用户和權限:
http://host/v1/users
http://host/v1/privileges
現在,讓我們假設 API 中的一項破壞性更改需要引入第二個版本:
http://host/v2/users
http://host/v2/privileges
當我們版本化媒體類型並擴展語言時,我們通過使用此標頭進行內容協商 lenta.
。 這是因為任何已發佈 API 中的任何斷層更改都將引入整個 API 的全新表示樹。 隨着時間的推移,這成為維護的負擔,同時也為客户端帶來問題——現在它們有更多的選擇。 。 沒有辦法簡單地演化單個資源或整體 API 的小部分。
Vary HTTP 標頭 以指示正在緩存的多個版本。 ,採用版本化媒體類型的方法比包含版本標識符的 URI 的方法需要更多工作,因為當其鍵是一個 URL 而不是一個媒體類型時,緩存某物更容易。 API 演化)來結束這一部分: 接下來,我們考慮一下REST API中引入的變更類型——這些在下面介紹: 媒體類型的文檔格式應以向前兼容性為目標。 具體的,客户端應忽略它不理解的信息(JSON在這方面做得更好,而不是XML)。 現在,在表示資源的“amount”信息不會破壞現有客户端,如果這些客户端得到正確實現。 為了繼續我們的早先示例,在“user”資源的表示中添加“amount”不會導致破壞性變更: 刪除、重命名或總體上重構現有表示中的信息是對於客户端來説是破壞性變更,因為他們已經理解並依賴於舊格式。 這就是內容協商的作用。 對於這些變更,我們可以添加一個新的供應商 MIME 媒體類型。 讓我們繼續之前的示例。 假設我們想將“name”的“user”拆分為“firstname”和“lastname”: 因此,這對於客户端來説是不兼容的變更——客户端必須請求新的表示形式並理解新的語義。 但是,URI 空間將保持穩定,不受影響。 這些是資源、它們之間的關係或它們在後端映射的內容中的變更。 這種變更可能需要新的媒體類型,或者可能需要發佈一個新的、兄弟資源旁邊,並利用鏈接指向它。 雖然這聽起來像在 URI 中再次使用版本標識符,但重要的是,新的資源獨立於 API 中的其他資源發佈,不會在根級別分叉整個 API。 REST API 應該遵循 HATEOAS 約束。 根據此約束,大多數 URI 應該由客户端發現,而不是硬編碼。 更改此類 URI 不應被視為不兼容的變更。 新的 URI 可以替換舊的 URI,客户端將能夠重新發現 URI 並繼續功能。 值得注意的是,雖然使用版本標識符在 URI 中存在這些問題,但它在任何一種方式上都不是不符合 RESTful 的。
5. 可能的API變更
5.1. 增加資源的表示信息
{
"user": {
"name": "John Smith",
"amount": "300"
}
}5.2. 刪除或更改現有表示信息
===>
GET /users/3 HTTP/1.1
Accept: application/vnd.myname.v2+json
<===
HTTP/1.1 200 OK
Content-Type: application/vnd.myname.v2+json
{
"user": {
"firstname": "John",
"lastname": "Smith",
"amount": "300"
}
}5.3. 主要語義變更
6. 結論
本文旨在概述 演進 RESTful 服務這一非常複雜且多樣的問題。我們討論了兩種常見的解決方案,各自的優缺點,以及在 REST 的背景下如何進行思考。
本文的結論是支持第二種解決方案——版本化媒體類型,同時考察 RESTful API 的可能變更。
7. 進一步閲讀
通常,這些閲讀資源會在文章中穿插鏈接,但在此情況下,好的資源實在太多了: