Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why HTTP method PUT should be idempotent and not the POST in implementation RestFul service?

Tags:

java

rest

jax-rs

There are many resources available over the internet wherein PUT vs POST is discussed. But I could not understand how would that affect the Java implementation or back end implementation which is done underneath for a RestFul service? Links I viewed are mentioned below:

https://www.keycdn.com/support/put-vs-post/

https://spring.io/understanding/REST#post

https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

http://javarevisited.blogspot.com/2016/10/difference-between-put-and-post-in-restful-web-service.html

For example let's say there is a RestFul webservice for Address. So POST /addresses will do the job of updating the Address and PUT /addresses/1 will do the job of creating the one. Now how the HTTP method PUT and POST can control what weservice code is doing behind the scenes?

PUT /addresses/1 

may end up creating multiple entries of the same address in the DB.

So my question is, why the idempotent behavior is linked to the HTTP method?

How will you control the idempotent behavior by using specif HTTP methods? Or is it that just a guideline or standard practice suggested?

I am not looking for an explanation of what is idempotent behavior but what make us tag these HTTP methods so?

like image 210
Sam Avatar asked Feb 22 '18 10:02

Sam


People also ask

Why put is idempotent but POST is not?

PUT and DELETE are idempotent, POST is not. For example, if we make the PUT request from our test once, it updates the avatarNumber to 2. If we make it again, the avatarNumber will still be 2. If we make the PUT request 1 time or 10 times, the server always results in the same state.

Why put is idempotent in REST?

Generally – not necessarily – PUT APIs are used to update the resource state. If you invoke a PUT API N times, the very first request will update the resource; the other N-1 requests will just overwrite the same resource state again and again – effectively not changing anything. Hence, PUT is idempotent.

Why we use Put instead of POST?

Use PUT when you want to modify a single resource which is already a part of resources collection. PUT overwrites the resource in its entirety. Use PATCH if request updates part of the resource. Use POST when you want to add a child resource under resources collection.

Why put method is considered as idempotent whereas POST method is not in the context of the REST?

Why every method is not idempotent, by default? Post method always results in a server state change. If the POST method was idempotent, everything sent and accepted to or from the web server would already have to exist on the server in some form to respond with the same codes and value response.


2 Answers

This is HTTP specific. As RFC linked by you states that https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html (see up to date RFC links at the bottom of this answer). It is not described as part of REST: https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

Now you wrote,

I am not looking for an explanation of what is idempotent behavior but what make us tag these HTTP methods so?

An idempotent operation has always the same result (I know you know it), but the result is not the same thing as the HTTP response. It should be obvious from HTTP perspective that multiple requests with any method even all the same parameters can have different responses (ie. timestamps). So they can actually differ.

What should not change is the result of the operation. So calling multiple times PUT /addresses/1 should not create multiple addresses.

As you see it's called PUT not CREATE for a reason. It may create resource if it does not exist. If it exists then it may overwrite it with the new version (update) if its exactly the same should do nothing on the server and result in the same answer as if it would be the same request (because it may be the same request repeated because the previous request was interrupted and the client did not receive response).

Comparing to SQL PUT would more like INSERT OR UPDATE not only INSERT or UPDATE.

So my question is, why the idempotent behavior is linked to the HTTP method?

It is likned to HTTP method so some services (proxies) know that in case of failure of request they can try safely (not in the terms of safe HTTP method but in the terms of idempotence) repeat them.

How will you control the idempotent behavior by using specif HTTP methods?

I'm not sure what are you asking for. But:

  • GET, HEAD just return data it does not change anything (apart maybe some logs, stats, metadata?) so it's safe and idempotent.
  • POST, PATCH can do anything it is not safe nor idempotent
  • PUT, DELETE - are not safe (they change data) but they are idempotent so it is "safe" to repeat them.

This basically means that safe method can be made by proxies, caches, web crawlers etc. safely without changing anything. Idempotent can be repeated by software and it will not change the outcome.

