RESTful API Design - POST vs PUT vs PATCH

Featured

In a previous article, we had a look at the basics of REST API design. In that post, we mentioned the various HTTP methods, but we didn't dig deep and explore the difference between HTTP POST, HTTP PUT and HTTP PATCH. In this blog post we'll not only explore these differences but also discuss idempotent and safe HTTP methods.

There are some important differences between these three methods, and often it is the base of confusion that developers are having.

To better explain the differences, we'll be using a simple analogy. We'll imagine that we have an empty piece of lot (land) on which we have the option to build multiple houses. These houses will be placed on by parcel number, and we are just about to plan out which house to build where.

Translating the above to REST would mean that http://domain.com/house using HTTP POST would be constructing a house on the land at parcel 1. (1 is an auto-generated system ID)

POST

We know that POST allows us to create a resource. So to build a house, we need to gather the requirements of the house, which looks like this in a JSON format:

{
  "front_garden": true,
  "back_garden": true,
  "windows": 3,
  "doors": 2,
  "garage": true
}

Invoking http://domain.com/house and sending the above mentioned JSON structure as a payload would place a house with those properties to the land, at parcel location number 1. (Here the parcel location is the equivalent of a system generated ID.)

If we wanted to create another house, we could create another payload (could be the same, could be different) and invoke http://domain.com/house to place a house at parcel location number 2.

The takeaway here is that no matter how many times we invoke POST it will always create a new house at a different location - that is - it will always generate a different (unique) system ID.

PUT

Let's see what happens when we issue a PUT request. With PUT we again need to specify a payload, and there are a bunch of scenarios that can happen. For the sake of this discussion let's issue the following request: http://domain.com/house/1 with this payload:

{
  "front_garden": true,
  "back_garden": true,
  "windows": 13,
  "doors": 3,
  "garage": false
}

This means that we want to PUT the house defined in the payload to the land identified by parcel 1.

But we already have a house at this location that we created as part of a POST request. What will happen is that we'll replace the entire resource with whatever is in the payload.

This means that if our payload contains only the following:

{
  "windows": 8
}

the result is going to be a house that will only have a windows property and nothing else since we overwrite everything with the content of this new payload.

Remember that for PUT we need to define the entire resource at all times, otherwise we could end up with an undesired result.

The question is of course, what happens when we do a PUT against a resource that does not exist. In this case the resource is going to be created. So going back to our analogy, if we send a payload to the endpoint of http://domain.com/house/5 the resource should be "PUT" in place (created).

PATCH

Using HTTP PATCH means that we'd like to apply a partial update to the resource. This means that whatever we have in our payload will become part of an existing resource.

Let's assume that we have the following house:

{
  "front_garden": true,
  "back_garden": true,
  "windows": 13,
  "doors": 3,
  "garage": false
}

and we apply the following patch update:

{
  "windows": 8
}

The result is going to be the following:

{
  "front_garden": true,
  "back_garden": true,
  "windows": 8,
  "doors": 3,
  "garage": false
}

If we have a property in the payload that doesn't exist in the resource, PATCH will add that property to it.

Please note that when calling HTTP PATCH on a resource that doesn't exist with a payload, the resource should not be created. The request should fail. This is significantly different from how PUT works.

Idempotent

Often when discussing REST APIs the term idempotent and idempotence pop up.

Idempotence is a mathematical property that is used both in computer science and mathematics. It means that if we apply a change using an operation N number of times, the end result of the operations should always be the same.

In light of the above, we can categorise HTTP methods to be either idempotent or not.

HTTP GET is idempotent. This is due to the fact that issuing the same GET request (identical requests) will always behave the same - that is - return the same resource.

HTTP POST is not idempotent. If we think about a simple scenario, we use POST to create resources on the server. Executing the same POST request multiple times results in multiple resources created in the server, each having a unique ID of some sort (like an ObjectId in the case of MongoDB). Because how each invocation to POST yields a different result, we can say that it is not idempotent.

HTTP PUT is idempotent. Updating a resource will always yield the same result - it's going to be either the creation of the result based on the payload (if the resource did not exist) or the resource is going to be updated - and the update is always going to be the same.

HTTP PATCH is a tricky one. Generally speaking, it is not an idempotent HTTP method, but depending on implementation it can be. An example of why it's not idempotent would be a PATCH request against an /employee endpoint to change the salary property where the employee's salary is 10 to 15. This will change the resource, now any additional request that says 'change the employee salary where the salary is 10' will fail since that original resource has now been changed.

PATCH can be made idempotent by using the ETag and If-Modified-Since HTTP headers.

Safe Methods

In the context of RESTful APIs, we not only talk about idempotent HTTP methods but also safe HTTP methods. A safe HTTP method means that the method itself never modifies nor changes a resource.

Summary of Safe and Idempotent HTTP methods

Here's a table overview of some of the most used HTTP methods indicating their safe and idempotent status:

HTTP Method Idempotent Safe
GET yes yes
POST no no
PUT yes no
PATCH no* no
OPTIONS yes yes
HEAD yes yes
DELETE yes no

* PATCH can be made idempotent; please see above how.

Summary

In this article we discussed using a down-to-earth analogy the differences between HTTP POST, PUT and PATCH and we also examined the idempotent and safe properties of various HTTP methods.