REST is a very flexible and at the same time, powerful methodology used for software architecture design. But this flexibility gives more space for design mistakes. Unlike SOAP that can transfer data via multiple protocols, REST interaction is done completely via the HTTP protocol. It uses HTTP verbs (or methods) to express the intention of operations.
Most commonly used verbs in the REST world are:
- GET
- POST
- PUT
- DELETE
In many cases, developers have to map those verbs on CRUD operations. Honestly, this mapping is quite a difficult task itself and moreover has no single definition from the REST side. The first and the last verbs are pretty obvious and self-explanatory: data retrieval and data removal. But one very popular problem is related to the remaining POST and PUT. In general, very often there is a decision problem: which operation to use for data insert and which – for data update.
As it was previously mentioned: REST is flexible, and it does not force you to follow any strict rules and moreover has no constraints. Thus POST and PUT can be used interchangeably (most important here is to be consistent within the project for all endpoints).
Here is a couple of opposite examples from quite influential IT representatives:
Company | Create Method | Update Method |
---|---|---|
Oracle | PUT | POST |
Amazon | PUT or POST | POST or PUT |
IBM | POST | PUT |
Now it looks very confusing. And the choice turns to be even more difficult. But there are some hints that can help to decide which way to go.
HTTP Specification
First of all, as a starting point in this investigation can be the statement that says: REST is based on HTTP. So HTTP specifies all the verbs used by REST and related details. The most relevant to the current topic term taken from the specification is idempotence.
Methods Idempotence
In short words this is a characteristic of an action (or method) that ensures that result of execution is the same no matter how many times it was performed: one or more.
According to the specification
- PUT is idempotent;
- POST is NOT idempotent.
This definition gives more clarity and helps to decide on a particular verb to be chosen. In fact, there is still no single answer to every case but depends on the particular implementation it can be properly selected.
For example, there is a system that persists users. The corresponding API accepts incoming requests that contain the user’s data. In case if the data storage behind is a regular RDBMS then it requires for every user to have a generated ID. Plus there can be a requirement to persist the date and time when a particular user has been created. Both mentioned properties are not a subject of an incoming request, but rather work for the back-end behind. If this operation that creates a user will be executed 10 times there will be 10 different records with 10 different ID and creation timestamps. This fact leads to a conclusion that creation operation is not idempotent thus the most suitable method here is POST.
Another example, the same system changes the email address for the users. Now API accepts similar content but email property of it is variable. In case if this operation will be done once, two or more times there will be the same result in the end: user with a new email. And this is a behavior specific for idempotent operation, which is PUT.
Idiomatically PUT must be used for the full update or in other words “entity replacement“, and partial update must be done via PATCH, but due to its complexity (request content must be formed in a tricky way) the latter is often neglected and replaced with PUT. In the example above it is done as well, but just for the simplicity.
At this moment it must be clear what to take into account to decide on a particular HTTP operation. But there is one more aspect which is a consequence of the explanation above: resources representation.
Resources Representation
Another important statement from the specification is following:
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. … In contrast, the URI in a PUT request identifies the entity enclosed with the request …
Having in mind examples from the previous section the URIs for each API must be following:
- User creation resource is represented in a common way, and its purpose is handling the requests of the same type (method: POST): /user
- User update resource is represented in a specific way, it must contain the exact reference to the particular entity that is a subject of the current request (method: PUT): /user/{user-ID}
Exceptions
One may say that in fact it is difficult to ensure that the operation complies with specified conditions. For example, if the previously discussed system allows viewing user’s data it can also persist the timestamp when the profile was viewed lastly (or the number of views). And this causes a change to the resource. But the main rule that helps to resolve this kind of discrepancies can again be found in HTTP specification.
Naturally, it is not possible to ensure that the server does not generate side-effects … The important distinction here is that the user did not request the side-effects…
According to this statement it is easy to imagine cases when POST and PUT and interchangeable:
- PUT can create resources if the request to the server creates a subordinate of the specified resource, using internal server-side processing. For example, user’s email update can cause a change history record being created.
- POST can update resources if the request to the server updates a subordinate of the specified resource, using internal server-side processing. For example, order created for a user can cause a change to the available balance on the user’s account.
Links
Be First to Comment