HTTP Caching using JAX-RS

In the last blog we discussed different types of caches and their use cases.
In this post we will explore how we can leverage caching using HTTP response headers and the support provided by JAX-RS.

Expires Header
In HTTP 1.0, a simple response header called Expires would tell the browser how long it can cache an object or page. It would be a date in future after which the cache would not be valid.
So, if we made an API call to retrieve data :

GET /users/1

The response header would be:

HTTP/1.1 200 OK
Content-Type: application/xml
Expires: Tue, 25 Aug 2013 16:00 GMT
<user id="1">...</users>

This means the XML data is valid until 25th Aug 2013, 16:00 hours GMT.

JAX-RS supports this header in object.

	public Response getUserXML(@PathParam("id") Long id){
		User user = userDB.get(id);
		ResponseBuilder builder = Response.ok(user,MediaType.APPLICATION_XML);
		//Putting expires header for HTTP broswer caching.
		Calendar cal = Calendar.getInstance();

But to support CDNs, proxy caches and revalidations there was a need for more enhanced headers with richer set of features, having more explicit controls. Hence in HTTP 1.1 few new headers were introduced and Expires was depricated. Lets explore them.

Cache-Control has a variable set of comma-delimited directives that define who,how and for how long it can be cached. Lets explore few of them:
private/public : these are accessibility directives, private means a browser can cache the object but the proxies or CDNs can not and public makes it cachable by all.
-no-cache,no-store,max-age are few others where name tells the story.

JAX-RS provides class to represent this header.

	public Response getUserXMLwithCacheControl(@PathParam("id") Long id){
		User user = userDB.get(id);
		CacheControl cc = new CacheControl();
		ResponseBuilder builder = Response.ok(user,MediaType.APPLICATION_XML);

Revalidation and Conditional GETs : After the cache has expired the cacher can revalidate the cache sending a request to the server to check if the cache is stale or holds good. This is done with the help of a header called as “Last-Modified“.

HTTP/1.1 200 OK
Cache-Control: max-age=1000
Last-Modified: Mon, 19 aug 2013 16:00 IST

To revalidate one must send a GET request with the header “If-modified-since“.This is called a conditional GET, in case the data is modified a response code 200 (OK) with current value of resource will be sent. And if the data is not modified a response code of “304” is sent which would mean the cache is still valid, at this point the “Last-Modified” tag can be updated.

Etag is another HTTP header which can be used to revalidate caches, It is usually an MD5 hash value.
A hash generated from resource is sent by server in the response as Etag value, so that while validating, client can send its Etag value to server to check if the value residing at the server matches.(As the hash is generated from resource, change in resource would generate a different hash)

For this conditional GET, a request with header “If-none-Match” is sent to validate.

GET /users/23 HTTP/1.1
If-None-Match: "23432423423454654667444"

Also, we can have strong and weak Etag values depending on different usecases.

JAX-RS provides us with for the same.

public class EntityTag {

To help with conditional GETs, JAX-RS also provided one injectable helper class Request, which has methods like…

ResponseBuilder evalutatePostConditions(EntityTag eTag);
ResponseBuilder evaluatePreConditions(Date isLastModified);

The etag or LastModified values sent in the request Header are compared
Lets see an example…

	public Response getUserWithEtagSupport(@PathParam("id") Long id,
			@Context Request request){
		User user = userDB.get(id);
		//generating Etag out of hashCode of user
		EntityTag tag = new EntityTag(Integer.toString(user.hashCode()));
		CacheControl cc = new CacheControl();
		ResponseBuilder builder = request.evaluatePreconditions(tag);
			//means the preconditions have been met and the cache is valid
			//we just need to reset the cachecontrol max age (optional)
		//preconditions are not met and the cache is invalid
		//need to send new value with reponse code 200 (OK)
		builder = Response.ok(user,MediaType.APPLICATION_XML);
		//reset cache control and eTag (mandatory)

If the result of evaluation is not null, means the tags match and data is still valid, we can just reset the expiry time and return.

If the conditions have not been met it returns a null which means that the latest tag and the tag provided in request header DO NOT match, the resource is out of date and needs to be sent back in the response OK.
“304” response meaning not-modified is send.

This is how using JAX-RS we can leverage HTTP caching to its full potential effectively.

Tagged with: , , ,
Posted in java, JAX-RS, REST
One comment on “HTTP Caching using JAX-RS

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Enter your email address to follow this blog and receive notifications of new posts by email.

Join 166 other followers

Blog Stats
  • 21,769 hits

Get every new post delivered to your Inbox.

Join 166 other followers

%d bloggers like this: