REST:使用PATCH進行部分更新 - mscharhag
在開始之前,讓我們快速檢查一下為什麼部分更新有用的原因:
- 簡單性-如果客戶端只想更新一個欄位,則部分更新請求可能更易於實現。
- 頻寬-如果您的資源表示量很大,則部分更新可以減少所需的頻寬量。
- 更新丟失-使用PUT替換資源可能會導致更新丟失問題。儘管部分更新不能解決此問題,但它們可以幫助減少可能的衝突數量。
PATCH方法不屬於原始HTTP RFC的一部分。後來透過RFC 5789新增了它。PATCH方法既不安全也不是冪等的。但是,PATCH通常以冪等方式使用。
PATCH請求可以包含一個或多個請求的資源更改。如果請求多個更改,則伺服器必須確保自動應用所有更改。RFC說:
伺服器必須原子地應用整個更改集,並且絕不提供([..])部分修改的表示形式。如果無法成功應用整個補丁文件,則伺服器不得應用任何更改。
PATCH的請求主體非常靈活。RFC僅表示請求正文必須包含有關如何修改資源的說明:
使用PATCH [..],封閉的實體包含一組指令,這些指令描述了應如何修改當前駐留在原始伺服器上的資源以產生新版本。
這意味著我們不必為PATCH請求使用與可能用於PUT或GET請求的資源表示相同的資源。我們可以使用完全不同的Media-Type來描述資源更改。
PATCH可以以兩種常見的方式使用,它們都有各自的優缺點。在下一部分中,我們將對它們進行研究。
使用標準資源表示形式傳送更改(JSON合併Patch)
使用PATCH的最直觀的方法是保留GET或PUT請求中使用的標準資源表示形式。但是,對於PATCH,我們僅包括應更改的欄位。
假設我們有一個簡單的產品資源。一個簡單的GET請求的響應可能如下所示:
GET /products/123 { "name": "Cool Gadget", "description": "It looks very cool", "price": 4.50, "dimension": { "width": 1.3, "height": 2.52, "depth": 0.9 } "tags": ["cool", "cheap", "gadget"] } |
現在我們要提高價格,刪除便宜的標籤,並更新產品寬度。為此,我們可以使用以下PATCH請求:
PATCH / products / 123 { “ price”:6.20, “ dimension”:{ “ width”:1.35 } “ tags”:[“ cool”,“ gadget”] } |
請求中未包括的欄位應保持不變。為了從標籤陣列中刪除一個元素,我們必須包括所有剩餘的陣列元素。
PATCH的這種用法稱為JSON合併修補程式,在RFC 7396中定義。您可以想到僅使用欄位子集的PUT請求。這種修補方式通常使PATCH請求成為冪等。
JSON合併Patch和空值
您應該瞭解JSON Merge Patch的一個警告:處理空值。
假設我們要刪除先前使用的產品資源的描述。PATCH請求如下所示:
PATCH /products/123 { "description": null } |
為了滿足客戶的意圖,伺服器必須區分以下情況:
欄位不是JSON檔案的一部分。在這種情況下,說明應保持不變。description
欄位是JSON文件的一部分,並且具有值零。在此,伺服器應刪除當前description
。description
在使用將JSON文件對映到物件的JSON庫時,請注意這種區別。在Java之類的強型別程式語言中,當對映到強型別物件時,兩種情況都有可能產生相同的結果(兩種情況中的description欄位都可能為null)。
因此,在支援空值時,應確保可以同時處理兩種情況。
使用單獨的Patch格式
如前所述,可以將不同的媒體型別用於PATCH請求。
再次,我們要提高價格,刪除便宜的標籤,並更新產品寬度。完成此操作的另一種方法可能如下所示:
PATCH /products/123 { "$.price": { "action": "replace", "newValue": 6.20 }, "$.dimension.width": { "action": "replace", "newValue": 1.35 }, "$.tags[?(@ == 'cheap')]": { "action": "remove" } } |
在這裡,我們使用JSONPath表示式來選擇要更改的值。然後,對於每個選定的值,我們使用一個小的JSON物件來描述所需的操作。
要替換簡單值,此格式非常冗長。但是,它也具有一些優點,尤其是在處理陣列時。如示例所示,我們可以刪除一個陣列元素而不傳送所有剩餘的陣列元素。在使用大型陣列時,這很有用。
JSON Patch
用於描述使用JSON進行更改的標準媒體型別是JSON Patch(在RFC 6902中進行了描述)。使用JSON Patch,我們的請求如下所示:
PATCH /products/123 Content-Type: application/json-patch+json <p class="indent">[ { "op": "replace", "path": "/price", "value": 6.20 }, { "op": "replace", "path": "/dimension/width", "value": 1.35 }, { "op": "remove", "path": "/tags/1" } ] |
這看起來與我們之前的解決方案相似。JSON Patch使用op元素來描述所需的操作。path元素包含一個JSON指標(又一RFC),以選擇應當施加的變化的元件。
請注意,當前版本的JSON Patch不支援按值刪除陣列元素。相反,我們必須使用陣列索引刪除該元素。使用/ tags / 1,我們可以選擇第二個陣列元素。
在使用JSON Patch之前,您應該評估它是否滿足您的需求,以及您是否對它的侷限性感到滿意。在GitHub儲存庫json-patch2的問題中,您可以找到有關JSON Patch可能修訂的討論。
如果您使用的是XML而不是JSON,則應該看一下XML Patch(RFC 5261),它的工作原理類似,但是使用的是XML。
Accept-Patch標頭
用於HTTP PATCH的RFC還為HTTP OPTIONS請求定義了一個新的響應標頭:Accept-Patch。使用Accept-Patch,伺服器可以傳達給定資源的PATCH操作支援哪些媒體型別。RFC說:
對於支援使用PATCH方法的任何資源,“Accept-Patch”都應該出現在OPTIONS響應中。
支援PATCH方法並使用JSON Patch的資源的示例HTTP OPTIONS請求/響應可能如下所示:
OPTIONS /products/123 HTTP/1.1 200 OK Allow: GET, PUT, POST, OPTIONS, HEAD, DELETE, PATCH Accept-Patch: application/json-patch+json |
對HTTP PATCH操作的響應
PATCH RFC並不要求PATCH操作的響應主體看起來如何。可以返回更新的資源。也可以將響應主體留空。
伺服器通常使用以下HTTP狀態程式碼之一響應HTTP PATCH請求:
- 204(無內容)-表示操作已成功完成,沒有資料返回
- 200(Ok)-操作已成功完成,並且響應主體包含更多資訊(例如,更新的資源)。
- 400(錯誤請求)-請求正文格式錯誤,無法處理。
- 409(衝突)-請求在語法上有效,但不能應用於資源。例如,如果由JSON指標(路徑欄位)選擇的元素不存在,則可以將其與JSON補丁一起使用。
總結
PATCH操作非常靈活,可以以不同的方式使用。JSON Merge Patch(JSON合併Patch)使用標準資源表示來執行部分更新。但是,JSON Patch 使用單獨的PATCH格式來描述所需的更改。還可以提出自定義的PATCH格式。支援PATCH操作的資源應返回OPTIONS請求的Accept-Patch標頭。
相關文章
- REST API設計:如何處理Http併發一致性事務更新? - mscharhagRESTAPIHTTP
- 如何使用diff 和 patch 命令對檔案進行協作?
- 使用更新補丁對Android Studio進行更新。Android
- 在REST API中支援批次操作的幾個不同方法 - mscharhagRESTAPI
- 使用Spring Boot REST API進行測試驅動開發Spring BootRESTAPI
- 使用 RestTemplate 進行第三方Rest服務呼叫REST
- 如何使用git 生成patch 和打入patchGit
- 如何使用Spring Data進行一個實體中一部分資料的更新? | BaeldungSpring
- vue js 部分使用小技巧(持續更新)VueJS
- 使用 git add -p 整理 patchGit
- 使用多執行緒提高rest服務效能執行緒REST
- 使用SemanticKernel 進行智慧應用開發(2023-10更新)
- 使用Spring Reactive MongoDB進行自定義更新查詢 -Yuri MednikovSpringReactMongoDB
- Deadmin 更新部分文件介紹快速使用方法
- 用ASP.NET Core 2.0 建立規範的 REST API -- DELETE, UPDATE, PATCH 和 LogASP.NETRESTAPIdelete
- 使用VC++6.0 進行圖形介面設計部分控制程式碼的使用方法C++
- NetCore專案實戰篇03---HTTP Patch 更新資料NetCoreHTTP
- Spring Data JDBC如何對DDD聚合根進行部分更新? - spring.ioSpringJDBC
- [譯]使用 U-Net 進行語義分割(第一部分)
- Qt學習筆記-使用QScreen對螢幕進行截圖(可全屏,可部分)QT筆記
- LINUX 的patch 製作,及打patchLinux
- 打 patch 報錯:corrupt patch at line 36
- 瀏覽器漏洞正被利用,谷歌、火狐使用者儘快進行更新瀏覽器谷歌
- Diff and Patch
- Wisdom rest-client 使用教程RESTclient
- 使用SpringBoot構建REST服務-什麼是REST服務Spring BootREST
- Go微服務 - 第九部分 - 使用RabbitMQ和AMQP進行訊息傳遞Go微服務MQ
- Go微服務 - 第八部分 - 使用Viper和Spring Cloud Config進行集中配置Go微服務SpringCloud
- Webpack 4教程 - 第八部分 使用prefetch和preload進行動態載入Web
- 在多資料來源中對部分資料表使用shardingsphere進行分庫分表
- 使用Redis進行限流Redis
- 2.3.3.4 Application PatchAPP
- MySQL的原始碼安裝及使用UDFs進行資料自動更新的教程MySql原始碼
- 使用RxJava快取Rest請求RxJava快取REST
- Git 打補丁-- patch 和 diff 的使用(詳細)Git
- Git 打補丁– patch 和 diff 的使用(詳細)Git
- Salesforce LWC學習(三十五) 使用 REST API實現不寫Apex的批量建立/更新資料SalesforceRESTAPI
- 【mos 1265700.1】Oracle Patch Assurance - Data Guard Standby-First Patch ApplyOracleAPP