POST vs PUT Requests – Understanding the Convention

httprest

I've read quite a few articles on the difference between POST and PUT and in when the two should be used. But there are still few things confusing me ( hopefully questions will make some sense ):

1) We should use PUT to create resources when we want clients to specify the URI of the newly created resources and we should use POST to create resources when we let service generate the URI of the newly created resources.

a) Is it just by convention that POST create request doesn't contain an URI of the newly created resource or POST create request actually can't contain the URI of the newly created resource?

b) PUT has idempotent semantics and thus can be safely used for absolute updates ( ie we send entire state of the resource to the server ), but not also for relative updates ( ie we send just changes to the resource state ), since that would violate its semantics.

But I assume it's still possible for PUT to send relative updates to the server, it's just that in that case the PUT update won't be idempotent?

2) I've read somewhere that we should "use POST to append a resource to a collection identified by a service-generated URI".

a) What exactly does that mean? That if URIs for the resources were generated by a server ( thus the resources were created via POST ), then ALL subsequent resources should also be created via POST? Thus, in such situation no resource should be created via PUT?

b) If my assumption under a) is correct, could you elaborate why we shouldn't create some resources via POST and some via PUT ( assuming server already contains a collection of resources created via POST )?

Best Answer

Read the HTTP spec that defines those methods. Seriously. It will clarify a lot of questions for you going forward.

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

  • In HTTP, PUT is specifically the create / update method. Create if it doesn't exist, or update it if it does.

  • POST is sort of the grab-bag method. As Roy Fielding has said, it's the method to use when you don't want to generalize your operation.

Their usage has broken down this way in RESTish services:

  • Usually, create has fallen into the POST camp, because of the idea of "appending to a collection." It's become the way to append a resource to a list of resources.

However, POST is also the "data processing" method, so it's also applicable for ANYTHING ELSE YOU WANT TO DO. If you want to drive a battleship through a loophole in REST, use POST.

Taken together, POST is useful for create, because you can say "process this (incomplete) data, and append it to this list resource".

  • The semantics of PUT are much more specific. PUT is the "make it so" method. So if you have a complete representation, and a complete URL, then you PUT it and "make it so". If it doesn't already exist, the service will create it.

So, yes, both PUT and POST can be appropriate for create. Even for update, you might want to POST a piece of data for the resource to process. You can't draw a bright-line definition between CREATE / UPDATE and PUT / POST.

I've seen lots and lots of people try to map CRUD explicitly to the HTTP methods, but it always breaks down, because a) HTTP follows a "update or create" model and not a separate create and update model, and b) the breadth of POST is so large. Also, there are subtleties in the way data is processed that CRUD misses -- like identifier generation.

...

For example, let's say the Galactic Police Academy has a REST service. They have a Cadet resource & you can GET a Cadet by their helmet # for their service details.

GET http://galacticpoliceacademy/cadets/12345

All the Cadets are another resource that retrieves a list or collection of cadets:

GET http://galacticpoliceacademy/cadets/

Notice that the individual GET just adds information to the collection resource.

Now, if I get accepted to the Galactic Police Academy, I don't have my helmet # yet, so we'll POST my information to the collection.

POST http://galacticpoliceacademy/cadets/

{ info: "my info" }

Which will process my information, assign me a helmet number, and add me to the collection. Now the collection of cadets has 1 more item (i.e. me), and I can GET my details using my newly assigned helmet #. I can also pull the list of cadets, and I will be there in the list.

  • Some cadets transfer from the Provisional Frontier Militia, and already have their own helmets. They can just be PUT into the /cadets/ collection directly, since they already have a helmet number. The helmet numbers are unique, so they won't collide with another cadet, and they'll just be put straight into the list, as-is.

  • (!) If the asteroid that the academy is on gets blown up by space criminals, and we need to rebuild on a new asteroid, then I could PUT a copy of the existing list, or PUT a record for each of the survivors, and in the end I'd have a list of cadets that looks exactly like the data I have. Then I could start POSTing as I refill the ranks.

  • There's a surge of patriotism after the attack on the Academy, resulting in a large number of new recruits. We can POST a list of new recruits (without helmets) and the New Academy service will append each to the list and assign each of them a helmet #.

So your example of 10 / 11 items in a resource collection is right on -- that's correct behavior. Usually I don't mix PUT and POST for create for a particular resource, but the HTTP semantics allow it.

Related Topic