3

Far as I understand, PUT request is not supposed to return any content. Consider the client wants to run this pseudo code:

x = resource.get({id: 1});
x.field1 = "some update";
resource.put(x);
x.field2 = "another update";
resource.put(x);

(Imagine I have an input control and a button "Save", this allows me to change a part of object "x" shown in an input control, then on button click PUT changes to server, then continue editing and maybe "save" another change to "x")

Following different proposals on how to implement optimistic locking in REST APIs, the above code MUST fail, because version mark (however implemented) for "x" as returned by get() will become stale after put(). Then how do you people usually make it work? Or do you just re-GET objects after every PUT?

Maksim Gumerov
  • 642
  • 8
  • 23
  • I suppose I could return an updated ETag response header from PUT, but I don't feel it's conceptually any different than returning something in response body. PUT is not supposed to return anything, is it? – Maksim Gumerov Feb 21 '16 at 11:43

2 Answers2

0

You can use "conditional" actions with HTTP, for example the If-Match header described here:

https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24

In short: You deliver an ETag with the GET request, and supply this ETag back to the server in the If-Match header. The server will respond with a failure if the resource you are trying to PUT has another ETag. You can also use simple timestamps with the If-Unmodified-Since header.

Of course you will have to make your server code understand conditional requests.

For multiple steps, the PUT can indeed return the new representation, it can therefore include the new ETag or timestamp too. Even if the server does not return the new representation for a PUT, you could still use the timestamp from the response with an If-Unmodified-Since conditional PUT.

Robert Bräutigam
  • 7,514
  • 1
  • 20
  • 38
  • Thanks. So basically your advice boils down to "you have to return something from PUT to use multiple PUTs, be it an updated data object or header with updated ETag"? Or am I missing something? Looks like those are same ideas I described in my question :) – Maksim Gumerov Feb 21 '16 at 18:38
  • Actually what bugs me is the idea that PUT should not return anything. Have a look at http://stackoverflow.com/questions/797834/should-a-restful-put-operation-return-something - or, rather, they just say "no response body is needed" – Maksim Gumerov Feb 21 '16 at 18:47
  • 2
    "No response body is needed" is correct, the specification does not say you have to return something, it even has a response code (`204 No Content`) to indicate that. It does not say anywhere that `PUT` should not return anything. It implies actually that you should if the client view of the object changed, which is exactly your use-case I think. – Robert Bräutigam Feb 22 '16 at 07:27
0

Here is probably what I was looking for: https://www.rfc-editor.org/rfc/rfc7231#section-4.3.4 They implicitly say that we CAN return ETag from PUT. Though only in the case server applied the changes as they were given, without any corrections.

However this raises yet another question. In real world app PUT caller will run asynchronously in JS gui, like in my example in the question. So, Save button might be pressed several times with or without entering any changes. If we don't use optimistic locking, then supposed PUT idempotency makes it safe to send another PUT query with each button click, as long as the last one wins (but actually if there were changes then it's not guaranteed, so the question remains).

But with optimistic locking, when first PUT succeeds, it returns updatred ETag, ok? And if there is another PUT request running, still with outdated tag version, that latter request will get 412 and the user will see a message "someone else changed the resource" - but actually it was our former changes.

What do you usually do to prevent that? Disable the Save button until its request is fully completed? What if it times out? Or do you think it's acceptable to see concurrent-change error message if it was a timeout, because the stability is already compromised anyway?

Community
  • 1
  • 1
Maksim Gumerov
  • 642
  • 8
  • 23