-->

How to support Partial Updates (PATCH) in REST

2019-03-08 07:50发布

问题:

I want to implement the partial updates for my resource as i have large resource and want to update the partial information from it.I have gone through the following links but not
able to figure out whether to use HTTP POST or PATCH methods.

HTTP MODIFY verb for REST?

How to submit RESTful partial updates?

http://jacobian.org/writing/rest-worst-practices/

https://github.com/archiloque/rest-client/issues/79

http://tools.ietf.org/html/draft-dusseault-http-patch-16

http://greenbytes.de/tech/webdav/draft-dusseault-http-patch-06.html

http://jasonsirota.com/rest-partial-updates-use-post-put-or-patch

http://bitworking.org/news/296/How-To-Do-RESTful-Partial-Updates

https://github.com/dharmafly/jsonpatch.js

Please suggest any valid solution for this.

回答1:

According to RFC5789 (http://tools.ietf.org/html/rfc5789), this is precisely what PATCH is for:

Several applications extending the Hypertext Transfer Protocol (HTTP) require a feature to do partial resource modification. The existing HTTP PUT method only allows a complete replacement of a document. This proposal adds a new HTTP method, PATCH, to modify an existing HTTP resource.

The distinction between PATCH and PUT is described as:

The difference between the PUT and PATCH requests is reflected in the way the server processes the enclosed entity to modify the resource identified by the Request-URI. In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server, and the client is requesting that the stored version be replaced. With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version.

The limitations of POST are also described:

The PUT method is already defined to overwrite a resource with a complete new body, and cannot be reused to do partial changes. Otherwise, proxies and caches, and even clients and servers, may get confused as to the result of the operation. POST is already used but without broad interoperability (for one, there is no standard way to discover patch format support) [...]

I would suggest you read the RFC and make up your own mind, but to me this seems fairly clear-cut - PATCH requests should be processed as partial updates. (NB they are NOT idempotent, unlike PUT.)

EDIT: as pointed out by Eugene in the comments, although PATCH requests are "neither safe nor idempotent as defined by [RFC2616]", they can be made so:

A PATCH request can be issued in such a way as to be idempotent, which also helps prevent bad outcomes from collisions between two PATCH requests on the same resource in a similar time frame. Collisions from multiple PATCH requests may be more dangerous than PUT collisions because some patch formats need to operate from a known base-point or else they will corrupt the resource. Clients using this kind of patch application SHOULD use a conditional request such that the request will fail if the resource has been updated since the client last accessed the resource. For example, the client can use a strong ETag [RFC2616] in an If-Match header on the PATCH request.



回答2:

You should use method PATCH like described in RFC-7386 "json merge PATCH".

E.g. if you want to change value of "a" and removing "f" in resource like:

   {
     "a": "b",
     "c": {
       "d": "e",
       "f": "g"
     }
   }

You can achive this by sending:

       PATCH /target HTTP/1.1
       Host: example.org
       Content-Type: application/merge-patch+json

       {
         "a":"z",
         "c": {
           "f": null
         }
       }


回答3:

PATCH is to be used with a patch format, for document-level patching only (aka a diff on the actual representation). Its use for other purposes is dubious and debatable, and it's not clear that the method was designed for non-media-type uses.

In general a POST will be the right approach, but you may want to split your resource into multiple resources instead and modify those instead.

[Edited for clarity, as some don't read comments]