Wednesday, May 7, 2014

REST API Best Practices 3: Partial Updates - PATCH vs PUT

This post is a continuation of REST API Best Practices 2: HTTP and CRUD, and deals with the question of partial updates.

REST purists insist that PATCH is the only "correct" way to perform partial updates [1], but it hasn't reached "best-practice" status just yet, for a number of reasons.

Pragmatists, on the other hand, are concerned with building mobile back-ends and APIs that simply work and are easy to use, even if that means using PUT to perform partial updates [2].

The problems with using PATCH for partial updates are manifold:
  1. Support for PATCH in browsers, servers and web application frameworks is not universal. IE8, PHP, Tomcat, django, and lots of other software has missing or flaky support for it. So depending on your technology stack and users, it might not even be a valid option for you.
  2. Using the PATCH method correctly requires clients to submit a document describing the differences between the new and original documents, like a diff file, rather than a straightforward list of modified properties. This means the client has to do a lot of extra work - keep a copy of the original resource, compare it to the modified resource, create a "diff" between the two, compose some type of document showing the differences, and send it to the server. The server also has more work to apply the diff file. 
  3. There's no specification that says how the changes in the diff file should be formatted or what it should contain, exactly. The RFC simply says:
    "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."
    One early recommendation for using PATCH is the JSON Patch RFC [3]. Unfortunately, the spec overly complicates updating. I describe a much simpler alternative below, which works with either PATCH or PUT.

Pragmatic partial updates with PUT

Using PUT for partial updates is pretty simple, even if it doesn't conform strictly to the concept of Representational State Transfer.  So a fair number of programmers happily use it to implement partial updates on back-end mobile API servers. It's fair to say that when developing an API, a pragmatic approach that focuses on the needs of mobile client applications is completely reasonable.

Current "best practices" when using PUT for partial updates, as I see it, is this: When you PUT the update:
  1. Include the properties to be updated, with their new values
  2. Don't include properties that are not to be updated
  3. Set properties to be 'deleted' to null
The reality is that most data is going to be stored in a database that has an implicit or explicit schema that describes what sort of data your application is expecting. If you're using a relational database, this will end up being columns in your database tables, some of whose values may be null. In this scenario it makes perfect sense to "delete" properties by setting them null, since the database columns are not going to disappear in any case. And for those who use a NoSQL database, its not a stretch to delete nullified properties.

Update: This pragmatic approach to updates is used by a number of exemplary SaaS companies, including Github. It can also be used with the HTTP PATCH method, and it has now been formalized in RFC 7386 JSON Merge Patch [4].

Further reading

1. http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/
2. http://techblog.appnexus.com/2012/on-restful-api-standards-just-be-cool-11-rules-for-practical-api-development-part-1-of-2/
3. http://tools.ietf.org/html/draft-ietf-appsawg-json-patch-07
4. https://tools.ietf.org/html/rfc7386 

No comments:

Translate