To PUT or to POST… that is the question

To PUT or to POST… that is the question
November 23, 2015 Manuel Ortiz
hamlet

In this article, I introduce and discuss the following three best practices related to POSTs and PUTs in a RESTful service context:

  • If your server auto-generates URI’s or Id’s, ALWAYS use POST to CREATE and PUT to UPDATE. NEVER use PUT to CREATE due to loss of idempotence.
  • If your server permits the modification of Id’s or URI’s and does not auto-generate them, ALWAYS use PUT to CREATE and UPDATE.
  • If your server both auto-generates Id’s or URI’s and allows for their modification, use POST to CREATE and PUT to UPDATE. Otherwise you can also only use POST to CREATE and UPDATE.

PUT vs POST vs Auto Generated URI’s

Yes, one of those classic RESTful API related questions:

What HTTP verb should I use to insert and/or to update a resource: PUT or POST?

Well, the answer is: there is no correct answer, it depends on your implementation. A brief research on this topic will result in lots of different implementations and recommendations on how and when to use which verb. For that reason, I will not go into an in-depth analysis of the particularities of the mentioned verbs since there is already so much info on the internet from sources much more qualified than me ;). My intention is to give a brief overview of what to use when, specially depending on how your server and/or repository responds to the requests and identifies new vs. existing resources.

[ NOTE: If you want more info, I recommend reading this StackOverflow question to get a well-explained insight of the best practices currently in use. Also, another good source is this draft of the HTTPbis Working Group which explains the reasons for the verbs and their expected usage. ]

So let’s start with the simplest definition of what PUT and POST are according to the HTTPbis Working Group Draft:

  • POST: The POST method requests that the origin server accept the representation enclosed in the request as data to be processed by the target resource.
  • PUT: The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload.

In summary, it could be concluded from these “definitions” that while POST can be used to CREATE, PUT can be used either to CREATE or to UPDATE. However, it is not as simple as this, as there are other factors that must be considered in practice. Let’s see:

“Idempotency”… a pretty word for a simple concept

Maybe you have heard someone somewhere haughtily say “PUTs are idempotent“. Well, they are right! According to the HTTP/1.1 Specification, PUT requests MUST be idempotent. In simple terms, this means that if a client executes the same PUT request over and over, the effect will be the same as if it had been executed only once. In other words, only the first request will be the one causing the modification.

On the other side, POSTs should not be considered idempotent (therefore they are potent). What this means is that if you make the same request 10 times, 10 new resources will be created, even if they are exactly the same.

To best understand this, let’s give an example:

Assume you have a Person resource in your application defined by the following structure:

You want to create or insert a new person called Peter Griffin into the repository using a RESTful request:

You can do this operation using either a POST or a PUT request. If executed only once, either of the verbs will produce the outcome of a Peter Griffin being successfully created. However, let’s say that, for some reason, the request was sent 4 times using POST. Well, due to the POST verb’s potency characteristic, you have created 4 Peters! On the contrary, if you decided to use a PUT request and the request was sent 4 times, only 1 Peter was created due to the idempotency property of PUT.

Let’s now say that you want to change (update) that Peter Griffin Person‘s first name and last name properties to Homer Simpson. You will then send a request with the following payload:

If you were to follow strictly the guidelines given before, you would know that you can’t use a POST verb for this operation. But let’s assume you did, well, probably you know already what will happen (but just for the sake of repetition): a new Person object will be created in your repository.

[ NOTE: There is strong debate on whether POST can also be used to update a resource, since it is more “backward compatible” with browsers and servers than PUT is, among other reasons. ]

So, you will then have a Peter Griffin and a Homer Simpson:

On the contrary, if you had used a PUT request, the Peter Griffin Person will have been updated with the Homer Simpson first and last names as was desired:

By now, you surely think “Why would I ever use POST? PUT is always better!” Not so fast! Let’s look at the next important factor:

URI or ID auto-generation

