tags:

views:

68

answers:

2

While looking at the code in "petclinic", part of Spring 3.0 samples I noticed the following lines

<c:choose>
  <c:when test="${owner.new}"><c:set var="method" value="post"/></c:when>
  <c:otherwise><c:set var="method" value="put"/></c:otherwise>
</c:choose>

In this discussion at SO it seems that PUT should be used for "create/update" and POST for "updates".

Which is right?

What is the impact of using post for "create" and put for "update"?

Note : According to the HTTP/1.1 spec. quoted in the referenced SO discussion, the code given above seems to have the correct behavior.

+3  A: 

Both POST and PUT are have well defined behavior as per HTTP spec.

The result of a POST request should be a new resource that is subordinate to the request URL; the response should contain Location header with the URL of the newly created resource.

The result of a PUT should be an update of the resource at the request URL. if there is no existing resource at the request URL, a new one can be created.

The confusion arises from the fact that POST is also used with forms as a mechanism to pass the form data. Most common implementation of forms is to post back to the same URL at which the form page is located, thus giving the false idea that the POST operation is used for an update. However, in this particular usage, the form page is not the resource.

With all this in mind, here's the correct (in my opinion of course :-)) usage:

POST should be used to create new resources when:
- the new resource is subordinate to an existing resource - the resource identity/URL is not known at creation time

PUT should be used to update existing resources with well-known URL. It can be used to create a resource at well-known URL as well; however, it does help to think about this scenario in a different way - if the resource URL is known before the PUT request is made, this could be treated the same as the resource at this location already existing but being empty.

Franci Penov
The HTTP spec won't include that phrase for much longer. The revised version is here" `http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-11#page-17`
Darrel Miller
@Darren Miller - nice, so they just changed it enough so that both `PUT` and `POST` could be used for creating new or updating existing resource. :-) With the small difference that `PUT` should *store* the enclose data at the request URL, and `POST` should *process* the data at the request URL and _might_ return a Location header, which _might_ or _might not_ be the same as the request URL. Nope, there won't be any confusion at all there...
Franci Penov
@Franci There is a bigger difference between PUT and POST. With PUT what you are sending MUST be stored at the URI you PUT to. With POST, there is no such constraint. The semantics of PUT are far more constrained than POST. The problem in the past is too many people tried to do the mapping between HTTP methods and CRUD. In reality, it is not a sane thing to try and do.
Darrel Miller
@Darrel Miller - umh, isn't what you said the same as what I said? `PUT` _stores_ the request data, `POST _processes_ it. The result from _store_ is well-defined, the result from _process_ can be anything. :-)
Franci Penov
@Darrel Miller - my comment about the confusion was more in the line that at least, with the current definition, `POST` for anything but `application/x-www-form-urlencoded` was explicitly defined as _create_ of a new subordinate resource, so there was a rough mapping between HTTP `POST` and CRUD `CREATE`; but with the new draft, they allow `POST` to do anything it wants. Thus as you say, there's no sane way to map HTTP methods to CRUD consistently and every app has to explicitly define that mapping.
Franci Penov
@Franci The distinction for me is *where* the data gets stored.
Darrel Miller
@Franci Actually, no, the current definition also states that POST supports `Providing a block of data, such as the result of submitting a form, to a data-handling process` This is a catch all statement. The new definition is explicitly non-specific :-)
Darrel Miller
@Darrel Miller - With the current definition, if `POST` results in an identifiable resource, it must be a new resource subordinate to the resource at the request URL. Indeed, this is important distinction between `PUT` and `POST` - at the request URL or at a new URL. However, the new wording seems to allow for identifiable resources resulting from a `POST` request to be located at the request URL. In other words, the "new" `POST` might or might not behave exactly like `PUT`, at the implementor's discretion. Hence my "no confusion at all" comment. Unless I am missing something, of course. :-)
Franci Penov
@Franci I've never been aware of any constraint on POST that says if 201 is returned, the Location header MUST point to a subordinate resource. From the response to my question here http://lists.w3.org/Archives/Public/ietf-http-wg/2010JulSep/0272.html it seems that you can use POST to create resources at the request URL.
Darrel Miller
@Darrel Miller - RFC 2616, 9.3 is explicit that if no new identifiable resource is created, the response should be 200 or 204, and 201 should be used if an identifiable resource is created, in which case that resource should be subordinate to the resource at the request URL. Thus, a response to a POST can't be 201 with the Location header set to the request URL
Franci Penov
@Franci - The RFC even defines subordinate: *The posted entity is subordinate to that URI in the same way that a file is subordinate to a directory containing it, a news article is subordinate to a newsgroup to which it is posted, or a record is subordinate to a database.* It does not mention that the URI of the created resource must have any relation to the URI of the recipient of the data.
mogsie
@mogsie - I never said anything about the relationship between the new resource URL and the request URL. however, it would be hard to put the new subordinate resource at the request URL, as that means effectively deleting the current resource at this URL. it would be hard for the new resource to be subordinate to a resource that does not exist anymore.
Franci Penov
+2  A: 

It's quite simple:

  • POST allows anything to happen, and it isn't restricted to creating "subordinate" resources, but allows the client to "provide a block of data ... to a data-handling process" (RFC 2616 sec 9.5). POST means "Here's that data you asked for just now"
  • PUT is used as an opposite of GET. The usual flow is that you GET a resource, modify it somehow, and then you PUT it back at the same URI that you got it from. PUT means "Please store this file at this URI".

The uniformity of PUT (which is to store a file) allows intermediaries (e.g. caches) to invalidate any cached responses they might have at that exact URI (since they know that it's about to change). The uniformity of PUT also allows clients (that understand this) to modify a resource by first retrieving it (GET) and then send a modified copy back (PUT). It also allows clients to retry on a network failure, due to PUT's idempotency.

Side note: Using PUT to create resources is dubious. While it's possible within the spec, I don't see it as a good idea, just as using POST to perform searches isn't a good idea, just as tunneling SOAP over HTTP isn't a good idea. AtomPub explicitly states that PUT isn't used to create atom entries.

POSTs ubiquitousness comes from the fact that HTML defines <form> elements that result in POSTing a application/x-www-form-urlencoded entity, with which the recipient can do anything it pleases, including

  • creating subordinate resources (The repsonse is usually accompanied by a 201 response and Location header)
  • creating a completely different resource (again usually a 201 response and Location header)
  • creating many subordinate and/or unrelated resources (perhaps with a simple response indicating the URIs of the created resources)
  • doing nothing except return a response (e.g. 200 or 302) (a case where perhaps GET should have been used)
  • modifying the resource that received the POST itself (returning or redirecting back to the updated resource).
  • delete one or more resource.
  • any combination of the above.

The only one who knows what will happen in a POST request is the user who initiated the request (by clicking the huge "yes I confirm deleting my Facebook profile" button) and the server that's handling the request. To the rest of the world, the request is opaque and doesn't mean anything other than "this URI is being passed some data".

So the answer to your question is that both POST and PUT can be used for both create and update.

  1. POST is often use to create resources (like AtomPub 9.2)
  2. PUT semantics fits well for modifying resources (like AtomPub 9.3)
  3. POST may be used to modify resources (like a www form edit your profile)
  4. PUT can technically be used to create resources (although I advise against it)
mogsie
Since PUT and POST can technically be used for the create/update, the code fits with the definition. One discussion surrounding mapping of HTTP to CRUD is what is the contract with the client. In this case it looks like the client should expect that PUT would be idempotent while POST would not be idempotent. I prefer point #4 for this reason.
venky