Introduction to Redis and Caching with Node.js

pprathameshmore

Prathamesh More

Posted on March 22, 2021

Introduction to Redis and Caching with Node.js

What is Redis?

Redis is an open-source, in-memory data structure store, used as a NoSQL database for the cache to improve the overall response rate for most frequently requested data.

In this blog, we will develop Notes Taking App API, We will implement two feature,

  1. Take a note from the user.
  2. Return a note back to the user.

But here will use Redis, to cache note. If the user requests the same note frequently, we will return notes stored in Redis.

REST API Routes
POST => /api/notes => Create notes
GET  => /api/notes/:id => Get a note
Enter fullscreen mode Exit fullscreen mode

Software Requirements

Let's begin,
Install the required packages on your local machine:

npm install express body-parser mongoose redis --save

Set up Redis database with Upstash,

Upstash is a serverless database for Redis, with servers/instances, you pay-per-hour or a fixed price. With Serverless, you pay per-request.

This means you're not charged when the database isn't in use. Upstash configures and manages the database for you.

Let's start with creating an account on Upstash,

https://upstash.com/

Now set up database instance,

Create New Database<br>

Connect to your database<br>

Create a simple server and connect to the MongoDB database:

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const redis = require('redis');

const app = express();
app.use(bodyParser.json());

mongoose.connect('mongodb://localhost:27017/', {
    dbName: 'notes',
    useNewUrlParser: true,
    useUnifiedTopology: true
}, err => err ? console.log(err) : console.log('Connected to database'));


app.listen(3000, () => console.log('Server running at port 3000'));
Enter fullscreen mode Exit fullscreen mode

Now connect to the Redis server using the configuration provided by Upstash:

//Redis connection
const redis = require("redis");
var client = redis.createClient({
  host: "eu1-capital-cattle-31290.upstash.io",
  port: "31290",
  password: "YOUR_REDIS_PASSWORD",
});
client.on("error", function (err) {
  throw err;
});
Enter fullscreen mode Exit fullscreen mode

Mongoose Model:

//Mongoose Model
const NoteSchema = new mongoose.Schema({
  title: String,
  note: String,
});
const note = mongoose.model("Note", NoteSchema);
Enter fullscreen mode Exit fullscreen mode

Now implement routes for API

Get a note from the user and store it Redis and MongoDB:

//Create notes
app.post("/api/notes", (req, res, next) => {
  const { title, note } = req.body;
  const _note = new Note({
    title: title,
    note: note,
  });
  _note.save((err, note) => {
    if (err) {
      return res.status(404).json(err);
    }
    //Store in Redis
    client.setex(note.id, 60, JSON.stringify(note), (err, reply) => {
      if (err) {
        console.log(err);
      }
      console.log(reply);
    });
    return res.status(201).json({
      message: "Note has been saved",
      note: note,
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

Take look here in the code, we used a method setex to store data in Redis.

This method takes 4 parameters

  1. id : Unique ID must be provided to store data. It must be a string.

  2. seconds : Expiry time in seconds as a number.

  3. value : Actual data to store in Redis. It must be a string. So we are serializing object into string .

  4. callback : Callback takes two parameters err and reply.

Create a note
Create a note<br>

Now retrieve data, first, we have to check in Redis for data, if data is not available in Redis then we have to make a query in the database.

For that, we have to write middleware that checks the requested data in Redis.

Middleware:

const isCached = (req, res, next) => {
  const { id } = req.params;
  //First check in Redis
  client.get(id, (err, data) => {
    if (err) {
      console.log(err);
    }
    if (data) {
      const reponse = JSON.parse(data);
      return res.status(200).json(reponse);
    }
    next();
  });
};
Enter fullscreen mode Exit fullscreen mode

In the above middleware, we used get() method to retrieve existing data from Redis. get(id, callback()).

Here we parsed string back to the object.

Now use this middleware on get request:

app.get("/api/notes/:id", isCached, (req, res, next) => {
  const { id } = req.params;
  Note.findById(id, (err, note) => {
    if (err) {
      return res.status(404).json(err);
    }
    return res.status(200).json({
      note: note,
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

First time retrieves data. It took 11ms
First time retrieves data. It took 11ms<br>

Next, we retried to get data, It took 5ms
Next, we retried to get data, It took 5ms.<br>

Code

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const redis = require('redis');

const app = express();

app.use(bodyParser.json());

//Redis connection
var client = redis.createClient({
  host: "eu1-capital-cattle-31290.upstash.io",
  port: "31290",
  password: "YOUR_REDIS_PASSWORD",
});
client.on("error", function (err) {
  throw err;
});

//MongoDB connection
mongoose.connect('mongodb://localhost:27017/', {
    dbName: 'notes',
    useNewUrlParser: true,
    useUnifiedTopology: true
}, err => err ? console.log(err) : console.log('Connected to database'));

//Mongoose Model
const NoteSchema = new mongoose.Schema({
    title: String,
    note: String
});

const Note = mongoose.model('Note', NoteSchema);

//Create notes
app.post('/api/notes', (req, res, next) => {

    const { title, note } = req.body;

    const _note = new Note({
        title: title,
        note: note
    });

    _note.save((err, note) => {
        if (err) {
            return res.status(404).json(err);
        }

        //Store in Redis
        client.setex(note.id, 60, JSON.stringify(note), (err, reply) => {
            if (err) {
                console.log(err);
            }
            console.log(reply);
        });

        return res.status(201).json({
            message: 'Note has been saved',
            note: note
        });
    })

});

const isCached = (req, res, next) => {

    const { id } = req.params;

    //First check in Redis
    client.get(id, (err, data) => {
        if (err) {
            console.log(err);
        }
        if (data) {
            const reponse = JSON.parse(data);
            return res.status(200).json(reponse);
        }
        next();
    });
}

app.get('/api/notes/:id', isCached, (req, res, next) => {

    const { id } = req.params;

    Note.findById(id, (err, note) => {
        if (err) {
            return res.status(404).json(err);
        }
        return res.status(200).json({
            note: note
        });
    });
});

app.listen(3000, () => console.log('Server running at port 3000'));
Enter fullscreen mode Exit fullscreen mode

Check out Upstash for production: https://upstash.com/

💖 💪 🙅 🚩
pprathameshmore
Prathamesh More

Posted on March 22, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related