PUT POST being idempotent (REST)

2019-02-09 10:00发布

I don't quite get how the HTTP verbs are defined as idempotent. All I've read is GET and PUT is idempotent. POST is not idempotent. But you could create a REST API using POST that doesn't change anything (in the database for example), or create a REST API for PUT that changes every time it is called.

Sure, that probably is the wrong way to do things but if it can be done, why is PUT labeled as idempotent (or POST as not) when it is up to the implementation? I'm not challenging this idea, I'm probably missing something and I ask to clear my understanding.

EDIT:

I guess one way to put my question is: What would be the problem if I used PUT to make a non-idempotent call and POST to do so?

3条回答
ゆ 、 Hurt°
2楼-- · 2019-02-09 10:18

hope the link helps to you:HTTP Method idempotency

Be careful when dealing with safe methods as well: if a seemingly safe method like GET will change a resource, it might be possible that any middleware client proxy systems between you and the server, will cache this response. Another client who wants to change this resource through the same URL(like: http://example.org/api/article/1234/delete), will not call the server, but return the information directly from the cache. Non-safe (and non-idempotent) methods will never be cached by any middleware proxies.

查看更多
疯言疯语
3楼-- · 2019-02-09 10:19

You are right in pointing out there is nothing inherent within the HTTP protocol that enforces the idempotent attribute of methods/verbs like PUT and DELETE. HTTP, being a stateless protocol, retains no information or status of each request that the user makes; every single request is treated as independent.

To quote Wikipedia on the idempotent attribute of HTTP methods (emphasis mine):

Note that whether a method is idempotent is not enforced by the protocol or web server. It is perfectly possible to write a web application in which (for example) a database insert or other non-idempotent action is triggered by a GET or other request. Ignoring this recommendation, however, may result in undesirable consequences, if a user agent assumes that repeating the same request is safe when it isn't.

So yes, it is possible to deviate from conventional implementation, and rollout things like non-changing POST implementation, non-idempotent PUT etc. probably with no significant, life-threatening technical problems. But you might risk upsetting other programmers consuming your web services, thinking that you don't know what you're doing.

Here's an important quote from RFC2616 on the HTTP methods being safe (emphasis mine):

Implementors should be aware that the software represents the user in their interactions over the Internet, and should be careful to allow the user to be aware of any actions they might take which may have an unexpected significance to themselves or others.

In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested.

Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them.

UPDATE: As pointed out by Julian, RFC 2616 has been replaced by RFC 7231. Here's the corresponding section.

So when you publish a web service as a PUT method, and I submit a request that looks like:

PUT /users/<new_id> HTTP/1.1
Host: example.com

I will expect a new user resource to be created. Likewise, if my request looks like:

PUT /users/<existing_id> HTTP/1.1
Host: example.com

I will expect the corresponding existing user to be updated. If I repeat the same request by submitting the form multiple times, please don't pop up a warning dialog (because I like the established convention).

Conversely, as a consumer of a POST web service, I will expect requests like:

POST /users/<existing_id> HTTP/1.1
Host: example.com

to update the corresponding existing user, while a request that looks like:

POST /users/<new_id> HTTP/1.1
Host: example.com

to raise an error because the URL doesn't exist yet.

查看更多
太酷不给撩
4楼-- · 2019-02-09 10:28

Indeed, an implementation can do anything it wants. However, if that is incorrect according to the protocol spec, surprising things might happen (such as as library or intermediary repeating a PUT if this first attempt failed).

查看更多
登录 后发表回答