Monday, October 1, 2012

Use HTTP PATCH method for partial updates

Had an interesting problem at work to design the RESTful API for partial updates of resources. We want an API to partially update an existing resource, e.g. some existing properties get updated or deleted, some new properties get added, etc. The body is in JSON format.

There are a few choices:

  • Use POST, add a query parameter to capture the operation (delete, add, update), put the affected properties in the POST body.
  • Use PUT, similar to above POST design.
  • Use POST, but instead of using a new query parameter, design the body to capture the operation and the data for the operation. For example, use delete, add, and update as the first level properties, then put the actual properties under the corresponding operations.
  • Use PUT, similar to the above POST design.
Then, a colleague suggested using PATCH for partial updates to make it really RESTful. Yeah, I vaguely remember there is one HTTP method for PATCH, but what does it do and why should we care?

First, let's see the difference between POST and PUT. One misconception is that POST is used to create a resource, PUT is used to update a resource. Actually, both POST and PUT can be used for creation. Here are the major points based my study:
  • PUT is idempotent, POST is not. This means you can send the same PUT request multiple times and the result should remain the same as you send it only once.
  • PUT URL uniquely identifies the representation in the request body. POST URL identifies the service to process the request body. For example, PUT URL is like the address on each regular mail, which uniquely identifies the mail, POST URL is like the address of the post office, which identifies the service to process the mails. The result of POST request handling on the server side does not necessarily creates new representations/resources that can be identified by a URL.
  • PUT response is not cacheable, in addition, PUT response should invalidate the cached copies of the representation identified by the PUT URL in the intermediate caches when the response passes through the caches. POST response, however, is cacheable if it contains "freshness" cache control headers. A cached POST 303 response contains Content-Location header redirecting User Agent to fetch the cached copy.
So, PUT URL identifies a complete representation to be updated or created. For example, you can use PUT to overwrite an entire representation. How about partial updates, which is more common. If you only want to do partial update, according to HTTP spec, you need to use a different URL that identifies the partial content and send the partial content as request body. Or you need to use the PATCH method (defined in rfc5789).

Mark Norttingham has a nice piece explaining why PATCH is good for a RESTful design. He is also working on a JSON PATCH draft (rev 05 was updated days ago), which defines semantics in JSON format, exactly what we are looking for ;-) Note it has a new content type of "application/json-patch".

The PATCH request body should contain operations (such as add, remove, update, etc.), the relative path to the URL identifying the entire representation, and the value. Here is an example from the JSON PATCH draft:

       { "op": "test", "path": "/a/b/c", "value": "foo" },
       { "op": "remove", "path": "/a/b/c" },
       { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
       { "op": "replace", "path": "/a/b/c", "value": 42 },
       { "op": "move", "path": "/a/b/c", "to": "/a/b/d" },
       { "op": "copy", "path": "/a/b/c", "to": "/a/b/e" }

In fact, PATCH is going to be the main method for updates starting in Rails 4.0. However, PATCH method may not be as well supported as POST or PUT. In case your framework or server does not support it, you will have to fall back to one of the choices mentioned in the beginning of the post, probably.


No comments:

Post a Comment