Nowadays, RESTful API’s are widely used to access and manipulate (CRUD) entities of an application that are mainly stored is some kind of persistence or repository. In most cases, those entities have a primary key or unique identifier that is auto-generated by the repository itself or by the application that consumes it. This auto-generation of the unique identifier (and in consequence of the URI – e.g.: http://myservice.com/api/{uniqueId}) of an entity is an extremely important factor in considering the adequate implementation to follow when deciding which HTTP verb to use for inserting and/or updating a resource.

To illustrate this, let’s go back to the Person entity of the last example, but let’s add to it an unique identifier or index named id. This id will be auto-generated by the repository or server and cannot be modified:

Let’s also assume that you want to insert the following person:

Then:

  • If you use a POST request, a new Homer Simpson person with a randomly generated id will be generated and returned as a Response object so that the client knows what is the new object’s unique identifier.
  • The same would happen if you use PUT and your server permits creations using PUT.
  • For both verbs, if a non-existing or null id is sent, the server will always create a new resource with a new random id. If a valid, pre-existing id is sent, POST will disregard that idand create a new resource with a new random id, however PUT will update the object with the request’s contents after finding that it exists.

The result of all of this is that the necessary idempotency of PUT is lost if your server auto-generates the id‘s and does not permit their modification. Therefore, the first “best practice” that can be extracted from this example would be:

If your server auto-generates URI’s or Id’s, ALWAYS use POST to CREATE and PUT to UPDATE. NEVER use PUT to CREATE due to loss of idempotence.

Now, let’s suppose that your server does not auto-generate Id’s or URI’s but allows their creation and/or modification. You want to insert the following Person:

This is what will happen given the following use cases:

  • If you use a POST request, the Peter Griffin Person with an id of 5 will be created. Subsequent calls to POST with the same id will update the resource but will not create new ones. A PUT request would behave exactly the same way.
  • If you POST or PUT a resource with an invalid id such as null, no change will be executed, and an error response will most likely be returned, however, the HTTP status codes may change depending if it was a PUT or a POST (but that is outside the scope of this article).

Hence, in this example, PUT and POST will cause the same results and both can be considered idempotent. However, some subtleties between both will exist depending on the implementation and or technologies used (e.g.: if the request is made by a browser, it will warn the user if he or she tries to reload POST request; this will not happen for a PUT). Therefore, even though you could hard wire the server to only accept creations via POST and updates via PUT, for the sake of simplicity of your API, only go with PUT and deactivate POST. The second “best practice” then goes as follows:

If your server permits the modification of Id’s or URI’s and does not auto-generate them, ALWAYS use PUT to CREATE and UPDATE.

Finally, let’s assume that your server or repository allows the modification of Id’s or URI’s and also auto-generates them.

Given the following use cases, the expected behavior will be as follow:

  • If a resource with an invalid or null id is sent with a POST request, a new resource will be created with a randomly generated id. The same will happen with PUT. Subsequent requests will result in new resources being generated all with the same data but with different id‘s. (Here PUT and POST are not idempotent).
  • If a resource with a valid but non existing id is sent within a POST request, a new resource will be created with the specified id. Subsequent requests with the same id will result in updates to the resource, since the id is valid and existent. (Here PUT and POST are idempotent).

As can be seen, in these cases, the idempotency of both verbs cannot be predicted, as it depends in the validity and/or existence of the resource’s unique identifier. Therefore, the third and final “best practice” will be:

If your server both auto-generates Id’s or URI’s and allows for their modification, use POST to CREATE and PUT to UPDATE. Otherwise you can also only use POST to CREATE and UPDATE.

Conclusion

As discussed, there is no correct or incorrect way to use POST or PUT to perform CRUD operations in your RESTful API. However, adopting some best practices for each possible use case or situation will greatly help and streamline the way you implement your solutions and take away all those hours of discussion that every software developer is accustomed to when it comes to designing and constructing these types of interfaces.

In this article, three “best practices” have been introduced whose usage depend in how your server and/or repository manages the resources’ unique identifiers (Id’s or URI’s). Here are them again for the sake of summarizing:

  • If your server auto-generates URI’s or Id’s, ALWAYS use POST to CREATE and PUT to UPDATE. NEVER use PUT to CREATE due to loss of idempotence.
  • If your server permits the modification of Id’s or URI’s and does not auto-generate them, ALWAYS use PUT to CREATE and UPDATE.
  • If your server both auto-generates Id’s or URI’s and allows for their modification, use POST to CREATE and PUT to UPDATE. Otherwise you can also only use POST to CREATE and UPDATE.
Loves beach and beer (specially Medalla). Software Engineer and Co-founder of Mozart Analytics, and award winning technology startup Citamed.net. Passionate about software engineering with strong knowledge and years of experience in cloud services and architecting for the cloud. Works as the CEO of Citamed.net in San Juan, Puerto Rico. Lives happily with his wife and dog.

0 Comments

Leave a reply

Your email address will not be published. Required fields are marked *

*