Or is it that just a guideline or standard practice suggested?

It is "standard". Maybe RFC is not standard yet but it will eventually be one and we don't have anything else we could (and should) follow.

Edit:

As RFC mentioned above is outdated here are some references to current RFCs about that topic:

  • Retrying idempotent requests by client or proxy: https://www.rfc-editor.org/rfc/rfc7230#section-6.3.1
  • Pipelineing idempotent requests: https://www.rfc-editor.org/rfc/rfc7230#section-6.3.2
  • Idempotent methods in: HTTP https://www.rfc-editor.org/rfc/rfc7231#section-4.2.2

Thanks to Roman Vottner for the suggestion.

like image 70
Daniel Boczek Avatar answered Oct 12 '22 21:10

Daniel Boczek


So my question is, why the idempotent behavior is linked to the HTTP method? I am not looking for an explanation of what is idempotent behavior but what make us tag these HTTP methods so?

So that generic, domain agnostic participants in the exchange of messages can make useful contributions.

RFC 7231 calls out a specific example in its definition of idempotent

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. For example, if a client sends a PUT request and the underlying connection is closed before any response is received, then the client can establish a new connection and retry the idempotent request. It knows that repeating the request will have the same intended effect, even if the original request succeeded, though the response might differ.

A client, or intermediary, doesn't need to know anything about your bespoke API, or its underlying implementation, to act this way. All of the necessary information is in the specification (RFC 7231's definitions of PUT and idempotent), and in the server's announcement that the resource supports PUT.

Note that idempotent request handling is required of PUT, but it is not forbidden for POST. It's not wrong to have an idempotent POST request handler, or even one that is safe. But generic components, that have only the metadata and the HTTP spec to work from, will not know or discover that the POST request handler is idempotent.

I could not understand how would that affect the Java implementation or back end implementation which is done underneath for a RestFul service?

There's no magic; using PUT doesn't automatically change the underlying implementation of the service; technically, it doesn't even constrain the underlying implementation. What it does do is clearly document where the responsibility lies.

It's analogous to Fielding's 2002 observation about GET being safe

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).

An important thing to realize is that, as far as HTTP is concerned, there is no "resource hierarchy". There's no relationship between /addresses and /addresses/1 -- for example, messages to one have no effect on cached representations of the other. The notion that /addresses is a "collection" and /addresses/1 is an "item in the /addresses collection" is an implementation detail, private to the origin server.

(It used to be the case that the semantics of POST would refer to subordinate resources, see for example RFC 1945; but even then the spelling of the identifier for the subordinate was not constrainted.)

I mean PUT /employee is acceptable or it has to be PUT/employee/<employee-id>

PUT /employee has the semantics of "replace the current representation of /employee with the representation I'm providing". If /employee is a representation of a collection, it is perfectly fine to modify that collection by passing with PUT a new representation of the collection.

GET /collection

200 OK

{/collection/1, collection/2}

PUT /collection

{/collection/1, /collection/2, /collection/3}

200 OK

GET /collection

200 OK

{/collection/1, /collection/2, /collection/3}

PUT /collection

{/collection/4}

200 OK

GET /collection

200 OK

{/collection/4}

If that's not what you want; if you want to append to the collection, rather than replace the entire representation, then PUT has the wrong semantics when applied to the collection. You either need to PUT the item representation to an item resource, or you need to use some other method on the collection (POST or PATCH are suitable)

GET /collection

200 OK

{/collection/1, collection/2}

PUT /collection/3

200 OK

GET /collection

200 OK

{/collection/1, /collection/2, /collection/3}

PATCH /collection

{ op: add, path: /4, ... }

200 OK

GET /collection

200 OK

{/collection/1, /collection/2, /collection/3, /collection/4 }
like image 39
VoiceOfUnreason Avatar answered Oct 12 '22 20:10

VoiceOfUnreason