REST Best Practices: Optimizing Content Retrieval With Conditional HTTP Requests

As promised in our previous article, this post will be about the ways to optimize the response time from a web service when a client needs to read a resource. We are going to achieve this by not reading information on a resource if it has not changed. This helps developers create faster web applications.

The Problem

Suppose you want to create a web service that reads information on a resource only when it has changed. For instance, think of an application that allows you to manage calls in a call center. This application lists all the calls in the system in a page and adds new calls to the list in real-time. Since calls can take more than a few minutes, a time-frame during which no changes occur, the application will reload the list only if new calls occur or a call is closed.

Making Conditional HTTP Requests

To solve the problem, the web service and the application communicate by passing conditional HTTP headers. Some of these headers, Last-Modified and Etag, are not new to you as you’ve already read about them in a previous article. In today’s article, we’ll be introducing two new ones, namely If-Modified-Since and If-None-Match.

So, if you want your web service to support conditional HTTP requests, you have to design it to return the Last-Modified and Etag conditional headers. Clients of the web service receive these headers and save them. At a later point, when clients make the same GET or HEAD HTTP requests and want to check if the information they have is still fresh, they must send the following headers to the web service:

  • If-Modified-Since with the value of the Last-Modified header as received in response to the initial request
  • If-None-Match with the value of the Etag header as received in response to the initial request

If the web service determines that a If-None-Match header was sent, then it compares its value to that of the ETag as saved internally. If the If-Unmodified-Since header is received, its value is compared to the date the representation was last modified. If the checks are false or if the client did not send these headers, the web service must return the Last-Modified and Etag headers to the client and a HTTP response with status 200 OK. If checks prove to be true, an HTTP response is returned with the 304 Not Modified status.

This method does not decrease the number of HTTP requests the client makes to the web service. It might reduce the load on the database and the response overhead, because in many cases it’s not needed to serve a response back, as nothing was changed since the last request. Reducing load on database might be a tricky subject, so we want to discuss this further in a next article – it actually matters a lot how you compute Etag and how you keep track of changes.

Making HTTP conditional requests enables the web server to improve its response time. Applications also save resources, since they are not required to reload the information if no changes occurred.

An Example

Let’s assume that the call center application above decouples its interface from its back-end. The interface is written in JavaScript and the only way it can communicate with the back-end is through a RESTful service. This means that, when it needs the list of calls, it makes a GET HTTP request to the web service. The application expects to receive the Last-Modified and Etag headers in the response received.

# First request that reads the list of calls
GET /call HTTP/1.1
Host: my.callcenter.com

...
# The web service responds with 200 OK and 
# a resource that contains the list of calls
HTTP/1.1 200 OK
Content-Type: application/json
Last-Modified: Sun, 13 Jun 2013 13:00:15 GMT
ETag: "cbd1956fb32c0275f1faccbb6fafff8f"
...

{ "call": [
	{"source": "3334444",
	 "sourceCallerName": "Marry Smith",
	 "destination": "2224444",
	 "destinationCallerName": "John Smith",
	 "answered":"9 Jun 2013 12:34:12"},
	{"source": "5554444",
	 "sourceCallerName": "John Doe",
	 "destination": "6664444",
	 "destinationCallerName": "Jane Smith",
	 "answered":"9 Jun 2013 13:00:12"},
 ]
}

As you can see, the web service returns the Last-Modifed and ETag headers. The second time the application wants to read the list of calls, it makes an HTTP request in which it includes the headers If-Modified-Since and IF-None-Match. The web service compares the values received in these headers with the ones known internally and, if nothing changed, it returns an HTTP response with a 304 Not Modified status.

# Second request to read the list of call
GET /call HTTP/1.1
Host: my.callcenter.com
If-Modified-Since: Sun, 13 Jun 2013 13:00:15 GMT
If-None-Match: "cbd1956fb32c0275f1faccbb6fafff8f"

...
# Nothing changed since the last time 
HTTP/1.1 304 Not Modified
Content-Type: application/json
Last-Modified: Sun, 13 Jun 2013 13:00:15 GMT
ETag: "cbd1956fb32c0275f1faccbb6fafff8f"

To sum up, this is the way you can save web service response time and create faster applications. In one of our future posts we’ll be discussing partial updates as requested by a reader, so keep reading our blog. 🙂

1 Comment

You can post comments in this post.


  • “If the If-Unmodified-Since header is received,” – did you mean If-Modified-Since? This may be a typo because it does not make much sense here.

    Also, thanks for the simple example! It helped a lot to wrap my head around conditional requests.

    Attila Gulyas 9 years ago Reply


Post A Reply