Managing an HTTP cache in a RESTful web service

Managing an HTTP cache in a RESTful web service

 Reading resources over the web is always a challenging process in terms of time and network latency. As a result, when you build a web application or web service, the ability to cache and reuse previously retrieved resources is a critical aspect of optimizing for performance. The HTTP/1.1 protocol specification provides a number of features to facilitate the caching of network resources.

In this section, we will discuss the native support in the HTTP protocol for managing the cache of the resources retrieved from the server. Similarly, we will see how the JAX-RS framework APIs embrace the HTTP caching features for managing the cache of the results returned by the RESTful web services.

Using the Expires header to control the validity of the HTTP cache


You can use the Expires HTTP header field to let all entities involved in the request-response chain know when a resource has expired. The Expires HTTP header was defined as part of the HTTP/1.0 specification. You can specify the date and time in the Expires header, after which the resource fetched from the server is considered stale.

The following code snippet shows how you can add the Expires HTTP header to the resource returned by the method:

@GET 
@Path("departments/{id}/holidays") 
@Produces(MediaType.APPLICATION_JSON) 
public Response getHolidayListForCurrentYear(@PathParam("id") 
Short deptId) { //Reads the list of holidays List<Date> holidayList = getHolidayListForDepartment(deptId); //Build response Response.ResponseBuilder response = Response.ok(holidayList). type(MediaType.APPLICATION_JSON); //Set the expiry for response resource //This example sets validity as //Dec 31 of the current year int currentYear = getCurrentYear(); Calendar expirationDate = new GregorianCalendar (currentYear,12, 31); response.expires(expirationDate.getTime()); return response.build(); }

Here is the sample response header generated by the preceding method for the GET departments/10/holidays HTTP/1.1 request:

Server: GlassFish Server Open Source Edition 4.1  
Expires: Sat, 31 Dec 2015 00:00:00 GMT  
Content-Type: application/json  
Date: Mon, 02 Mar 2015 05:24:58 GMT  
Content-Length: 20  

Expires headers are good for the following uses:

  • Making static resources returned by the server, such as images, cacheable.
  • Controlling the caching of a resource returned by servers that changes only at specific intervals. For instance, a list of public holidays for an organization for a specific year, which does not usually change within a year.

Using Cache-Control directives to manage the HTTP cache


The Cache-Control header was defined as part of HTTP/1.1 and offers more options than the Expires HTTP header. This header is used for specifying the directives that must be obeyed by all caching mechanisms involved in HTTP communication. These directives indicate who can do the caching of a resource returned by the server, how the caching is done, and for how long the resource can be cached.


The Expires header is recommended for static resources such as images. The Cache-Controlheader is useful when you need more control over how caching is done.


Here is a list of useful Cache-Control directives:

  • private: This directive indicates only those clients who originally requested the resource (for example, browser). This directive can do the caching and no other entity in the request-response chain (for example, proxy) is expected to do the caching.
  • public: This marks a response as cacheable and caching can be done by any entity in the request-response chain.
  • no-cache: This directive tells the client (for example, browser or proxies) that it should validate with the server before serving the resource from the cache. The validation can be done with the server by sending a request with the appropriate header fields, such as If-Modified-SinceIf-Unmodified-SinceIf-Match, and If-None-Match.
  • no-store: This directive indicates that a response can be cached (for example, in-memory), but should not be stored on a permanent storage (for example, disk).
  • no-transform: This directive means that the resource should not be modified by any entity in the request-response chain. This directive is used for avoiding loss of data while transforming a response from one format to another by intermediate entities.
  • max-age: This value (measured in seconds) indicates how long the cached resource will be considered fresh. After this, the cached content needs to be validated with the server while serving the next request.
  • s-maxage: This directive is similar to the max-age directive, except that it only applies to shared (for example, proxy) caches, not for the client who originated the request.
  • must-revalidate: This directive tells all caches that they must follow the freshness information set by the server while generating the resource. Note that the HTTP protocol allows caches to serve stale resources under special conditions. By specifying the must-revalidate directive in the header of a response, you are telling all caches not to use any stale resource from the cache and validate the expired cache resources with the server before serving the request.
  • proxy-revalidate: This directive is similar to the must-revalidate header item, except that it only applies to the proxy caches (not for the client that originally requested the resource).
JAX-RS allows you to specify the Cache-Control directives on the javax.ws.rs.core.Responseobject returned by your REST resource method via the javax.ws.rs.core.CacheControl class. The CacheControl class exposes methods for accessing all possible Cache-Controldirectives.

//Other imports are omitted for brevity 
import javax.ws.rs.core.CacheControl; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.Response; 
import javax.ws.rs.core.Response.ResponseBuilder;  
 
@GET 
@Path("departments/{id}") 
@Produces(MediaType.APPLICATION_JSON) 
public Response findDepartmentById(@PathParam("id") Short deptId) 
{ Department department = findDepartmentEntityById(deptId); //Specifies max-age and private directive for the response CacheControl cc = new CacheControl(); //Cache is valid for a day (86400 sec) cc.setMaxAge(86400); cc.setPrivate(true); ResponseBuilder builder = Response.ok(myBook); //set the CacheControl object and build Response builder.cacheControl(cc); return builder.build(); }

Here is the sample response header generated by the preceding method for the GET departments/10 HTTP/1.1 request:

Server: GlassFish Server Open Source Edition 4.1  
Cache-Control: private, no-transform, max-age=86400  
Content-Type: application/json  
Date: Mon, 02 Mar 2015 05:56:29 GMT  
Content-Length: 82 


Comments

Popular posts from this blog

Understanding the JAX-RS resource life cycle

Generating a chunked output using Jersey APIs

Jersey client API for reading chunked input