How To Use Redis As A Caching Server In Your Javascript Project - For Beginners

How To Use Redis As A Caching Server In Your Javascript Project - For Beginners

In my article today, I will put you through how you can set up and configure a caching server for your next huge project.

Firstly, I will start by explaining what a database is and how Redis comes into the picture.

What is a Database

According to Oracle, a database is an organized collection of structured information, or data, typically stored electronically in a computer system.

This simply means that a database enables us to store a collection of information or data in an organized manner. For example in a fintech project, we can have a database where all user-related information is stored, their wallets, their transactions, etc.

I hope you now understand the concept of a database. Now, let us talk about a type of database, called, the in-memory database.

What is an in-memory database?

According to DragonflyDB, an in-memory data store is a type of database that stores data in the main memory (RAM) to ensure faster access times compared to disk-based databases. The data stored in this type of database has indexes that act as direct pointers to specific rows and columns. Simply put, this type of database has a key (index) that points to a value.

Having understood the basic concept of databases, here are the two most popular in-memory databases or solutions;

  • Redis (Remote Dictionary Server)

  • Memcached

You can read up on their differences here, and for the sake of this article, I will focus on Redis and share some utility functions that you can implement in your next big project.

But first, let us install this caching server into our system.

Installing Redis Server

For Linux OS, the process is simple, just copy the shell command below and paste it into your terminal.

$sudo apt-get install redis-server # Install Redis Server

$sudo systemctl start redis-server # Start the Redis service

For Windows OS, it is important to note that the Redis project does not officially support Windows but there's a workaround on this amazing website.

Now that we have Redis installed in our system, let us talk about some basic Redis commands and what you can use them for.

Basic Redis Commands

Here are some of the 3 basic Redis commands that we would use to integrate data caching within our project.

  1. SET: This will set the value of a key.

  2. GET: This will get the value of a key.

  3. DEL: This will delete a key.

If you can recall earlier when we discussed what an in-memory database is, you would notice that the commands above all referenced a kind of "key" and this is needed for us to have access to the data we store in Redis.

For example, from our terminal, using redis-cli (Redis Command Line Interface enables us to interact with the Redis server direclty from the terminal). if I wanted to cache an OTP code for a user, I would use the SET command like this;

SET MY_KEY THE_VALUE
$redis-cli   # Access Redis command Line

127.0.0.1:6379> SET otpCode 123456
OK #If the operation is successful, you will see this

The same goes for the GET and DEL commands

127.0.0.1:6379> GET otpCode #Retrieve the cached OTP
"123456" #This is the otpCode we cached earlier

127.0.0.1:6379> DEL otpCode #Delete the cached OTP
(integer) 1 #DEL Operation was successful

We're heading somewhere, right? Sit tight and you'll understand how you can use Redis as a caching server in your project.

Importing Redis Into Your JavaScript Application

To make use of Redis in your application, I would personally recommend this package ioredis available on npm via;

$npm install ioredis

Redis typically provides a default port (6379) and host (127.0.0.1) when it is installed on your local system so that we can make connections to it. But if you have a Redis cache provisioned elsewhere for you, typically, they would share a URL that you can use to connect to it.

On your local system, the connection URL would be 127.0.0.1:6379 and because it is the default URL, we do not necessarily need to provide this URL when creating a Redis client.

import Redis from 'ioredis';

//create a new Redis client to connect to the Redis server using the 
//connection URL
const redisClient = new Redis(process.env.REDIS_URL ?? "");

redisClient.on('error', (err) => {
    console.error('Redis error:', err);
});

redisClient.on('ready', () => {
    console.log('Redis is ready ✅');
});

Flexible Redis Utility Functions

I believe with the explanations above, you have been able to understand the basic commands in Redis, how to import Redis into your javascript application, and below, we will leverage the basic Redis commands to build some utility functions that can ease the stress and make our code more modular.

Now, if we wanted to cache some data in Redis, we would typically use the SET command and create a function that returns a promise like this;

/// ...
function cacheData(key, data) {  
    return new Promise((resolve, reject) => {
        //call the SET command
        redisClient.set(key, data)
            .then(data => {
                if (data === "OK") {
                    resolve(data)
                } else {
                    resolve(false)
                }
            }).catch((err) => {
                reject(err)
            })
    })
}

//usage
await cacheData("otpCode", "123456")

The SET command also allows us to cache some data with an expiry time and this is particularly useful if you are caching an OTP code or something else that is sensitive and shouldn't have a long TTL - Time To Live

/// ...
function cacheData(key, data, shouldExpire = false, expiry = 300) {
    //check if the data should expire
    if (shouldExpire) {
        return new Promise((resolve, reject) => {
            //call the SET command with EX (expiry) and provide the 
            //expiry time in seconds
            redisClient.set(key, data, 'EX', expiry)
                .then(data => {
                    if (data === "OK") {
                        resolve(data)
                    } else {
                        resolve(false)
                    }
                }).catch((err) => {
                    reject(err)
                })
        })
    } else {
        return new Promise((resolve, reject) => {
            //call the SET command without Expiry
            redisClient.set(key, data)
                .then(data => {
                    if (data === "OK") {
                        resolve(data)
                    } else {
                        resolve(false)
                    }
                }).catch((err) => {
                    reject(err)
                })
        })
    }
}

To use this function, we can do something like this;

const userData = {
    otpCode: "123456",
    timeStamp: Date.now()
}

//cache OTPCode to last for 10 mins
await cacheData("YOUR_USER_ID_HERE", JSON.stringify(userData), true, 600)

Then to use the GET command, I would have a function like this;

/// ...
function queryCachedData(key) {
    return new Promise((resolve, reject) => {
        //call the GET command
        redisClient.get(key)
            .then((storedData) => {
                resolve(storedData);
            })
            .catch((err) => {
                reject(err)
            })
    })
}

//usage
let cachedData = await queryCachedData("YOUR_USER_ID_HERE")
//parse cachedData if it was stored as JSON
cachedData = JSON.parse(cachedData)
// {otpCode: "123456", timeStamp: 1709202327082}

Now when the OTP code has been verified by comparing the user Input with what you had cached, you would typically want to delete the cached data manually or you could wait for it to expire. Whichever, here is the delete function below.

/// ...
function deleteCachedKey(key) {
    return new Promise((resolve, reject) => {
        redisClient.del(key)
            .then((response) => {
                resolve(response);
            })
            .catch((err) => {
                reject(err)
            })
    })
}

//usage
await deleteCachedKey("YOUR_USER_ID_HERE")

Now, I can't be the one to do everything for you, but I believe that with my help so far, you can figure out some logic around your project and implement the best caching system with Redis. The use cases of this include;

  • OTP code verification

  • Password Reset

  • Session management

  • Queue management

  • ... think forward

If you need help with any part of this article, or you need more utility functions, or some logic around your project, hit me up and we will brainstorm together!

EXTRA

If you have an existing project and wish to use Redis as your caching server, you could subscribe to a Redis plan from Render or use the free provision available on their platform.

Make sure to whitelist only the IP of the platform you wish to access Redis from and try to add strict validations for every data that is cached to ensure integrity.

Are you ready to wield the power of this great caching solution?

Wand GIFs | Tenor

Feel free to experiment with the basic commands above and do more research on the other commands not listed above.

Psst... I'm still your favorite Software Developer.

Photo Credit: Benjamin Lehman on Unsplash