1. Overview

This article will focus on ETags - the Spring support, integration testing of the RESTful API, and consumption scenarios with curl. This is the ninth of a series of articles about setting up a secure RESTful Web Service using Spring 3.1 and Spring Security 3.1 with Java based configuration.

The REST with Spring series:

2. REST and ETags

From the official Spring documentation on ETag support:

An ETag (entity tag) is an HTTP response header returned by an HTTP/1.1 compliant web server used to determine change in content at a given URL.

 

ETags are used for two things - caching and conditional requests. The ETag value can be though as a hash computed out of the bytes of the Response body. Because a cryptographic hash function is likely used, even the smallest modification of the body will drastically change the output and thus the value of the ETag. This is only true for strong ETags - the protocol does provide a weak Etag as well.

Using an If-* header turns a standard GET request into a conditional GET. The two If-* headers that are using with ETags are "If-None-Match" and "If-Match" - each with it's own semantics as discussed later in this article.

3. Client-Server communication with curl

A simple Client-Server communication involving ETags can be broken down into the steps:

- first, the Client makes a REST API call - the Response includes the ETag header to be stored for further use:

curl -H "Accept: application/json" -i http://localhost:8080/rest-sec/api/resources/1

HTTP/1.1 200 OK

ETag: "f88dd058fe004909615a64f01be66a7"

Content-Type: application/json;charset=UTF-8

Content-Length: 52

- next request the Client makes to the RESTful API includes the If-None-Match request header with the ETag value from the previous step; if the Resource has not changed on the Server, the Response will contain no body and a status code of 304 – Not Modified:

curl -H "Accept: application/json" -H 'If-None-Match: "f88dd058fe004909615a64f01be66a7"' -i http://localhost:8080/rest-sec/api/resources/1

HTTP/1.1 304 Not Modified

ETag: "f88dd058fe004909615a64f01be66a7"

- now, before retrieving the Resource again, we will change it by performing an update:

curl --user admin at fake dot com:adminpass -H "Content-Type: application/json" -i -X PUT --data '{ "id":1, "name":"newRoleName2", "description":"theNewDescription" }' http://localhost:8080/rest-sec/api/resources/1

HTTP/1.1 200 OK

ETag: "d41d8cd98f00b204e9800998ecf8427e"

Content-Length: 0

- finally, we send out the the last request to retrieve the Privilege again; keep in mind that it has been updated since the last time it was retrieved, so the previous ETag value should no longer work - the response will contain the new data and a new ETag which, again, can be stored for further use:

curl -H "Accept: application/json" -H 'If-None-Match: "f88dd058fe004909615a64f01be66a7"' -i http://localhost:8080/rest-sec/api/resources/1

HTTP/1.1 200 OK

ETag: "03cb37ca667706c68c0aad4cb04c3a211"

Content-Type: application/json;charset=UTF-8

Content-Length: 56

And there you have it - ETags in the wild and saving bandwidth.

Read the rest of the article