Introduction to Redis and How to Use Caching in Node.js using Redis
By: Ramu Bathala
Tags: JavaScript, Redis, Nodejs, Web Development, Node

In this article, we are going to implement caching in a node js application using Redis. But, before let’s start with explaining & installing Redis on your machine, covering the basics of the Redis CLI & then use it in Node.js.

Redis stands for Remote Dictionary Server.

What is Redis?

Redis is a data storage system which works on the concept of key-value pair used as a NoSQL database or as a memory-cache store to improve performance when serving data that is stored in system memory.

The key-value store provides ability to store some data called a value, inside a key. You can recieve this data later only if you know the exact key used to store it.

What is Cache?

A cache is a reserved storage location that collects temporary data to help websites, browsers, and apps load faster.

What is caching?

Caching is the process of storing copies of files in a cache or a temporary storage location so that they can be accessed more quickly.

Why do we Cache?

To reduce app response time. We don’t want your application to take too long to respond to users’ requests.

Prerequisites

Node.JS

Redis Server

Postman

Code Editor (VsCode)

If you don’t have Node installed just click on to the official Node.js website.

Installing Redis

Linux: https://redis.io/download

Windows: Use the Linux subsystem for Windows. Then just intall it like on Linux.

You can also install with these commands

sudo apt update

sudo apt install redis-server

Check, If Redis is working

Start by checking that the Redis service is running.

sudo systemctl status redis

If it is running without any errors, this command will produce output similar to the following.

Output ● redis-server.service - Advanced key-value store

Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled)

Active: active (running) since Wed 2018-06-27 18:48:52 UTC; 12s ago

Docs: http://redis.io/documentation,

man:redis-server(1)

Process: 2421 ExecStop=/bin/kill -s TERM $MAINPID (code=exited, status=0/SUCCESS)

Process: 2424 ExecStart=/usr/bin/redis-server /etc/redis/redis.conf (code=exited, status=0/SUCCESS)

Main PID: 2445 (redis-server)

Tasks: 4 (limit: 4704)

CGroup: /system.slice/redis-server.service

└─2445 /usr/bin/redis-server 127.0.0.1:6379

. . .

Here, you can see that Redis is running and is already enabled.

Redis CLI

To test that Redis is functioning correctly, connect to the server using the command-line client.

redis-cli

It will give Redis prompt as below.

127.0.0.1:6379>

Testing with a simple String

Give SET/set, then give the key, i.e the variable name and with a space after it, the value.

127.0.0.1:6379> set test "It's working!" Output

OK

Now we can print out the value of our key, called “test”. We should receive “It’s working!”.

127.0.0.1:6379> get test Output

"It's working!"

We can also delete the stored key with command “del key”. We should receive “(integer) 1” it means that key deleted from the list.

To get a list of all current keys that exist, simply use the KEYS command.

127.0.0.1:6379> set title1 1

127.0.0.1:6379> set title2 2

127.0.0.1:6379> keys * Output

1) "title2"

2) "title1"

By following KEYS with an asterisk ( * ) – which acts as a wildcard search – we’re asking Redis to retrieve all keys in the system.

We can give expiration time for keys. So the keys will be automatically deleted from the list after a given time.

The Syntax for expiration key is “set key value ex seconds”.

127.0.0.1:6379> set mykey hello ex 30

We can also check the remaing time for expiring the key with the command “ttl key”.

Visit official website to get more related commands.

Getting started with Redis in Node.js

To get started, create a new directory for the application by running the following command on the terminal.

mkdir redis-cache && cd redis-cache

Initialize the directory to create a package.json file by running the following command.

npm init -y

Install dependencies

We will be using redis, axios and express modules, so let’s install them by running the following command.

npm i express redis axios

Open the project folder in code editor(VsCode) by using the command “code .”. Your folder structure should now look like below.

Folder Structure

Create a simple Express server file as given in package.json as index.js.

const express = require("express"); const app = express(); const port = 8080; app.listen(port, () => {

console.log(`Server running on port ${port}`);

}); module.exports = app;

We are going to be making request to a public API for various jobs provided by https://jobs.github.com

In index.js file paste the following code.

const express = require("express"); const app = express(); const port = 8080; const axios = require("axios");

try {

const { search, type, title } = req.query;

const foundResults = await axios.get(

`https://jobs.github.com/positions.json?search=${search}&type=${type}&title=${title}`

);

return res.status(200).send({

error: false,

data: foundResults.data

});

} catch (error) {

console.log(error);

}

}); app.get("/jobs", async (req, res) => {try {const { search, type, title } = req.query;const foundResults = await axios.get();return res.status(200).send({error: false,data: foundResults.data});} catch (error) {console.log(error);}); app.listen(port, () => {

console.log(`Server running on port ${port}`);

});

Start the server by running node index.js and open postman to make a request to the jobs endpoint.

As we can see, the request completed in 2446ms which is quite a long time to fetch data that doesn’t change often. We will improve this by implementing caching using Redis.

Add the following changes to index.js file

const express = require("express");

const axios = require("axios");

const redis = require("redis"); const app = express(); const port = 8080; // make a connection to the local instance of redis

const client = redis.createClient(6379); client.on("error", error => {

console.error(error);

}); app.get("/jobs", (req, res) => {

try {

const { search, type, title } = req.query; // Check the redis store for the data first

client.get("jobs", async (err, jobs) => {

if (jobs) {

return res.status(200).send({

error: false,

message: `Jobs from the cache`,

data: JSON.parse(jobs)

});

} else {

// When the data is not found in the cache then we can make request to the server

`https://jobs.github.com/positions.json?search=${search}&type=${type}&title=${title}`

); const foundResults = await axios.get(); // save the record in the cache for subsequent request

client.setex("jobs", 1440, JSON.stringify(foundResults.data)); // return the result to the client

return res.status(200).send({

error: false,

message: `Jobs from the server`,

data: foundResults.data

});

}

});

} catch (error) {

console.log(error);

}

}); app.listen(port, () => {

console.log(`Server running on port ${port}`);

}); module.exports = app;

In the /jobs route handler, we tried to get the appropriate matching data to serve the request by checking for the key in our redis store. If found, the result is served to the requesting client from our cache and then we don’t have to make the server request anymore.

But if the key is not found in our redis store, a request is made to the server and once the response is available, we store the result using a unique key in the redis store.

The setex method of the redis client is used to set the key to hold a string value in the store for a particular number of seconds which in this case is 1440 (24 minutes).

Testing the application

Now let’s test the application after implementing cache. Open postman and make a request to the same endpoint as before.

Again, because the key is not found in the cache the request is sent to the server which takes 2446ms to complete. Since the key didn’t exist in the cache before, it is now saved in the cache and subsequent requests with the same data will be fetched from the cache which makes it faster, and also reduces the load on the server. Below is the response time after the cache.

As we can see above, it took 179ms for the request to be completed because it was fetched from the cache.