How to prevent race conditions in Restful APIs

Oct 14, 2014

HTTP Protocol

The Hypertext Transfer Protocol (HTTP) is an application-level protocol for distributed, collaborative, hypermedia information systems http://www.w3.org/Protocols/Specs.html

Scenario:

Imagine that two users retrieve the same document from the server. And, they would like to make different updates on it: image

But, the first user is faster than the second one and sends its modifications to the server. image

From the point of view of the second user, he believes that he is changing the original document. He does not know that there is another version of that document. The system must prevent that by not allowing to change the document and returning an error to the user.

One interesting approach to achieving it is by using the ETag or entity tag.

When the users retrieve a representation of the resource:

GET /article/123 HTTP/1.1

they get an additional ETag header:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8; profile="http://localhost:5000/api/item-schemas/article-schema"
Link: <http://localhost:5000/api/item-schemas/article-schema>; rel="describedby"
Content-Length: 76
ETag: W/"4c-6abdcf72"
Connection: keep-alive

That value should be sent on subsequent requests, along with another HTTP header called If-None-Match, the way the server may compare it with the current version of the document. If the value matches, it means that the representation of the resource is the same, the server may send back a response with a HTTP 304 Not Modified status (This is for cache purposes).

It is possible to take advantage of ETag, along with other HTTP header called If-Match to prevent race conditions. The client must send those two headers on the request:

PUT article/123
If-Match: W/"4c-6abdcf72"

{
  "title": "Something new."
}

After the update, the ETag value gets changed:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8; profile="http://localhost:5000/api/item-schemas/article-schema"
Link: <http://localhost:5000/api/item-schemas/article-schema>; rel="describedby"
Content-Length: 76
ETag: W/"4e-8942e140"
Connection: keep-alive

So, when the second user sends his modifications with the old ETag value, the server may send back a response with HTTP 409 Conflict status or HTTP 412 Precondition Failed status.

Happy Coding!

Cover Photo by: Andy Higgs

Icons: http://thenounproject.com/term/user/8457/, http://thenounproject.com/term/user/8458/.).