How Containers Work; or, when do I use PUT vs. POST

Introduction

An extremely common misunderstanding about REST is when one should use the PUT vs. POST methods. For some of us hardcore REST types, this is a no-brainer, so it seems odd - to me at least - that people have trouble with it. But then I remember that not everybody has the same mental model of how REST's generic interface works. Hence this note.

Background

This may possibly be a case of having a hammer and seeing everything as a nail, but I have found it very useful to think back to previous compound document, containment based component frameworks. I'm thinking specifically about OpenDoc, Taligent, OLE, Java Beans (Glasgow), Linda/JavaSpaces. Now, not all of those technologies are what I described, but each of them helped me form my model.

The Model

The model of how stuff happens with REST's generic interface is based on resources (or objects, if you like), and containers. Of course, containers are themselves resources, ala CompositePattern. Now, each resource has a type associated with it. It's a late-bound (aka dynamically bound) type of course, meaning that the type is orthogonal to the interface, or in other words that you discover the type after you access the resource. With REST, this is done with a GET (or conceivably a HEAD if you use the Resource-Type header).

Containers are, like their name suggests, resources which "accept things into them" if you like, the way that "add" works with Glasgow Beans, or "write" works with JavaSpaces. The resource-centric view of them suggests that their state is usually some function of all the things that they have accepted into them since their initialization. So for example, the current state of a mailing list archive is a function of its initial state (some banner describing the list) and the set of all messages which have been sent to the list.

Containers can do all sorts of interesting things, as you might imagine. The state of the container can change in completely arbitrary ways depending upon the information they're asked to contain, plus any other information they feel is relevant (current time, phase of the moon, etc..). In addition, the form of interface that they present can be quite rich; certainly the HTTP interface is, with features such as the 201 response code for signalling the creation of new resources subordinate to the container.

An Observation re the Container/Resource Relationship

One of the little things you'll notice about this model as applied to the Web, is that not only are most containers also resources (per the CompositePattern), but most resources are also containers. That is, for every resource, you can conceptualize a reason for it to also be a container for something. This is quite different than was seen in those older technologies, but I can't really think of any reason why this is so, or that the Web changes anything. I think it was just a missing feature of those systems. But for whatever reason, it seems more obvious to me that this is OK.

PUT vs. POST

Bringing this all back to PUT/POST, hopefully it should be clear that PUT's job is to set the state of some resource explicitly, and that it does this to the exclusion of any existing state that might be there, i.e. you can't use it to do an incremental update of a single resource. It also holds for containers. If you PUT to a container, you are attempting to overwrite the state that was constructed from all the previous POSTs to it. So to reuse the mailing list example, if you PUT to the mailing list, you'll be overwriting the index of the archived messages (since the messages themselves have their own identity).

POST's job is simply to logically add something to a container.

Another not-so-obvious thing about PUT vs. POST is that for PUT, since you're trying to replace the state of some existing resource, you have to know the URI of the thing that you're replacing. With POST, you send data to a container, and if it's the right type it will create a new resource and tell you about it with a 201 response. When you also factor in that URIs should be opaque, and clients shouldn't typically be constructing them unless they're following orders (like a GET form) or the authority doing the PUT happens to also run the server, a rule of thumb falls out; if you want to create a resource, POST a representation of its state to a container that will assign it a URI.

See Also