# Implement Redis caching with ExpressJS

In this article, we are going to create a simple ExpressJS project which will call a `starwars` API to fetch its movie character details. This API is provided by  [Swapi](https://pipedream.com/apps/swapi) . You can find the code for this at  [Github](https://github.com/qualascend/starwars-redis-express) .

## Installing Redis
Redis is an open-source, key-value database. It is widely used for caching as an in-memory data structure. It can also be used as a persistence database.

### Windows
On windows, you can install Redis by downloading it from https://github.com/dmajkic/redis/downloads after unzip run the executable file.

### Mac
On Mac, you can use a Homebrew package manager.

If homebrew is not already installed you can install it by running the following command

```
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
``` 
Once Homebrew is installed you can install Redis

```
brew install redis
``` 

### Docker
The best way to get Redis running quickly on any operating system is using Docker.

Once docker is successfully installed you can execute the following command to run Redis in the background.

```
docker run --name some-redis -d redis
``` 

## Setting up our project
Let's start by creating our project directory and `cd` into it.
```
mkdir starwars-redis-express
cd starwars-redis-express
```

Initialize a NodeJS project passing the `-y` flag which accepts all the defaults.

```npm init -y```

For this project, we will use ExpressJS as our web framework, Node Fetch library to call starwars API, and Redis library to communicate with Redis.

Install express, node-fetch, and Redis

```npm i express node-fetch redis```

Install `nodemon` as a dev dependency so that we don’t have to manually restart the server again and again after every change.

```npm i -D nodemon```

Open `package.json` and add a script like this
```
"scripts": {
  "start": "nodemon index"
}
```
Now let's create a simple express server.

Create `index.js` file
```
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/startwars/people', (req, res) => {
  res.send('Star Wars');
});
app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}`);
});
```

Now let's run the server by executing the command npm run start.

If you visit `http://localhost:3000/starwars/people` you should see a text **Star Wars** on your browser.

The endpoint is `startwars` because we are going to consume Star Wars API from https://swapi.co/ in this example app.

Let’s call the star wars actual API to fetch the results and send them to the client.

First import the nodefetch libaray

```const fetch = require('node-fetch')```

create an `async` function to call startwars API.
```
const getPeople = async (req, res, next) => {
  try {
    const { id } = req.params;
    console.log(`Fetching people data for id ${id}`);
    const response = await fetch(
      `https://swapi.co/api/people/${req.params.id}`
    );
    const people = await response.json();
    res.send(getResponse(people));
  } catch (err) {
    console.error(err);
    res.status(500);
  }
};
```
Implement the getResponse function use above
```
const getResponse = (people) => {
  const { name, height, gender } = people;
  return `
    <ul>
      <li>Name: ${name}</li>
      <li>Height: ${height}</li>
      <li>Gender: ${gender}</li>
    </ul>
  `;
}
```

Change our API definition to include `id` as the URL parameter

```app.get('/startwars/people/:id', getPeople);```

Above API calls the `getPeople` function which then calls the `starwars` API to fetch person data by `id`.

Now if you visit URL `http://localhost:3000/startwars/people/1` you should get a below response

![1_-C4T8P8VC61j400ghh5Fbg.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638175926034/y76RgvQDj.png)

If you check the network logs in the browser our API call approximately take 2 sec to respond.

![1_eIUTHnuqZ3HVP0HTZy0FEw.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638176767746/C-3AbDufz.png)

Now let's add caching to our API to make it faster

Import the Redis package

```const redis = require('redis');```

Connect to Redis client
```
const REDIS_PORT = process.env.REDIS_PORT || 6379;
const client = redis.createClient(REDIS_PORT);
```

Create a middleware function to return the cached response if available
```
const cachePeople = (req, res, next) => {
  const { id } = req.params;
  client.get(id, (err, data) => {
    if (err) throw err;
    if (data !== null) {
      res.send(getResponse(JSON.parse(data)));
    } else {
      next();
    }
  });
};
```
This function checks if there is an entry against the id in Redis. If it finds one it will return the cached result other will return next() which will allow continuing with the normal API call.

Change the API call line to make use of the above middleware.

```app.get('/startwars/people/:id', cachePeople, getPeople);```

Last we need to add a line in our `getPeople` function right before we send the response to the client to set an entry in Redis after fetching result from `starwars` API.
```
client.set(id, JSON.stringify(people), 'EX', 3600);
res.send(getResponse(people));
```

This will create a cache entry with key `id` for 3600 sec.

Now if you visit the URL `http://localhost:3000/startwars/people/1` first time it will take around ~2sec to load if you refresh it you will see response time will be less than ~10ms

![1_JITCfYFxOG3d-t00q1_gJQ.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638176052175/WKd0p1VJdK.png)


If you change the `id` from 1 to 2 again the first response time will be high but further requests will be served from the cache until the cache entry expires.

That’s it, you check out the code on GitHub.

This article is inspired by Brad’s video tutorial https://www.youtube.com/watch?v=oaJq1mQ3dFI. Follow it to learn a lot of cool things.

Thanks
