Robert Robert - 3 months ago 7
reST (reStructuredText) Question

Best practices for RESTful API for records with version numbers. Do I use PUT?

Need some guidance on best practices for building a RESTful API in node.js

Let's say I have a person record like so:

{
id: 1,
name: 'Jon',
age: 25,
recordVersion: 1
}


If I need to increment the recordVersion every time a value gets changed, would I still use a HTTP PUT to update this record? I've researched on how PUT should be idempotent and should contain the newly-updated representation of the original resource, so I am no sure of what to do.

I could increment the recordVersion property on the first PUT call and send an error on the second PUT call with the same versionNumber of 1 (because it would have incremented to 2 at that point), but does this follow RESTful API standards?

Answer

Representation != State

The resources sent over the wire are a representation of the state, not the actual state.

It's perfectly fine to remove the recordVersion and to update it behind the scenes - however if you do that, it would be best to remove it from the representation returned by a GET to that resource as well. To understand why: idempotency is all about what would happen if you applied the operation multiple times in a row (it isn't guaranteed if other operations happen in between...), and about observable side effects.

  • PUT the data without the version
    • the data is updated
    • version code incremented
    • if you did a GET you would get the data you had PUT (with no version)
  • PUT the same data again without the version
    • the data is updated
    • version code incremented
    • if you did a GET you would get the same data you had PUT (with no version)

Idempotent, because the resource representation has not changed as a result of calling PUT twice, even though the internal entity state has changed - no observable side effects.

See http://restcookbook.com/HTTP%20Methods/idempotency/ for a bit more detail.

Using version codes to detect conflicts

As you note, you could use inspect the version and throw an error if it has changed - and in fact this is very RESTful, and in my opinion the best way to approach PUT as it helps avoid (often inexplicable) concurrency errors. If you detect this case, it would be appropriate to return a 409 Conflict http status code.

How this would work is:

  • PUT the data with the version (v1)
    • the data is updated
    • version code incremented
    • if you did a GET you would get the data you had PUT with the new version (v2) (this is a side effect, but it's ok to have a side effect from the first time you do an operation).
  • PUT the same data again with version (v1)
    • conflict is detected because v1 != v2
    • 409 Conflict returned
    • if you did a GET you would get the same as the result of the first operation - the data you originally PUT with the version v2

This is idempotent, because there have been no observable side effects as a result of calling the operation twice.

The client should, in response to a 409, do another GET to get the latest version code, and possibly offer to the user the opportunity to merge their changes with whatever else has changed in the meantime.

Often people confuse idempotency with thinking that the response to the operation must be the same as a result of multiple calls, but that is not the case - it is about there being no observable side effects as a result of multiple sequential calls.

Comments