If a GET request's response changes, is idempotency respected?
Asked Answered
R

2

7

I am reading a lot about rest API and I always stumble upon terms idempotency. Basically GET, HEAD, PUT, DELETE and OPTIONS are all idempotent, and POST is not.

This statement on http://www.restapitutorial.com/lessons/idempotency.html made me doubt my understanding of idempotency.

From a RESTful service standpoint, for an operation (or service call) to be idempotent, clients can make that same call repeatedly while producing the same result. In other words, making multiple identical requests has the same effect as making a single request. Note that while idempotent operations produce the same result on the server (no side effects), the response itself may not be the same (e.g. a resource's state may change between requests).

So does idempotency actually has something to do with server-work or a response?

What confuses me if I have

GET /users/5

returning

{
"first_name" : "John",
"last_name" : "Doe",
"minutes_active": 10
}

and then do the same request after one minute I would get

GET /users/5
{
"first_name" : "John",
"last_name" : "Doe",
"minutes_active": 11
}

How is this idempotent?

Furthermore if response contains some kind of UUID which is unique for each response, would that break idempotency?

And finally, is idempotency same server-work over and over again, or same results over and over again for the same/single request?

Rhizobium answered 4/7, 2017 at 12:31 Comment(1)
I suggested an edit to rephrase the question in the title.Lankester
M
9

So does idempotency actually has something to do with server-work or a response?

It refers to the server state after subsequent request of the same type.

So, lets suppose that the client makes a request that changes the server's old state, for example S1, to a new state, S2, then makes the same request again.

If the method is idempotent then it is guaranteed that the second request would not change the server's state again, it will remain S2.

But if the method is not idempotent, there is no guarantee that the state would remain the same, S2; it may change to whatever state the server wants for example S3 or S1. So, in this case the client should not send the command again if a communication error occurs because the outcome would not be the same as the first time it sent the command.

GET /users/5 How is this idempotent?

You may call this url using GET method as many time you want and the server would not change its internal state, i.e. last_name of the user; if it does not change it, then it remains the same so GET is idempotent.

Furthermore if response contains some kind of UUID which is unique for each response, would that break idempotency?

The response has nothing to do with the server's state after subsequent requests of the same type so the response could be unique after each request and the request would still be idempotent. For example, in the GET request from your question, the minutes_active would be greater each minute and this does not make GET not-idempotent.

Other example of idempotent method is DELETE. For example if you delete a user then it is gone/deleted. Because DELETE is idempotent, after a second atempt/request to delete the same user, the user would remain deleted so the state would not change. Of course, the second response could be a little different, something like "warning, user already deleted" but this has nothing to do with idempotency.

Magical answered 4/7, 2017 at 20:47 Comment(0)
M
2

For understanding idempotency in REST, your best starting point is probably going to be the definition include in RFC 7231

A request method is considered "idempotent" if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request.

For "effect", think side effect. When the server is advertising that a particular action is idempotent, it is telling you that the (semantically significant) side effects will happen at most once.

// the guarantee of an idempotent operation
oldState.andThen(PUT(newState)) === oldState.andThen(PUT(newState)).andThen(PUT(newState))

Safe methods are inherently idempotent, because they have no effect on the server.

// the guarantee of a safe operation
oldState === oldState.andThen(GET)

// therefore, the guarantee of an idempotent operation follows trivially oldState.andThen(GET) == oldState.andThen(GET).andThen(GET)

So does idempotency actually has something to do with server-work or a response?

Server work. More generally, its a constraint on the receiver of a command to change state.

Roy Fielding shared this observation in 2002:

HTTP does not attempt to require the results of a GET to be safe. What it does is require that the semantics of the operation be safe, and therefore it is a fault of the implementation, not the interface or the user of that interface, if anything happens as a result that causes loss of property (money, BTW, is considered property for the sake of this definition).

If you substitute PUT/DELETE for GET, and idempotent for safe, I think you get a good picture -- if a loss of property occurs because the server received two copies of an idempotent request, the fault is that the server handled the request improperly, not that the client broadcast the request more than once.

This is important because it allows for at least once delivery over an unreliable network. From RFC 7231

Idempotent methods are distinguished because the request can be repeated automatically if a communication failure occurs before the client is able to read the server's response.

Contrast this with POST; which does not promise idempotent handling. Submitting a web form twice may produce two side effects on the server, so the client implementations (and intermediary components, like proxies) cannot assume it is safe to repeat a lost request.

Back in the day, dialogs like this were common

Internet explorer warning about retrying a form submission

for precisely this reason

And finally, is idempotency same server-work over and over again, or same results over and over again for the same/single request?

Work on the server. An idempotent change is analogous to SET, or REPLACE (aka, compare and swap).

The responses may, of course, be different. A conditional PUT, for example, will include meta data "indicating a precondition to be tested before applying the method semantics to the target resource."

So the server might change state in response to the receiving the first copy of a put, sending back 200 OK to indicate to the client that the request was successful; but upon receiving the second request, the server will find that the now-changed state of the resource no longer matches the provided meta data, and will respond with 412 Precondition Failed.

I noticed you mentioned may produce in "Contrast this with POST; which does not promise idempotent handling. Submitting a web form twice may produce two side effects on the server....." basically rest standards declare POST as non-idempotent, but one could actually make POST an idempotent, but it would be opposite to rest standards...

No, that's not quite right. The HTTP specification does not require that POST support idempotent semantics -- which means that clients and intermediaries are not permitted to assume that it does. The server controls its own implementation; it may provide idempotent handling of the POST request.

But the server has no way to advertise this capability to the clients (or intermediaries), so that they can take advantage of it.

Male answered 4/7, 2017 at 14:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.