The Vary HTTP header

The Vary HTTP header

I try to constantly deepen my knowledge of HTTP and REST. Recently, I stumbled upon the list of all registered HTTP Headers. This post is dedicated to the Vary HTTP Header.

The problem

Two years ago, I wrote about web resource caching server-side. The idea is to set up a component between the client and the upstream to cache previously computed results to avoid overloading the latter. Depending on your infrastructure and requirements, this component can be a reverse proxy or an API Gateway. HTTP offers the Cache-Control header to customize the different aspects of caching, e.g., the time the server holds the resource in cache before it considers it stale. I used plugin configuration in the above post, but you can also delegate to Cache-Control.

Now, imagine the following scenario. You request a resource, e.g., GET /book/1 and get the result:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 1,
  "title": "Notre-Dame de Paris"
}

The request succeeds; the result is cached. Now, I request the same resource, but because my code works around XML, I set the Accept header to application/xml. Unfortunately, the server returns the cached JSON resource, which differs from what I asked and probably utterly breaks my code.

The problem is that the cache key has a single dimension, the URL, by default.

The solution

We need a configurable multi-dimension cache key. As you can probably guess by now, that's the role of the Vary header: it explicitly lists all dimensions of the cache key. In the example above, the upstream would communicate the additional cache key with the following:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Language: en
Vary: Accept


{
  "id": 1,
  "title": "Notre-Dame de Paris"
}

Instead of a single cache entry per URL, we now have one per MIME type/URL combination. Note that it's up to the caching component to use this information.

Another common request header is Accept-Encoding, which usually specifies which compression algorithms the client can accept. Encoding is another possible cache key. The specification allows specifying multiple cache keys:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Language: en
Vary: Accept, Accept-Encoding


{
  "id": 1,
  "title": "Notre-Dame de Paris"
}

Conclusion

I've described the Varyresponse header in this post. As soon as you configure caching, you must consider possible cache keys and use the Vary header accordingly.

To go further:


Originally published atA Java Geekon May 5th, 2024