1

I'm trying to design a RESTful web API, so I've been studying rfc2616. I like the idea of using ETags for optimistic concurrency and was trying to use it to make a safe way to add resources without race-conditions. However, I noticed the following two statements in section 14.24:

If the request would, without the If-Match header field, result in anything other than a 2xx or 412 status, then the If-Match header MUST be ignored.

A request intended to update a resource (e.g., a PUT) MAY include an If-Match header field to signal that the request method MUST NOT be applied if the entity corresponding to the If-Match value (a single entity tag) is no longer a representation of that resource.

I'm using a RDBMS and don't know whether a transaction will successfully commit until I try it, so I think the first requirement seems a bit onerous. Consider a case where somebody supplies an If-Match header with mismatched ETags: If the commit would succeed, then I should heed the If-Match header, NOT attempt the commit, and return 412. If the commit would fail, then a request without the If-Match header would have resulted in a non-2XX/412 response, so I MUST ignore the If-Match header, meaning I should attempt the commit.

As far as I can figure out, I have 2 options:

  1. Use 2-phase commits to gain foresight into whether the commit will succeed before attempting it.
  2. Ignore the first requirement above, and return 412 even if ignoring If-Match would have resulted in a non-2XX/412 response. (this is the one I'm leaning towards)

Any other ideas? Am I misinterpreting the specs?

Community
  • 1
  • 1
Steve W.
  • 13
  • 2
  • Slightly related, may be of interest for the 412 crowd: http://stackoverflow.com/questions/3620203/http-status-412-precondition-failed-and-database-versioning?rq=1 – Thilo Aug 06 '12 at 01:13

2 Answers2

3

Wouldn't something like "update unless modified" (optimistic locking) work? The entity would need to store a version number or the etag in the database.

  1. run validations that don't require a commit, ignoring the etag, return error if necessary

  2. update entity where id = :the_id and etag = :expected_etag

  3. this returns either 0 or 1 for affected rows

  4. if 0 the resource has seen a concurrent update (or the id is completely wrong, which you could check separately). In this case return 412

  5. commit

  6. if the commit fails, return error as appropriate

Thilo
  • 257,207
  • 101
  • 511
  • 656
0

Maybe this is somewhat on the theoretical side, but based on my current understanding of the HTTP specification, I would classify the usage of If-Match-like headers practically unusable for all but maybe the safe methods, because of this:

"If the request would, without the If-Match header field, result in anything other than a 2xx or 412 status, then the If-Match header MUST be ignored".

Why? Simply because in most practical cases, it's just impossible to foresee what should happen if the request was carried out.

As an example, who can forsee a IO-level error or some exceptional case occuring in code that must be run?

It'd be more "solvable" if 5xx where added to 2xx and 412.

Per Samuelsson
  • 1,000
  • 1
  • 6
  • 8