What is Redis and How To Implement Redis Cache in Node JS.
Tags: redis, node, caching
Published: 2023-02-18 21:10:55

With the development of the internet, websites now have tons of data. This is why we need a solution to reduce latency and improve performance.

In this article, we will discuss what is Redis, what is used for and how to implement a simple caching solution in NodeJS.
Let's get started!
<br>

## What is Redis?
Redis (**Re**mote **Di**ctionary **S**erver) is an open-source in-memory database which used primally for caching. It is a NoSQL key-value data store, the keys can store strings, lists, sets and bitmaps.

Unlike normal databases which stores data in HDDs. Redis stores data in memory, which makes read and write operations very fast. This leads to a better speed, reliability and performance for applications.

So since redis store data in memory, do we lose this data ?

To prevent data loss from happening, there is a built-in persistence module which writes the in-memory state to a dump file on the disk. These dump files are loaded when the system is starting; once it's up and running, the data is available again.
<br>

## What is redis used for ?
<br>  

### Caching
Redis is commonly used as a cache to store frequently accessed data so that applications can be responsive to users. Redis provides a variety of caching patterns. It includes the capacity to set how long you want to keep data and which data to evict first.

The typical workflow for this case is when a user tries to a access data, the application searches for this data in the cache. If the data is there, it simply returns it. If not, redis will fetch this data from the database and return it back to the cache.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1tw7h4vfdlw00vnrqryq.png)
### Primary Database
If the data size and risk profile are well known and match with Redis’ disk model, it can serve as a primary database.

A problem you might encounter while using redis as a primary database is running out of memory. The simple solutions for this are clustering and sharding.

Clustering means that you have a primary or master Redis instance, which can be used to read and write data. You can also have multiple replicas of that primary instance for reading the data.

Sharding means that you split your data into smaller chunks, where each shard is responsible for its own subset of data.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/785ui5oro01x3pwez3ig.png)
### Queues
Redis can be used as a message queue that enables applications and services to communicate and exchange data with each other. It can validate, store, route and deliver messages to it's destination without knowing the details about the receiver. 

In a nutshell, message queues works under a Pub/Sub model.
The publisher is responsible for publishing messages to the queue.
The Subscriber is the endpoint that waits the delivery of messages.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s5ev47fb2u3sy839tquj.png)
### Lua Scripting
Redis lets users upload and execute Lua scripts on the server.
This allows users to add features to Redis themselves in the form of fast executing scripts.

Redis also supports storing various data structures like streams, geospatial, hyperloglog and bitmaps which can be used for various use-cases.

## How To implement Redis Cache in Node.JS

In this section, we will use redis with nodejs. The idea is simple, we create an API that catches the number of public repositories of a GitHub user. Then, we will cache this result using redis.

Let's start by installing the required NPM packages:

`npm install express node-fetch redis`

If you haven't install redis yet, you can install it from [here](https://redis.io/docs/getting-started/installation/).

Create an empty JavaScript file and add the following code:

```js
const express = require('express');
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
const redis = require('redis');

const PORT = 8000;
const REDIS_PORT = 6379;

const client = redis.createClient({
    legacyMode: true,
    PORT: REDIS_PORT
});

client
    .connect()
    .then(async () => {
        console.log("You are connected")
})
    .catch((err) => {
        console.log("error happened", err)
});

const app = express();
```

We require the modules we will use and redis port and server port. Next, create a client and connect to that client.
Note that you need redis server to be running before create a redis client.
The last step is to create an express app.

Now, let's a function that gets the total number of repositories.

```js
// send a request to Github for data
getRepos = async (req, res, next) => {
  try {
    console.log('Fetching Data...');
    const { username } = req.params;
    const response = await fetch(`https://api.github.com/users/${username}`);
    const data = await response.json();
    const repos = data.public_repos;
    // Set data to Redis
    await client.setex(username, 3600, repos);
    res.json({username, repos});
  } catch (err) {
    console.error(err);
    res.status(500);
  };
};
```
In this function, we get the username from the requests parameters and send a request to this user profile using node-fetch.

After that, set the (key, data expirations in seconds, value) of the client using the `.setex` function. Finally return the response in json.

Now let's create a cache middleware that returns the cached data.

```js
cache = async (req, res, next) => {
  const { username } = req.params;
  client.get(username, (err, repos) => {
    if (err) throw err;
    if (repos !== null) {
      res.json({data:"cached data", username, repos});
    } else {
      next();
    };
  });
};
```

Like we did before, we get the username from the parameters. Then redis searches for keys that have same username.
If redis finds data it will return it, otherwise, the middleware will execute what comes next which is the previous function.

The last step is to register create a route in start the server.

```js
app.get('/repos/:username', cache, getRepos);

app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}`);
});
```

Let's test this out!


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/omx01yjd0s5nhiy6tg70.png)

As you can see from the image, we sent a request and it took about 372 ms to fetch the data.
 
Now let's send the same request again to get the cached data.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ka94a6rcbny1tg92yrg2.png)

This was fast!
It took only 5 ms to get the cached data from memory.

## Conclusion
In this article we talked redis and what it is used for, We also went through an implementation of redis in nodejs.

In a nutshell redis a NoSQL key/value store, which can be used a cache database. Redis also can be used as a message queue and a primary database.

If you find this article valuable, consider sharing it with other people!