Learn how HTTP caching works, and which headers are involved in determining whether a response from the API is cacheable.
- [Instructor] Caching is an important piece of any RESTful API. If resources and API responses are designed to be cached, clients won't need to make requests to the server again for the same resource while the cache is fresh. This reduces the load on your server and can increase both the response time of the API and the perceived response time in clients with cache responses. Caching involves both the client and the server. On the server side, your application can let clients know that responses are cacheable in a few ways. The first is by returning the cache control header with a response.
The cache control header can specify the number of seconds a cache copy should be considered fresh or it can be used to disable caching entirely by setting the no-cache and no-store directives. The Expires header can also be used to let the client know how long to cache a request. If the date of the response is less than the timestamp in the header, the response is still fresh and it can be returned from the cache. If a response includes both Cache-Control and Expires, Cache-Control takes priority in determining whether cache data is fresh. The amount of time to keep the data fresh in the cache is a tradeoff between reducing requests to the server and keeping the resource up-to-date.
For data that change frequently, you'll need to specify a short freshness window. On the other hand, static or nearly static data can have long freshness windows. Clients decide how to handle cache data depending on whether the cache is still fresh or it's become stale. When a client makes a request that could be fulfilled by cache data, it checks whether that data is still fresh in the cache or if it's gone stale. If it's fresh, the client can return the data straight from the cache and avoid making any network requests to the server. If it's stale, the data in the cache might still be valid or it might be out of date.
The client will need to check with the server to see if the cache copy is still valid. Validation headers are included on the outgoing request which lets the server know which version of the resource the client has in the cache. If the server determines that the resource still hasn't changed, it can send back the 304 Not Modified status and updated cache headers with new freshness information. The 304 Not Modified response doesn't include a response body because there's no need to retransmit the whole resource if the cache copy is still good. This way even though the client did need to make a network request to validate the cache with the server, the request is light and doesn't require much network bandwidth.
One way the client can validate a cache resource with the server is by using the Last-Modified header. On the initial response, the server includes a timestamp that indicates the last time the resource was modified. When the client needs to validate a cache but stale version, it will attach the If-Modified-Since header to the validation request it sends to the server. If the resource has still not been modified, the server will respond with 304 Not Modified and updated freshness information. If the resource has been modified, the server would respond with a normal 200 Okay response.
Another way of validating cache resources against the server is with the ETag header. On the original response, the server includes the ETag header which is a fingerprint or hash that uniquely identifies this version of a resource. If the resource changes on the server, a new ETag is calculated. When the client needs to validate a cache but stale version, it will attach the If-None-Match header to the validation request it sends to the server. If the resource hasn't changed, the server will respond with 304 Not Modified and updated freshness information. If the resource has changed and the ETag no longer matches, the server will send a normal 200 Okay response that includes the updated ETag fingerprint.
ETag validation is stronger and more accurate than validation with Last-Modified because Last-Modified is only accurate down to a second of resolution whereas the ETag fingerprint will change anytime a resource is modified. Because of this, the ETag header will take priority over the Last-Modified header if both are used. To recap, in order to support caching, the application should return the Cache-Control or Expires headers on resources that can be cached. The application should also return the Last-Modified header for resources that support a modification timestamp or an ETag for resources that can be compared using a hash or fingerprint.
When the client attaches the If-Modified-Since or If-None-Match headers, the application should compare the last modified date or the ETag fingerprint and return 304 Not Modified if the resource has still not changed. Now that we've taken a look at how caching works between the client and the server, let's add it to the Landon Hotel API.
- What is RESTful design?
- Building a new API with ASP.NET Core
- Using HTTP methods
- Returning JSON
- Creating RESTful routing with templates
- Securing RESTful APIs with HTTPS
- Representing resources
- Representing links
- Representing collections
- Sorting and searching collections
- Building forms
- Adding caching to an ASP.NET Core API
- Configuring user authentication and authorization