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 named public means that a resource can be cached anywhere. In this case, the browser can cache the resource based on the max-age directive
  • The cache-control value of private 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 with max-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 to public, private, no-cache and no-store.
  • The expiresIn is a value in seconds for the max-age directive. This works for all privacy options except no-cache. When it is set with other privacy options, the max-age property is appended to the cache-control.
  • The cache property receives an abstract-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.

Categories: BlogFastify

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *