DEV Community

Kachi Cheong
Kachi Cheong

Posted on • Updated on

Koa Js : Part 5 - how to connect a caching database to your Koa Js server

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 of this tutorial series as we're gonna be starting from there.

If you want to follow along, fork or clone part 1 before you continue.

Packages

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

npm i node-cache axios
Enter fullscreen mode Exit fullscreen mode

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:

mkdir middleware
touch middleware/cache.js middleware/crypto.cache.js
Enter fullscreen mode Exit fullscreen mode

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

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

module.exports = {
  shortCache,
};
Enter fullscreen mode Exit fullscreen mode

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:

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,
};
Enter fullscreen mode Exit fullscreen mode

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 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:

mkdir helpers
touch helpers/crypto.helpers.js
Enter fullscreen mode Exit fullscreen mode

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:

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,
};
Enter fullscreen mode Exit fullscreen mode

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:

mkdir services
touch services/request.services.js services/crypto.services.js
Enter fullscreen mode Exit fullscreen mode

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:

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,
};
Enter fullscreen mode Exit fullscreen mode

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:

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,
};
Enter fullscreen mode Exit fullscreen mode

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.
  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:

touch controllers/crypto.controllers.js
Enter fullscreen mode Exit fullscreen mode

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

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,
};
Enter fullscreen mode Exit fullscreen mode

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:

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;
Enter fullscreen mode Exit fullscreen mode

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:

node index.js
Enter fullscreen mode Exit fullscreen mode

Let's test it out 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

Top comments (0)