PUT for CREATE
Before we consider examples of using PUT for Create let’s take a peek at the section 9.1.2 of the HTTP RFC first.
9.1.2 Idempotent Methods
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests are the same as for a single request. The methods GET, HEAD, PUT and DELETE share this property.
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests are the same as for a single request. The methods GET, HEAD, PUT and DELETE share this property.
In plain English this simply means that regardless of how many times I call the same operation, it should always produce the same result. In case of GET and DELETE this is quite easy to understand; e.g. once I call a DELETE on a resource, it will get deleted and will remain deleted no matter how many times I keep calling delete on it. However, things are not that obvious with PUT. Suppose you are working on an order processing system and considering using PUT to create an order. Your call would look something like this:
Client Request
PUT /myapp/orders
{
“productName”:”my best product”,
“quantity”:”2”
}
Server Response{
“productName”:”my best product”,
“quantity”:”2”
}
/myapp/orders/123456
Making the same call for the second time will just generate another order, thus violating the principal of idempotency mandated by the spec.
For our next scenario consider a user registration component where your REST client knows the identifier of the user it is going to create beforehand.
Client Request:
PUT /myapp/users/bartsimpson
{
“nameFirst”:”Bart”,
“nameLast”:“Simpson”
}
Server response:{
“nameFirst”:”Bart”,
“nameLast”:“Simpson”
}
/myapp/users/bartsimpson
This would be a valid creation use case using PUT. However, the key here is that you’d need to send all data that will be stored with your user resource. This is the only way to guarantee that the server’s state would be identical whether you call this method ten or hundred times.
PUT for UPDATE
The logic above applies to the UPDATE case as well. You can use PUT to update your resource but your REST client would have to submit all fields associated with the resource in the PUT request.
So, when using PUT for either CREATE or UPDATE you have to always include all data about your resource in the request body.
POST for CREATE and UPDATE
Unlike PUT, POST is not defined as idempotent; hence there is no restriction of always returning the same result. This means that you can freely use POST for both creating and updating using partial information about your resource.
POST /myapp/users/bartsimpson
{
“nameFirst”:”Bartholomew”
}
{
“nameFirst”:”Bartholomew”
}
However, to better understand use cases for POST let’s take a look at the spec again…
9.5 POST
The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.
The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.
As defined, POST is not really meant for partial updates of a given entity. Instead, it is meant to add the entity being submitted to its enclosing object. Examples of such requests are: adding a new member to a collection, posting a message to a bulletin board, etc.
POST /myapp/powerplantemployees
{
“unid”:”homerabesimpson”,
“nameFirst”:”Homer”,
“nameLast”:”Simpson”
}
{
“unid”:”homerabesimpson”,
“nameFirst”:”Homer”,
“nameLast”:”Simpson”
}
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
Note also that the response from the POST method might not necessarily result in a newly created resource that can be identified by a URI. In this case the server should return 200 (OK) rather than 201 (Created).
So, what is the best way to do partial updates? Read on…
PATCH
PATCH is the HTTP method you would use for partial updates. It is neither idempotent nor safe; i.e. you do not have to send the whole representation of your resource to the server, plus it allows side effects such as changing the state of other resources as a result of patching. In addition, PATCH is an atomic
operation which means that no matter how complex the implementation, it should roll back in the case of errors.
This sounds great, but do not jump in trying to implement something like this
PATCH /myapp/users/bartsimpson
{
“nameFirst”:”Bartholomew”
}
{
“nameFirst”:”Bartholomew”
}
Instead, let’s have a closer look at the spec which states:
The PATCH method requests that a set of changes described in the request entity be applied to the resource identified by the Request-URI. The set of changes is represented in a format called a "patch document" identified by a media type.
What this means is that though PATCH is intended for partial updates, you do not use it to send partial representations of your resource. Instead you send the description of changes.
Considering that we live in a world of standards (well, at least we try), the next question that comes to mind is – what do these description of changes look like? And more specifically, how do they look in JSON?
Another standard, called JSON Patch was proposed about a year ago and just turned into a RFC. According to JSON Patch the example above would look like the following:
PATCH /myapp/users/bartsimpson
{
“op”:”replace”, “path”:”/nameFirst”, “value”:” Bartholomew”
}
{
“op”:”replace”, “path”:”/nameFirst”, “value”:” Bartholomew”
}
As you can see, this patch document has three main fields:
- op – Describes the operation to be performed on the path. In this case we are using replace
- path – A reference to a location within the target document
- value – Value to be used in the operation. In this case, a replacement value
Check out the RFC for more details and other examples.
SUMMARY
As you have seen, creating one-to-one mapping between common HTTP methods and CRUD operations is not quite accurate, especially when it comes to PUT and POST where every use case requires careful consideration of many variables such as the nature of the request, traffic constraints, performance, firewalls, time, etc.
In the table below I have summarized the points made in this blog so that the table can be used as a quick reference to decide which method to use and why.
| CREATE | UPDATE | |
| PUT (idempotent) |
Resource identifier is known beforehand. All data can be submitted in the call. No traffic or performance constraints. Each request is going to either create or completely replace the state of the resource on the server | |
| POST | The target of the call is an object enclosing the resource submitted in the body of the request (e.g. adding a member to a collection) | |
| PATCH | Updates can be sent to the target resource in the form of a patch document describing operations performed on paths with submitted values. |
AFTERWORD
Many architects hardwire PUT and POST to CREATE and UPDATE respectively (or vice versa). After all, if neither method fully covers all possible scenarios then why bother about the details of idempotence, especially when there are no sound alternatives.
Even with JSON Patch becoming a standard, there is no framework (at least I am not aware of any) which would allow you to easily implement standards compliant patching. This means that, for the time being, we would continue using PUT/POST for all CREATE/UPDATE operations, which is well justified in isolated projects coupled with the time constrained environments in which we all work. However, should you develop a public facing REST API, or one that is going to be consumed by more than one type of client, the decisions made early in the design will validate the extensibility of your framework, so following standards would become imperative.