REST API: 該使用部分更新還是全部更新?

關於Rest API更新資源的討論:
當更新一個對象的時候,是否要將完整object全部信息重新提交到服務器?還是隻提交部分內容?

  • 一種是完整提交的方案
    • 認爲在前端需要保存完整的object數據,在前端由用戶做更改,
      之後將完整的object重新使用PUT方法傳回服務器。
    • 這種方法的弊端在於
      • 傳送數據量過大
    • 好處是
      • API冪等
      • 後端設計簡單
  • 一種是部分提交的方案
    • 認爲每次在前端更改內容的時候,只將更新的內容提交到服務器即可
    • 好處
      • 交互流量少
    • 弊端
      • 當該模型某些字段可爲null時,如何知道沒有指定的字段,是要求置爲Null還是保持原樣?

事實上查閱資料後,發現這是一個架構設計的問題。

一切開端於REST API的設計原則。
根據REST API的設計哲學,每個API需要有以下幾個性質:
1. 服務器-客戶端原則
- 在整個應用中,需要將客戶端與服務器分開,兩者之間儘量解耦合,都可以分開演進
2. 無狀態
- 客戶端的狀態不會在服務端存儲。每個session的信息只在客戶端存儲。
3. 可緩存
- 同樣的請求應該有同樣的返回,使得請求可緩存。
4. 分層
- 客戶端無法分辨自己是否直接連接到服務器或者是中間層。這個性質可以進一步增強可擴展性。
5. 統一的接口設計
- 這個是REST接口設計的核心。分爲以下幾個小原則
1. 識別資源
- 資源通過請求進行識別。識別後的資源會在服務端進行轉換格式,返回到客戶端。返回的格式與數據本身無關。
2. 通過資源的表達來操作資源
- 客戶端需要保存完整的資源,以及必要的元信息(MetaData),使得這些信息足夠對資源進行修改或刪除。
3. 自解釋的消息
- 每個消息需要包含足夠的信息來決定如何處理這個消息。例如在指定parser的時候需要使用Internet media type來指定。
4. HATEOAS
- 字面意思是,超媒體作爲應用狀態轉移的引擎
- 從最開始的一共請求開始,每次返回的請求能夠告訴客戶端,服務端還有哪些資源提供。有時可以返回帶有超鏈接的文字。
- 客戶端不需要根據服務端的數據結構進行任何定製

這些原則很多是過於嚴苛的。在實際操作中如果嚴格遵循,會給架構設計帶來很大的約束。

這裏我們只討論一個細節,就是前端在修改內容的時候,是否需要上傳完整的數據?
原始的REST API中,只提供Get,Put,Post,Delete四種操作。
GET:獲取資源列表或單個資源。這是一種nullipotent的操作,即,操作進行多次之後,等於沒有進行。對於任何正整數n,x^n = 1.
PUT: 將指定的資源進行替換。如果作用在collection上,則替換整個collection。這是一個冪等操作,即操作多次之後,等於操作一次,而且每次操作的結果是相同的。對於任何正整數n,x^n = x.
POST:一般只作用於collection上。在這個collection中新建一條記錄。
DELETE:刪除對應記錄或collection。

這四種操作,除了POST,都有很好的性質。但針對如何對一個對象的部分字段進行更新,則一直有各種爭論。
後來在2010年的時候,HTTP協議中增加了一個操作:Patch,
此時REST API也使用這個新的操作來進行資源的部分更新。

但是,這個Patch操作有許多值得注意的地方,一個是,這個操作不冪等,一個是,在進行patch操作的時候,
需要以原子操作的形式來進行,而不能同時指定多個更新字段。

例如,在更新資源時,需要指定是增加,還是更新某個字段。

PATCH /users
[
    { "op": "add", "username": "newuser", "email": "[email protected]" }
]

以及

PATCH /users/123
[
    { "op": "replace", "path": "/email", "value": "[email protected]" }
]

注意這裏的op字段指定了服務器該如何操作傳送過來的字段。

Patch 爲何不冪等呢?
有兩個解釋,一個是,在兩次patch請求之間,如果對應資源有改變,那麼兩次patch請求造成的結果不同,
返回的object也不同。
另一個解釋是,當資源模型中有一個列表時,如果多次執行 add 操作,那麼這個列表幾次操作後得到的結果也不同。

所以,我的看法是,在儘量多的地方使用PUT,對完整資源進行更新,在必要時使用Patch,指定原子級別操作來進行部分更新。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章