6

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 )?

  • Really, read the HTTP spec for the methods. It's very readable. I usually feel put out when people say "Read the spec", but in this case it's easy to read and sheds a lot of light on the issues. – Rob Jun 3 '14 at 19:40
  • 1
    Also, "Request-URI in POST is interpreted by server as the URI of the service" ... sort of. In these examples the URI still identifies a Resource, it's just a collection resource rather than an individual resource. But sometimes the resource is a processor noun, which is more like a service. In all cases, though, it's some thing or idea that the URI identifies. A URI is kind of like the Primary Key of the Internet. – Rob Jun 3 '14 at 21:00
15

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.

  • 1
    Did you mean POST/PUT not POST/POST? – paul Jun 3 '14 at 18:07
  • If you have time, could you please see my reply? – bckpwrld Jun 3 '14 at 18:57
  • lol from the HTTP spec, POST: "Extending a database through an append operation." ;) – Rob Jun 3 '14 at 19:38
  • 1
    Not at all! It's a good question, and has taken years for the industry to more or less settle down on an answer. And the answer is still incomplete -- the use of POST remains a blurry area. I went through a couple years of REST Hell fighting mano a mano over these issues before I felt I had a handle on it. Let me add a little to my answer & see if that helps. – Rob Jun 3 '14 at 20:10
  • 1
    Sure. If your helmet meets Academy standards. But the standards are pretty high. – Rob Jun 3 '14 at 22:38
2

I asked a nearly identical question here

Spring REST follows your model (PUT = client supplied resource id). But they admit that it was a serious debate. Referring to the spec isn't good enough. It just isn't clear on this issue (or at least, clear enough).

As for partial updates, my understanding is that, for those, you would use the PATCH command

2

You need to consider the distinction between standards/specifications vs. guidelines.

Standards/Specifications:

Conformance to specifications is expected and assumed by most browsers and other clients. They handle requests assuming that the spec holds true. Some of these "rules" are specified here: Hypertext Transfer Protocol. The HTTP specification goes into more detail - recommended reading for anyone doing web development.

For example, for the HTTP specification, browsers assume that GET would have no side effects, and so cache most GET requests to save bandwidth and server calls. PUT is meant to be idempotent, so browsers are allowed to repeat PUT calls without any confirmation from end-users (not so for POST).

Not following these standards is of course possible, but you may break the behavior of compliant clients and possibly cause hard-to-track bugs.

Guidelines/Conventions:

The other part that you mention are guidelines. They are used for uniformity and to make sure that other people can understand/follow your API easily. The mapping of CRUD to REST calls that you mention, is one such guideline. It does not address all scenarios, can sometimes be bad design, but is still a useful abstraction if used judiciously.

So the typical mapping is as follows:

GET is an idempotent method which should not take an input payload, only query params. Hence it is usually used for queries and read operations on the server.

PUT is also idempotent, but can take a payload body. Hence, its semantics are used for doing a full replace/update of a resource. If you repeat the call, there is no change because it is a full replace anyway. PUT can also be mapped to a create where the client specified the id of the new resource. For example, you can PUT to the following address with the user's details in the body:

PUT http://www.example.com/users/<new_user_id>
{
    ...
}

This should still be implemented as idempotent - a repeated call would create the same user with the same id, essentially no effective change.

PATCH is a new addition to the HTTP spec. It can be used to send partial changes and merge them on the server. This does not have widespread adoption yet but should be the way going ahead.

POST is more of a generic "everything else" method. It has no restrictions such as being idempotent. In many cases, it is mapped to sub-resource creation. For example, you could POST a user's details to the following URL to have a new user created for you:

POST http://www.example.com/users
{
    ...
}

The convention is that the server creates the user id and returns it to you. Later, you can access the created user with:

GET http://www.example.com/users/<created_user_id>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.