Caching is an important consideration for any application. If done correctly, it can help improve the performance of the application. Fastify Redis Cache setup can help developers take care of caching requirements for a Fastify application.
One of the tricky things about caching is that you could have it at the client level as well as the server level. We can manipulate HTTP Cache Headers of our REST API responses to control how caching works on the client side. At the same time, we can cache data on the server side using tools such as Redis.
The great thing about the fastify-caching
plugin is that it provides support for both the cases.
1 – What is the Cache-Control Header?
Cache-Control is an important HTTP header that specifies browser caching policies. It is part of both client requests and server responses. These caching policies determine how a resource is cached and its maximum age (or time to live).
A typical cache-control
header is made up of multiple directives. Some of the major directives are as follows:
- The
max-age
directive defines the amount of time it takes for a cached copy to expire. After expiry of the resource, the browser must fetch a fresh copy from the server. For example, max-age=300 means the resource is valid for 300 seconds. - The
no-cache
directive effectively disables all client-side caching. Technically, it does not prohibit the browser from caching the response but it must always validate with the server. - The
no-store
directive means that the browsers are not allowed to cache any response. They must always fetch the latest response from the server. - The
cache-control
directive namedpublic
means that a resource can be cached anywhere. In this case, the browser can cache the resource based on themax-age
directive - The
cache-control
value ofprivate
means that the browser may cache the response. However, it is user-specific. In other words, the browser should cache the response only on a client device. - The
must-revalidate
response directive indicates that the browser can cache the response and use it while it is fresh. Typically,must-revalidate
is used withmax-age
property.
2 – Fastify Set Cache Header
With an understanding of the above parameters, we can move further on setting cache header using Fastify. For this, we will install the fastify-caching
NPM package in our project.
See below command:
$ npm install fastify-caching
As with everything in Fastify, the fastify-caching
is also a plugin. Once installation is done, we can register the fastify-caching
plugin in our application. If interested about plugins, you can read more about them in our detailed post on Fastify plugins.
const http = require('http')
const fastify = require('fastify')({ logger: true })
const fastifyCaching = require('fastify/caching')
fastify.register(
fastifyCaching,
{privacy: fastifyCaching.privacy.NOCACHE},
(err) => { if (err) throw err }
)
fastify.get('/', (req, reply) => {
reply.send({hello: 'world'})
})
fastify.listen(3000, (err) => {
if (err) throw err
http.get('http://127.0.0.1:3000/', (res) => {
console.log(res.headers['cache-control'])
})
})
The above example will disable client side caching of all routes. Basically, it will set the value of cache-control
as no-cache
. This is because we have set the privacy
option to NOCACHE.
If you notice, the fastify-caching
plugin takes the a configuration options as input. Below is a sample object:
{
privacy: 'value',
expiresIn: 300,
cache: {get, set},
}
Let us understand these options one-by-one:
- The
privacy
option can be set to any field that is valid as per RFC2616. For example, we can set it topublic
,private
,no-cache
andno-store
. - The
expiresIn
is a value in seconds for themax-age
directive. This works for allprivacy
options exceptno-cache
. When it is set with otherprivacy
options, themax-age
property is appended to thecache-control
. - The
cache
property receives anabstract-cache
protocol compliant cache object. We will use it in the next section.
3 – Fastify Redis Cache for Server Side Caching
As discussed earlier, the fastify-caching
package also works to enable server side caching for our application.
We need to install a few packages.
$ npm install fastify-redis ioredis abstract-cache-redis
The abstract-cache-redis
makes it easy to interact with a Redis instance. This module provides a cache client that is compliant with the abstract-cache
protocol.
Also, by default, we should have a local Redis instance running on port 6379.
Then, we can simply use the IORedis package to connect to the Redis instance and use it to cache the data.
Below is the complete example code:
const http = require('http')
const fastify = require('fastify')({ logger: true })
const fastifyCaching = require('fastify-caching')
const IORedis = require('ioredis')
const redis = new IORedis({host: '127.0.0.1'})
const abcache = require('abstract-cache')({
useAwait: false,
driver: {
name: 'abstract-cache-redis',
options: {client: redis}
}
})
fastify.register(require('fastify-redis'), {client: redis})
fastify.register(
fastifyCaching,
{privacy: 'public',
expiresIn: 100,
cache: abcache},
(error) => { if (error) throw error }
)
fastify.get('/', (req, reply) => {
fastify.cache.set('hello', {hello: 'world'}, 10000, (err) => {
if (err) return reply.send(err)
reply.send({hello: 'world'})
})
})
fastify.get('/cache', (req, reply) => {
console.log("Headers: ", req.headers)
fastify.cache.get('hello', (err, val) => {
reply.send(err || val)
})
})
// Run the server!
fastify.listen(3000, (err) => {
if (err) throw err
http.get('http://127.0.0.1:3000/', (res) => {
console.log(res.headers['cache-control'])
})
})
In the fastify.get()
handler for the root path, we set a key hello to the Redis instance with a TTL value.
Within the fastify.get()
handler for /cache
path, we get the same key hello
from the Redis cache.
As you can see, we have both the Fastify cache header settings and server side caching working with each other. If you want to know more about implementing API endpoints in Fastify, check out this post on Fastify REST API.
Conclusion
The fastify-caching
is a Fastify plugin that provides facility to handle both HTTP Cache Headers and also manage the Server Side Caching aspects. For the latter, it does need to use fastify-redis
and ioredis
packages to connect with a Redis instance. However, it certainly gets the job done.
Want to do more with Fastify? Check out this post on Fastify JWT Authentication.
If you have any comments or queries about this post, please feel free to mention them in the comments section below.
0 Comments