03 Feb 2017 - by 'Maurits van der Schee'
How should a RESTful JSON-based API handle counters (atomic increments)? In this post I'll try to describe the considerations and do an implementation suggestion using the "PATCH" HTTP method.
When counting events, such as people visiting a web page, it may be cheaper to increment a counter than to insert a log record. But when dealing with many increments per second you cannot simply read a value in one call and then write the incremented value back in the next call. The concurrent updates would cause issues and increments would get lost. This is the problem I am trying to solve.
In my quest for the most appropriate method for incrementing values I have ran into the various methods (or verbs) described in HTTP, the concept of "safe" and "idempotent" requests, the "PATCH" method and the "JSON PATCH" standard for updating an existing JSON HTTP resource. That last one sounded very promising, and even has an operation named "add", but unfortunately that is for adding elements to a JSON array and not for incrementing counters.
The following HTTP methods are allowed in RFC 2616 (the HTTP 1.1 standard):
None of the above seem very suitable for an "increment" command.
RFC 2616 & 7231 say that GET and HEAD methods should not take other action than retrieval of information and can therefor be considered "safe". Other methods, such as POST, PUT and DELETE take actions other than retrieval and should be considered "unsafe".
Also defined in RFC 2616 & 7231 is that a request is "idempotent" when the result of multiple identical invocations is the same as that of a single invocation. The methods GET, HEAD, PUT and DELETE, but also OPTIONS and TRACE, share this property, while POST and PATCH do not.
RFC 5789 describes that the extension method PATCH should be used to modify an existing HTTP resource as opposed to PUT, which is for replacement of a document.
RFC 6902 describes the use of the extension method PATCH to send a JSON document describing operations to apply to an existing JSON document (HTTP resource).
Creating a RESTful JSON API involves mapping the HTTP standard to SQL and this is not easy. In order to facilitate incrementing, you could allow back-references or commands in posted JSON documents (or post values). Another option is to use the PATCH verb for this purpose. This means you can no longer use that for partial updates, so you would have to allow those for the PUT method (a common violation of the standard).
Using PATCH to increment is simple, which is good, but has the downside you cannot easily express other operations. You can, however, vary what PATCH does based on the type of the field. You may want PATCH to "concatenate" to a string or blob typed field while you would "increment" a numeric or date typed field (using seconds). I implemented PATCH as increment for numeric fields in my (pragmatic) API project PHP-CRUD-API.