Each user has a collection of gems. These gems can be accessed via a REST API:
GET /user/<user id>/gem -> get all gems
GET /user/<user id>/gem/<gem id> -> get an existing gem
POST /user/<user id>/gem -> add a new gem
PUT /user/<user id>/gem/<gem id> -> edit an existing gem
DELETE /user/<user id>/gem/<gem id> -> delete an existing gem
I have several backend processes, which run concurrently and which could add gems via the POST
HTTP method. (They can also edit (PUT
) or delete (DELETE
) gems, but that's not important for my question. Well actually, it is. Please continue reading.)
Seen from a high-level view, they do the following:
1. GET /user/<current user id>/gem
2. some calculations, based on step 1
3a. if (step 2 decided that a gem should be added)
3b. POST /user/<current user id>/gem
As said, these processes run in parallel. Usually, two processes are not managing the gems of the same user, but it might happen.
So I need a mechanism to disallow the POST
in step 3b
if something changed in the meantime. I thought about using ETags and optimistic locking:
1. GET /user/<current user id>/gem and remember the returned ETag
2. some calculations, based on step 1
3a. if (step 2 decided that a gem should be added)
3b. POST /user/<current user id>/gem with header 'If-Match=<ETag from step 1>'
3c. if (server returns 412 - precondition failed)
3d. start again at step 1
I am not sure if ETags are intended for this. Most examples of ETag are about one single resources (such as /gem/23
), but not about a collection of resources (such as /gem
). That is, in step 3b
, I am providing the ETag of the complete collection of gems, while in essence I am providing one single gem to be added.