Using HTTP Methods for RESTful Services

REST (REpresentational State Transfer) is an architectural style for developing web services. A primary benefit of using REST, both from a client and server’s perspective, is REST-based interactions happen using constructs that are familiar to anyone who is accustomed to using the internet’s HTTP.

Having said that, one of the trickiest tasks in REST is to choose the right methods. We are all aware of basic HTTP methods like GET, POST, PUT and DELETE. But often make mistakes over their application and usage.

Before we deep dive into types of HTTP methods and their use cases, lets take a look at how they are classified.


Classification of HTTP methods

Based on the operation performed by the HTTP methods, they can be broadly classified into two categories —

Safe methods
These are HTTP methods which don’t change the resource on the server side.
For example using a GET request on a resource URL should NEVER change the resource.
Safe methods can be cached and prefetched without any side-effect to the resource .GET /user/464
-- This will retrieve the user 464. No matter how many times you execute this method, the resource in the server will not be modified or impacted.
Idempotent Methods
These are methods which are safe from multiple calls i.e. they produce same result irrespective of how many times you call them.
They change the resource in server every time you call them but the end result is always same.

    An arithmetic example 
    a = 6; //idempotent
    a++; //not idempotent

If we correlate our DB to an array, then making a push operation will never be an idempotent request. This is because calling it multiple times will result in multiple entries being added to the array.


//if you call this n times, n entries will be added to the array.
users.push({
  name:"Akshay Kumar",
  email:"abc@abc.com"
})
//even if you call this n times, the state will always remain same.
users[464]={
  name:"Akshay Kumar",
  email:"abc@abc.com"
}

Whenever we make changes to the array using indexes, it will always be idempotent. No matter how many times you call this operation, this will always result in the same behaviour i.e set the resource at 464 location.

Now that we have covered the basis on which HTTP methods are defined, let us, deep dive, into the different types of HTTP methods and their use cases.


Types of HTTP methods

GET

Retrieves resources from the server (should only retrieve the resource and should have no other effect).


GET /users/464

GET request is both safe and idempotent.
USE CASE — Fetch a resource or a resource collection from the server.

POST

This HTTP request type is usually used for creating an entity i.e. a resource without an id. Once the request is successfully created, an id of the newly created resource is returned as part of the response to this HTTP request.
For example, following URL will create a new user in the server


POST /users

POST is neither safe nor idempotent.
POST is not idempotent because calling it multiple times will result in a new resource being created everytime.
USE CASE — Create a new resource on the server

PUT

Similar to POST, but used to update an existing resource. You pass the id of existing resource along with the request.
For example, following URL will replace the user with id 464 in the server


PUT /users/464

PUT is idempotent because it only allows complete replacement of a resource.
It creates a new resource if one is not present.
USE CASE — Update the complete resource on the server.

PATCH

PATCH request method applies partial modifications to a resource.
Unlike PUT, PATCH is ideally not idempotent, meaning successive identical patch requests may have different effects.
However, it is possible to issue PATCH requests in such a way as to be idempotent.
To find out whether a server supports PATCH, is the presence of the Accept-Patch header in response.
USE CASE — If you only want to update a single field, use a patch request.

DELETE

Removes the resource from the server. You need to pass the id of the resource to be deleted.
For example, following URL will remove the user with id 464.


DELETE /users/464

USE CASE — Delete the specified resource.

TRACE

Provides a means to test what a machine along the network path receives when a request is made. As such, it simply returns what was sent.
USE CASE — This method simply echoes back to the client whatever string has been sent to the server, and is used mainly for debugging purposes.

HEAD

The HEAD method is almost identical to GET, except without the response body.
In other words, if GET /users returns a list of users, then HEAD /users will make the same request but won’t get back the list of users.
USE CASE — It’s often used by clients who use caching. As it does not contain the actual data, response headers from HEAD request can help us identify if the document has changed since it was last accessed.

OPTIONS

Allows a client to request information about the request methods supported by a service.
USE CASE — Helps us to identify which methods are supported on a resource. One of the popular use case include — checking if CORS is supported by the server or not.

CONNECT

Used to start two-way communications with the requested resource.
USE CASE — It can be used to open a tunnel usually to facilitate SSL-encrypted communication (HTTPS) through an unencrypted HTTP proxy.


POST versus PUT versus PATCH

When I started working on REST, one of the biggest dilemmas I had was, when to use POST and when to use PUT.
The protagonist for the confusion created here is idempotency. A request is idempotent if the side effects of making the request 1 time is same as 1 million times. However when it comes to certain scenarios of post, we can have a request that is idempotent all the time. (i.e it does not create a new resource). This is the reason why POST can also be used to update a resource.
This brings us to the question -

POST versus PUT

In order to decide whether you want to use POST or PUT, always remember two rules —

  1. The endpoint must be idempotent: so safe to redo the request over and over again.
  2. The URI must be the address to the resource being updated. e.g.

PUT /users/464

When choosing between PUT and POST, don’t just say “PUT is idempotent”. Instead look at both of the rules above, and see if we can have a case for PUT. If even one rule is not fulfilled, go ahead with POST.

A simplified example of the above statement can be taken from correlation to array. If you consider your db as an array, POST is similar to doing a push operation, whereas PUT is similar to updating the resource in the array using index.

A Case for PATCH

Technically, the definition of PUT states that — “take this object and replace the entire resource at the URI”.


PUT /users/464
{ 
    name :"Akshay Kumar", 
    email : "abc@abc.com" //only email has changed
}

What it meant was if we had a PUT request and just wanted to update email-id of a user, we will have to send the complete resource object. If we only send a partial resource, the rest of the properties will have null values. e.g.


PUT /users/464
{ 
    email : "abc@abc.com" //only email has changed
}

In this scenario, PUT request should set the email to the new email id and set the name to null as it was not provided in the request. But not all APIs follow this rule because it is a bit harsh and will set the content to blank without the client intending to do it.

This is where PATCH comes to the rescue.

The reason why everyone was still using PUT request for the above request is because, PATCH is relatively new to the REST world. ( PUT was introduced in RFC 2616 document, while PATCH was born in RFC 5789.)

Typically, PATCH is used exactly like PUT, except if we don’t send a name field then it keeps its current value instead of changing it to null.


Closing Comments

Use case for various HTTP methods are defined mostly defined on safety and idempotency. REST is simply a contract between the client and the server, which helps in creating scalable API architecture. You could also use a POST request to get a list of resources (however you should not do it )and use GET to update or create a resource (again this is a bad idea), till the time your API handing is written in that way.


References