Koa Js : Part 5 - how to connect a caching database to your Koa Js server
Tags: javascript, tutorial, node, webdev
Published: 2022-07-12 13:39:00

Caching is the storing of data temporarily and retrieving data from a high-performance store (usually memory) either explicitly or implicitly.

**Advantage**: When using external api's, you may have a restricted number of calls or cost per api call. If your api data doesn't constantly update, this not only reduces the number of api calls made but also reduces the loading speed.

In this tutorial, we'll be storing data temporarily in our **`Koa JS`** server using **`node-cade`**.

Before you start this part, make sure you have read [**part 1**](https://github.com/tutorial-point/koa-server-tutorial) of this tutorial series as we're gonna be starting from there.

If you want to follow along, fork or clone [**part 1**](https://github.com/tutorial-point/koa-server-tutorial) before you continue.

## Packages

Let's start by installing the packages that we need:

```
npm i node-cache axios
```

### What are we installing?

1. **`node-cache`** - this is the package we'll use to store our data temporarily.
2. **`axios`** - this is what we'll use to fetch our data.

## Middleware

We'll need to create **`middleware`** folder, a **` cache.js`** and a **`crypto.cache.js`** file, so run the following command in your terminal:

```bash
mkdir middleware
touch middleware/cache.js middleware/crypto.cache.js
```

Now let's add the following to the **`cache.js`** file located in the **`middleware`** folder:

```javascript
const NodeCache = require("node-cache");
const shortCache = new NodeCache({ stdTTL: 60 * 15 });

module.exports = {
  shortCache,
};
```

### What is happening?

We've just created a cache and named it **`shortCache`**, we've then set the time using **`stdTTL`** key. This key is measured with seconds, so in this case we've set 60 seconds multiplied by 15. Therefore, our cache is 15 minutes long. Keep that in mind moving forward.

We'll now add the following to our **`crypto.cache.js`** file:

```javascript
const { shortCache } = require("./cache");

const cryptoListCache = (ctx, next) => {
  try {
    if (shortCache.has("crypto-list")) {
      return (ctx.body = shortCache.get("crypto-list"));
    }
    return next();
  } catch (err) {
    ctx.status = 500;
    console.log(err);
    throw err;
  }
};

module.exports = {
  cryptoListCache,
};
```

### What is happening?

This cache will be used as middleware. If the cache has a key named **`crypto-list`** then it will return the value stored in the key. However, if there isn't then the middleware is skipped. This is important to note as later we'll be setting the key and storing a data in the cache.

## Helpers

For our api data, we will be using [**`this endpoint`**](https://www.cryptingup.com/api/markets) to get our crypto data.

We'll only be returning parts of the data so before we make the api call, let's create a helper function to manipulate the response data.

Run the following command:

```bash
mkdir helpers
touch helpers/crypto.helpers.js
```

This should return a directory named **`helpers`** which containing a file named **`crypto.helpers.js`**.

For each crypto object, we'll only be returning the following keys **`exchange_id`**, **`symbol`**, **`price`**, **`spread`**, **`change_24h`**, **`volume_24h`** and **`updated_at`**.

Copy the following code into the **`crypto.helpers.js`** in the **`helpers`** directory:

```javascript
const cryptoRender = ({ markets }) => {
  return markets.map((crypto) => {
    const {
      exchange_id,
      symbol,
      price,
      spread,
      change_24h,
      volume_24h,
      updated_at,
    } = crypto;

    return {
      exchangeId: exchange_id,
      symbol,
      price,
      spread,
      "24hChange": change_24h,
      "24hVolume": volume_24h,
      updated_at,
    };
  });
};

module.exports = {
  cryptoRender,
};
```

This is what we've done:

1. Deconstruct the keys from each object.
2. Changed the keys which were underscore to camel case.
3. Returned only the fields we need from the data

_Note: If the when passing a value, if the value has the same name as the key, you don't need to type it twice. For example, we did not need to type **symbol: symbol**. This applies above to **`symbol`, `price`, `spread` and `updated_at`.**_

## Services

We'll now create some service files to handle external api calls.

Run the following commands:

```bash
mkdir services
touch services/request.services.js services/crypto.services.js
```

We should now have a **`services`** directory with two files:

1. **`request.services.js`** - this where we'll use axios to make our api request functions.
2. **`crypto.services.js`** - this where we'll import our request functions to make requests for our crypto data.

So let's add this to your **`request.services.js`** file:

```javascript
const { request } = require("axios");

const getRequest = async (url) => {
  try {
    const res = await request({
      method: "GET",
      url,
    });
    return res.data;
  } catch (err) {
    console.log(err);
    throw err;
  }
};

module.exports = {
  getRequest,
};
```

### What did we do?

1. We first import **`request`** from **`axios`**
2. created a async function named **`getRequest`** to handle our api calls
3. return only the response data from the api call.

Now let's add the following code to your **`crypto.services.js`** file:

```javascript
const { cryptoRender } = require("../helpers/crypto.helpers");
const { getRequest } = require("./request.services");

const getCryptoData = async () => {
  try {
    const resData = await getRequest("https://www.cryptingup.com/api/markets");

    return cryptoRender(resData);
  } catch (err) {
    console.log(err);
    throw err;
  }
};

module.exports = {
  getCryptoData,
};
```

### What did we do?

1. Imported the **`getRequest`** function that we just made.
2. Created an async function named **`getCryptoData`** to fetch our data from [**https://www.cryptingup.com/api/markets**](https://www.cryptingup.com/api/markets).
3. Pass our data through the **`cryptoRender`** helper function we made earlier before returning the result.

## Controllers

Now our api calls are sorted, we need to create a controller for our crypto data.

Let's create the controller using:

```bash
touch controllers/crypto.controllers.js
```

Now let's add the following to our **`controllers/crypto.controllers.js`**

```javascript
const { shortCache } = require("../middleware/cache");
const { getCryptoData } = require("../services/crypto.services");

const getCryptoList = async (ctx) => {
  try {
    const resData = await getCryptoData();
    shortCache.set("crypto-list", resData);
    ctx.body = resData;
    ctx.status = 200;
  } catch (err) {
    ctx.body = "Error!";
    ctx.status = 500;
    console.log(err);
    throw err;
  }
};

module.exports = {
  getCryptoList,
};
```

### So what is happening?

Here's what we're doing:

1. Imported our cache (**`shortCache`**) and our crypto service (**`getCryptoData`**) to our controller.
2. Created an async function to handle errors that may arise.
3. Called our **`getCryptoData`** function and await the response data.
4. Stored the response data in the cache under **`"cryto-list"`**.
5. Return the response data.

The first request we make will take a couple seconds as we are interacting with an external api.

Once the cache sets our data under **`"crypto-list"`**, for the given duration - our middleware will detect that **`"crypto-list"`** has data stored and will return that data rather than executing our controller.

## Router

Finally let's update our router with the following code:

```javascript
const Router = require("koa-router");
const router = new Router();
const { cryptoListCache } = require("./middleware/crypto.cache");
const { getCryptoList } = require("./controllers/crypto.controllers");
const { getEvents, postEvent } = require("./controllers/events.controllers");

router.get("/crypto_list", cryptoListCache, getCryptoList);
router.get("/events_list", getEvents);
router.post("/post_event", postEvent);

module.exports = router;
```

So now we've add our crypto route with our middleware and controller. 

Let's start our server again, run this command to start our server:
```bash
node index.js
```

Let's test it out [**`http://127.0.0.1:8000/crypto_list`**](http://127.0.0.1:8000/crypto_list).

And that's all she wrote! Thanks for following this tutorial. The repo for this code can be found [here](https://github.com/tutorial-point/koa-cache-tutorial/blob/master/README.md)