Prajwal Tuladhar’s Blog
 
programming, life and some random thoughts

Aug 10 2009

Readings

Published by under Links


Comments Off

May 31 2009

Damn! There is a difference between HTTP POST and HTTP PUT

Published by under REST

HTTP 1.1 specifications has defined number of request methods like: GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, OPTIONS. But generally, GET and POST are two widely used and de-facto request methods due to the restrictions set by the server as well as client in most of the scenarios. As a web developer, I do know that these methods exist but like most of the web developers I had focused only on POST and GET because normally, other methods besides GET and POST are not supported by most web servers.

It’s been few sessions that I have started playing with document based storage technology, CouchDB which is *naturally* based on the REST philosophy. There is a really nice quote in CouchDB book site “Django may be built for the Web, but CouchDB is built of the Web”.

Everything was going fine until there was a command for creating database that utilizes HTTP PUT method:

$ curl -X PUT http://127.0.0.1:5984:/new_db

The response is: {"ok":true}

So, I was wondering what will happen if I use POST because my preception was that POST and PUT are really not so much different:
$ curl -X POST http://127.0.0.1:5984:/new_db

Response: {"error":"not_found", "reason": "missing"}

Booom! I was wrong!

As usual I google on the web and was pretty happy to find that it was not only me who was confused about PUT versus POST debate ;)

W3C has defined following functions of POST:

  • Annotation of existing resources;
  • Posting a message to a bulletin board, newsgroup, mailing list, or similar group of articles;
  • Providing a block of data, such as the result of submitting a form, to a data-handling process;
  • Extending a database through an append operation.

Let’s focus only on first function of POST for now. It clearly states that POST should be used for existing resources.

In my case, http://127.0.0.1:5984:/new_db has not existed yet so, using POST to create is against the specification.

But again trying to differentiate PUT and POST as: PUT for creating new resource and POST for updating existing one would be awful mistake. One can view PUT as a SQL insert operation. When a specified URI is defined, it will create resource there if the resource does not exist or replace the existing one.

But POST is quite flexible and can perform more operations as compared to PUT. POST sends data to the specified URI but how it will be processed is entirely dependent on the server. The action performed by the POST method might not result in a resource that can be identified by a URI. In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on whether or not the response includes an entity that describes the result.

According to the HTTP 1.1 specification:

The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request — the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI, it MUST send a 301 (Moved Permanently) response; the user agent MAY then make its own decision regarding whether or not to redirect the request.

Examples:

  • PUT => http://mysocialapp/users/{username} => createUser
  • PUT => http://mysocialapp/users/{username} => updateUser
  • POST => http://mysocialapp/users/{username}/posts => createPost
  • PUT => http://mysocialapp/users/{username}/posts/{post_id} => updatePost

The URI and client will be ultimately responsible for handling above requests URI. If we look at the POST example, there is no way one can map the URI for every posts being created so, POST is idempotent and non-cacheable. While first and second example shows that PUT can be used not only to create resource but also to update it. But this solely depends on who is responsible for creating the new resource’s URI: client or the server. If client is responsible, then it should response 201 (“created”) when new resource is created and when the resource URI already exists, it should use POST method. If the server is responsible, it should respond 401 (“unauthorized”). If I try to create same database “new_db” using:

$ curl -X POST http://127.0.0.1:5984:/new_db then CouchDB returns {"error": "database_already_exists", "reason":"Database \"another_test_db\" already exists"}

Lastly, it would be better if Roy T. Fielding’s response on PUT is also considered:

FWIW, PUT does not mean store.  I must have repeated that a million times in webdav and related lists.  HTTP defines the intended semantics of the communication — the expectations of each party. The protocol does not define how either side fulfills those expectations, and it makes damn sure it doesn’t prevent a server from having absolute authority over its own resources.  Also, resources are known to change over time, so if a server accepts an invalid Atom entry via PUT one second and then immediately thereafter decides to change it to a valid entry for later GETs, life is grand.

Some useful links + resources:

Please do correct me if I am wrong :)


Comments Off

RSS Feed
Subscribe by email
Follow me @ Twitter