The goal of this post is to try to help you figure out which HTTP verb:
POST is more appropriate to use when adding and updating resources.
Before we can get in to the details of which HTTP verb to use when, we first need to understand the type of “back end” or “server” or “service” we are trying to add the RESTful API to. For the purposes of this post, we will refer to the service providing the API as the “Resource Archetype”.
To start, we need to distinguish the differences between the two basic types of resource archetypes, namely, a collection and a datastore or “store” for short.
- A collection is a server-managed directory of resources. This means that clients may propose the addition of a new resource, but it is up to the discretion of the server whether or not to add or update the requested resource. If the server decides to add the resource, it will reply to the client with an
IDthat is associated with the newly created resource.
For the purposes of this conversation, we are not going to get in to the details of how the server provides the ID to the client, it is out of the scope of this post.
- A store is a client-managed resource repository. This means the client can Create Read Update and Delete resources on its own terms without any interference from the server. When interacting with a store, the client is responsible for assigning an
IDto the resource and managing the workflow around that task.
These terms feel too abstract, lets walk through two concrete examples to fully illustrate the two concepts.
Firstly, lets discuss a collection. The simplest form of a collection is a middleware stack on top of a physical datastore. For our example, the physical datastore is a NoSQL database, lets say Riak. Sitting on top of Riak is Spray and Akka, which provide a RESTful middleware stack. For the purposes of this example, all you need to know about Spray and Akka is that Spray provides an API to accept RESTful requests and reply to them, and Akka provides an abstraction around the physical transport between Spray and the actual socket. The main point of all this is that Spray is acting as the middleware/business logic, and it will be handling the request and determining if Riak will be updated.
Try not to get bogged down understanding these technologies if you are not familiar with them, try instead to substitute a framework/database that you are familiar with, as it doesn’t change the context of this example.
Now lets set up our example store, which ends up being a lot simpler than the collection, mainly because there is no middleware between the physical datastore and the client. So following the example of the collection, the store would simply be a Riak instance.
Now that we have a clear understanding of the difference between a collection and store, we can now discuss the details of when to use a
PUT vs a
POST when creating or updating a resource.
When interacting with a store:
PUTmust be used to add a new resource, with the ID specified by the client.
PUTmust also be used to update or replace an already stored resource.
The reason you
PUT to add a new resource to a store is because the client has full control over the details of the resource. The store is acting on behalf of the client. On its own, the store has no notion of what the data means. Thus it makes sense that the client has the ability to put things in the store, and then to update them, the client simply puts the resource again. This is another way of saying the request is idempotent.
When interacting with a collection:
POSTmust be used to create a new resource, and the collection provides the ID to the client.
PUTmust be used to update or replace an already stored resource.
The main difference here is that since the collection potentially has a middleware layer, and some sort of business logic, the server has the ability to determine if the request is valid or not, and therefore, it is possible that the client can
POST (request) the creation of the new resource, and not get back an
ID, meaning the request failed. Another thing to take notice of is the fact that no
ID gets passed from the client, because it is assumed that the server is handling this logic.
If you take a step back to think about our above collection example, it is possible that Spray has many different clients, besides the RESTful one. That is why it needs to manage the notion of identity. Whereas, in the store example, if Riak is exposed to the client directly without a middleware, chances are, that Riak database is meant only for the RESTful client.
Here is a additional example taken directly from the Riak documentation that also illustrates the point that when a client is providing an
ID, the request should be a
PUT, because the client is literally putting the resource in the store. Riak also has the capabilities, to act as a middleware, and provide the
ID to the client, and of course this request is a
PUT /buckets/bucket/keys/key # User-defined key POST /buckets/bucket/keys # Riak-defined key
As always, please feel free to comment on this post or email me with any comments, questions, or concerns.
Thanks for reading.