According to the Http specification, any Http GET request should be idempotent and safe. In this context, these principles have the following meaning:
Idempotence: One or more calls with identical requests should return the same resource representation (As long as the resource has not changed on the server between calls).
Safety: The only action produced by a GET request is to retrieve a resource representation, no side-effects should be evident on the service side after executing the request. An example that violates this principle could be a GET request that also updates some info in the resource.
As long as these principles are applied correctly by a service implementation, the client will have more available mechanisms to cache the resource representation on its side. This has a very positive meaning from a scalability view point, which represents a better use of the network bandwidth and an optimization in the utilization of server resources.
Those caching mechanisms are based on what is commonly called Http conditional gets. An Http conditional get involves the use of two special headers generated by the service, ETag and Last-Modified.
An Etag represents an opaque value that only the server knows how to recreate, it could represent anything, but it is usually a hash representing the resource version (it can be generated hashing the whole representation content or just some parts of it, like the timestamp). On the other hand, the Last-Modified headers represents a datetime that the service can use to determine whether the resource has changed since the last time it was served. The following example illustrates the request/response messages interchanged by the client/service for a service that returns information about customers
First request, the client does not have anything on the cache.
Date Thu, 02 Oct 2008 14:46:57 GMT
Expires Sat, 01 Nov 2008 14:46:57 GMT
Last-Modified Mon, 29 Sep 2008 15:40:27 GMT
The next time the client sends a new request for the same customer, some extra information will be included in the request headers,
If-Modified-Since Mon, 29 Sep 2008 15:40:27 GMT
With these two new headers, the service can now determine whether it has to serve the resource representation again or the client can use the cached version. If the resource has not changed according to the values in those headers (If-Modified-Since for Last-Modified and If-None-Match for Etag), the service can return an Http status code "304 Not Modified", which instructs the client to use the cached version.
This approach is widely used nowadays by syndication, RSS or Atom, that usually use the Last-Modified/If-Modified-Since to determine which items they have to send to the client.
Since I am a WCF fan, I will also include here some code snippets to get the value in those headers and return a "304" http status code,
Code to get those values:
if (WebOperationContext.IncomingRequest.Headers[HttpRequestHeader.IfNoneMatch] != null)
// Do something with etag...
else if (WebOperationContext.IncomingRequest.Headers[HttpRequestHeader.IfModifiedSince] != null)
var date = DateTime.Parse(context.IncomingRequest.Headers[HttpRequestHeader.IfModifiedSince]);
Code to set those values:
WebOperationContext.OutgoingResponse.LastModified = // sets the last modified;
WebOperationContext.OutgoingResponse.ETag = // sets the Etag
Code to return an Http 304 status code:
WebOperationContext.OutgoingResponse.StatusCode = HttpStatusCode.NotModified;
WebOperationContext.OutgoingResponse.SuppressEntityBody = true;