We live in the age of immediacy, where time is already worth more than money. And that era, combined with the dynamism of the internet, makes our audience more demanding every day.
The content of your website may be excellent, but if the loading speed is not good, will people wait to see it?
According to several studies, half of the users do not wait more than three seconds. This is a challenge for websites such as e-commerce, where users may abandon the page if it does not load almost immediately and lose potential sales.
Caching your web application data could be crucial to solving this problem and providing high-performance gains as you scale.
In recent years, Redis has become the most popular caching database as it allows the website to dramatically increase performance and work more smoothly by accessing data in a matter of milliseconds.
The Remote Dictionary Server (
Redis is based on a hash table structure where each key has an associated value. Compared to other Key-Value databases, Redis allows the use of more complex and flexible structures that open up several possibilities for different business application needs.
The use of Redis is highly recommended when access speed and response times are critical for a business solution. Its use is also indicated when working with real-time applications, which require data to be quickly accessible to improve response times. Among the most common use cases we can find:
Caching is the process of storing copies of data in memory to allow applications to access and retrieve data faster.
The goal of caching is to speed up data access operations better than a database or remote server could allow. This is especially the case for costly (in time) operations.
For example, if our queries require several operations, such as retrieving data from a database, performing calculations, retrieving additional data from other services, etc., we can use caching.
With this, we process the data only once, store it in a cache and then retrieve it directly from the cache without performing all those costly operations. We will then periodically refresh the cache so that users can see updated information.
Now we will start with the development of our app what we want to achieve in this tutorial is to perform queries to an external API and measure the response time.
After that, we will implement Redis in our application, storing the result of our queries in the cache. With this, we will be able to compare the response time before Redis and after Redis.
The first thing for this tutorial is to have Redis installed in our local environment. For this, we will follow these installation guides for each platform.
We start our Node.js project with the command to create package.json
.
npm init
For our Node.js application, we need to install the following dependencies with the following commands:
npm install express redis axios
npm install nodemon response-time -D
In our package.json
file, we will create inside the “scripts” key a new script that we will use to raise our application.
"dev": "nodemon src/app.js"
Set up the initial boilerplate for the Node.js application like this. We create an app.js
file, and inside it, we add the following lines:
const express = require('express')
const responseTime = require('response-time')
const redis = require('redis')
const axios = require('axios')const app = express()app.listen(process.env.PORT || 3000, () => {
console.log("Node server started")
})
Now we have the Express server created if we execute the command.
npm run dev
We will see in the console the message "Node server started"
For our tutorial, we will use the REST version of The Rick and Morty API, which offers us the following endpoints:
{
"characters": "https://rickandmortyapi.com/api/character",
"locations": "https://rickandmortyapi.com/api/location",
"episodes": "https://rickandmortyapi.com/api/episode"
}
Now we will make a request with axios to the /character
endpoint.
const express = require('express')
const responseTime = require('response-time')
const redis = require('redis')
const axios = require('axios')
const app = express()
app.use(responseTime())app.get("/character", async (req, res) => {
try {
const response = await axios.get('https://rickandmortyapi.com/api/character')
await client.set('characters', JSON.stringify(response.data))
return res.status(200).json(response.data)
} catch (err) {
return res.status(err.response.status).json({ mmessage: err.mmessage })
}
});
app.listen(process.env.PORT || 3000, () => { console.log("Node server started")})
With this request that we have made, the API returns us an object with all the characters, and what we are interested in seeing is the response-time
that this request has taken.
Using response-time that we have added as a middleware, we will be able to see in the headers of the request a new header called X-Response-Time
which will indicate the time in more.
This request has taken 238.831ms:
Now, let’s see how we can improve the application's performance by caching.
First, we need to connect to the Redis server through our application. We use the installed Redis package for this task.
By default, redis.createClient()
will use 127.0.0.1
and 6379
as the hostname and port, respectively. If you have a different host/port, you can supply them like so:
const client = redis.createClient(port, host)
const runApp = async () => {
const client = redis.createClient()
client.on('error', (err) => console.log('Redis Client Error', err))
await client.connect()
console.log('Redis connected!')
}
runApp()
Now we will make the same request to the API and cache the response with the set()
method of the Redis client, which receives as the first parameter the name of the key we want to save. As the second parameter, the value of this key, which we have to save as a string, so we have to parse the JSON to string.
const runApp = async () => {
app.get('/character', async (req, res) => {
try {
const response = await axios.get('https://rickandmortyapi.com/api/character')
await client.set('characters', JSON.stringify(response.data))
return res.status(200).json(response.data)
} catch (err) {
return res.status(err.response.status).json({ mmessage: err.mmessage })
}
})
}
runApp()
Once we reload our app and we get back the result of the query, we will have already cached the answer.
To validate this, we will use
npm install -g redis-commander
This package will provide us with a redis-commander
command that, when executed, will execute the database web interface on port 127.0.0.1:8081
.
And when we enter redis-commander, we will see that the response to our /character
request has already been stored with the name that we have assigned to it.
The process of caching with Redis is quite simple. When we receive a request from the user, we first check if the requested data is already cached. If so, we can quickly retrieve the data from Redis and send the response.
However, if the data is not cached, which we call a cache miss, we must first retrieve the data from the database or external API and send it to the client. We also make sure to store the retrieved data in the cache so that the next time the same request is received, we can simply send the cached data to the user faster.
const runApp = async () => {
app.get('/character', async (req, res) => {
try {
const cacheCharacters = await client.get('characters')
if (cacheCharacters) {
return res.json(JSON.parse(cacheCharacters))
}
const response = await axios.get('https://rickandmortyapi.com/api/character')
await client.set('characters', JSON.stringify(response.data))
return res.status(200).json(response.data)
} catch (err) {
return res.status(err.response.status)
.json({ mmessage: err.mmessage })
}
})
}
runApp()
Now that we are retrieving the information from the cache, the response time has dropped considerably to 4.230ms.
It is important to note that we have only touched the surface in this tutorial, and there is much more than Redis has to offer. I highly recommend consulting its official
Here is the complete script with one more example with an endpoint receiving parameters:
const express = require('express')
const responseTime = require('response-time')
const redis = require('redis')
const axios = require('axios')
const runApp = async () => {
// connect to redis
const client = redis.createClient()
client.on('error', (err) => console.log('Redis Client Error', err));
await client.connect();
console.log('Redis connected!')
const app = express()
// add response-time to requests
app.use(responseTime())
app.get('/character', async (req, res) => {
try {
// check if the request is already stored in the cache, if so, return the response
const cacheCharacters = await client.get('characters')
if (cacheCharacters) {
return res.json(JSON.parse(cacheCharacters))
}
// makes the request to the API
const response = await axios.get('https://rickandmortyapi.com/api/character')
/* Another way to save the data is to save it with the name of the requets url, with the property
req.originalUrl which would be the same as '/character'
await client.set(req.originalUrl, JSON.stringify(response.data))
*/
// save the response in the cache
await client.set('characters', JSON.stringify(response.data))
return res.status(200).json(response.data)
} catch (err) {
return res.status(err.response.status).json({ mmessage: err.mmessage })
}
})
app.get('/characters/:id', async (req, res) => {
try {
const cacheCharacter = await client.get('cacheCharacter' + req.params.id)
if (cacheCharacter) {
return res.json(JSON.parse(cacheCharacter))
}
const response = await axios.get('https://rickandmortyapi.com/api/character/' + req.params.id)
await client.set('cacheCharacter' + req.params.id, JSON.stringify(response.data))
return res.json(response.data)
} catch (err) {
return res.status(err.response.status)
.json({ message: err.message })
}
})
app.listen(process.env.PORT || 3000, () => {
console.log(`server on port 3000`)
})
}
runApp()
In this tutorial, we have seen a quick introduction to Redis and created a simple cache with it for a Node.js application.
You can now use Redis to cache frequently queried data in your application for a significant performance boost, especially in projects that handle many requests per second, where the performance provided by Redis becomes very important.
Want to Connect? Love connecting with friends all around the world on
Also published here.