Boost Your REST API with HTTP Caching

Because it will allow you to show off against other API Designers by claiming that your REST services are twice as RESTful as theirs ;-)

But more seriously, Roy Fielding, who invented the REST architectural style, didn’t add caching as a requirement just for the fun it! He added it because it can seriously boost performance, which is also shown in the numbers in Tom Christie’s great post on performance tuning of Django REST services.

So, how do you get started with HTTP caching?

It’s only for HTTP GET requests!

At first it may seem like an overwhelming task to implement HTTP Caching; especially if you have already developed a huge number of services.

The good news is that it’s only GET methods where you need to think about caching as it doesn’t really make much sense to cache POST, PUT or DELETE responses.

The even better news is that if you simply specify the right HTTP header then the browser will do all the heavy lifting for you!

Code, please!

That’s all very nice! But can you please show us the code?

Definitely, but the only code you need is the Cache-Control header in your HTTP response. There are a number of directives in this header you can use to control the caching:

Directive

Description

max-age

The maximum time that the cached response should be used (in seconds). The maximum value is 1 year.

Example:

Cache-Control: max-age=3600

Kyle Young writes that a rule of thumb is to use between 60 seconds and 1 hour for most content, but for pseudo dynamic content, use less than 60 seconds (or don’t cache it at all).

s-max-age

This directive overrides max-age for shared cache, such as proxy servers. You usually have more control over the proxy cache than the client’s local cache, so you can add longer values here.

Example:

Cache-Control: max-age=0, s-max-age=3600

Thuva Tharma has some interesting thoughts on why s-max-age may be better than max-age.

publicprivate

Is the response specific to the client, so it cannot be used for other clients? For example, /tasks/myTasks is client-specific.

If the response is client-specific, use private. Otherwise, use public, which is also the default.

Examples:

Cache-Control: private, max-age=3600

Cache-Control: public, max-age=3600

no-store

This is used for sensitive data (like credit card details) that must not be stored in caches or proxies under any circumstances.

Example:

Cache-Control: no-store

no-cache

The client must not use cached responses. Unless, it first sends a conditional GET (with an ETag) to the server to check if the data has been updated in the meantime.

Example:

Cache-Control: no-cache

must-revalidate

If the cached response has expired, it must be revalidated at the server.

HTTP might under some circumstances serve cached responses that have expired (for instance, under poor network connectivity), but using this directive ensures that this won’t happen.

Example:

Cache-Control: max-age=3600, must-revalidate

proxy-revalidate

Same as must-revalidate, but for proxy servers.

Example:

Cache-Control: s-max-age=3600, proxy-revalidate

So let’s say that the client sends a request for some metadata, and we want the client to cache it for 1 hour: