Benjamin Carlyle has an interesting bit about the possibility of deprecating the HTTP POST method. I think most people who have thought deeply about RESTful architectures have had similar thoughts. GET, PUT and DELETE are all nicely idempotent, but POST is not. GET, PUT, and DELETE have clean, well defined semantics, but POST does not. POST generally seems a little out of place next to it’s cleaner cut cohorts. However, there is an absolute requirement for the “process this” semantics of POST so deprecating it is completely out of the question. On the other hand, it does get used in some situations where there are better approaches.
POSTs lack of idempotence has some nasty side effects particularly for what is probably the most common use of POST today, new resource creation. Consider the following scenario, you POST a request to create a new resource but you don’t get a response. It is impossible to automatically recover from this scenario. You cannot resend the request because the new resource may have been created and you just did not get the response and you cannot check to see if the resource was created because you don’t know the URI it would have been assigned if it had, in fact, been created.
I think Mr. Carlyle is correct that using POST for resource creation is sub-optimal. He suggest the following approach1, suppose you have a new purchase order resource you want to make known to the server. The client generates a GUID and the issues the following request
PUT /purchaseOrders/76fd9473-a270-4aac-8a06-e5265048cbbc HTTP/1.1 Host: example.com Content-Length: .... <PurchaseOrder> ... </PurchaseOrder>
The server thinks “I do not know of a purchase order with an id of 76fd9473-a270-4aac-8a06-e5265048cbbc so this request is regarding a never before seen purchase order” then the go about storing that brand new purchase order and returns a “201 Created” response. From are RESTful point of view this is a reasonable approach. It relies on only standard PUT semantics, is resource focused and is idempotent so you can safely keep repeating the request until you get a response.
While relatively straight forward the approach does requires a lot of out of band information because the client has to understand the servers id generation scheme and be able to reliably generate a new id that is unique. If you are using GUIDs as the resource id’s you can be reasonably assured that clients can, in fact, generate globally unique ids so there are not really a practical short term problem.
Some potential problems arise when you have a server that uses a scheme for which ids cannot be reliably generated on the client, such as monotonically-increasing numbers, or where there would be a different way to figure the id for each type of resource, such as natural keys. It also tightly couples the clients to the server implementation in ways I think are dangerous. For example, what happens if you decide you would like to move to an URL scheme that is less ugly than GUIDs?
For all those situations Mr. Carlyle proposes continuing to use a GUID based URI for resource creation PUTs but rather than actually creating the resource, having the server response with a permanent redirect to a new URI at which the resource should exist. The client would then re-issue the PUT request to the new URI and only then would server create the new resource.
I really like the general arc of this proposal but I despise the GUID part. GUIDs are ugly and they offend my sense of elegance. However, this proposed approach can be easily tweaked into something I really like. Suppose that rather using GUID based URIs you instead used a “new resource” URI. For example you could say
PUT /purchaseOrders/new HTTP/1.1 Host: example.com Content-Length: .... <PurchaseOrder> ... </PurchaseOrder>
the server would respond with
HTTP/1.1 303 See Other Location: http://example.com/purchaseOrders/any_random_sort_of_id_the_server_wants ...
and the client would re-issue the PUT to the URI specified in the redirect. This pushes URI generation back to the server, where it belongs, while still retaining the general goodness of having all interactions between the client and server be idempotent.
It’s just too bad this approach does not work in a browser2.
I rephrase it here to make sure I really understand it and because I found the examples in the original a little hard to follow.
According to RFC 2616 (section 10.3) a redirection
MAY be carried out by the user agent without interaction with the user if and only if the method used in the second request is GET or HEAD.
So while technically you could do this in a browser the user experience would suck.
↩</li> </ol> </div>