How to cache data with Express and node-cache - a 10 minute tutorial
Kachi Cheong
Posted on June 29, 2022
What is caching?
Caching is the storing of data temporarily and retrieving that same data for a declared duration.
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.
Installation
Firstly, navigate to the directory where you would like to store your project from your terminal. Let's start by making our project.
Run the following command in your terminal:
mkdir cache-project
cd cache-project
Now let's initiate our package.json
file with the default parameters and install our packages with the following commands:
npm init -y
npm i express node-cache axios cors
These commands should create a package.json which looks like this:
{
"name": "cache-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.27.2",
"cors": "^2.8.5",
"express": "^4.18.1",
"node-cache": "^5.1.2"
}
}
Now let's breakdown the packages:
- axios - We'll use this package to make our api calls
- cors - This will enable our server to interact with our client.
- express - Our server of course.
- node-cache - This is our cache middleware package.
Server and Router
We'll now create our server and router:
touch index.js router.js
Let's paste the following code into our index.js
file:
const express = require("express");
const cors = require("cors");
const router = require("./router");
const App = express();
const Port = 8000; // Our server port
App.use(express.json());
App.use(cors());
App.use(router);
App.listen(Port, () => {
console.log(`Cache app listening at http://localhost:${Port}/`);
});
Let's quickly breakdown what we've just done:
- Created our server and declared it on port
8000
. - Added our parser using
express.json
, added ourcors
androuter
(which we will add shortly). - Add a listener to signal our server is running.
Let's move onto our router, paste the following code to our router.js
file:
const { Router } = require("express");
const router = Router();
router.get("/", (req, res) => {
res.send("Cache Project Home Page");
res.status(200);
});
module.exports = router;
This is just a router with a default home route which is then exported.
Middleware
Let's now move onto our middleware.
Firstly, we'll create a middleware
folder and a file which we'll call crypto.cache.js
. Run the following commands:
mkdir middleware
touch middleware/crypto.cache.js
Next, add the following to our crypto.cache.js
:
const Cache = require("node-cache");
const cryptoCache = new Cache({ stdTTL: 60 * 5 });
const cryptoCacheMiddleware = (req, res, next) => {
try {
if (cryptoCache.has("crypto-list")) {
return res.send(cryptoCache.get("crypto-list")).status(200);
}
return next();
} catch (err) {
console.log(err);
throw err;
}
};
module.exports = {
cryptoCacheMiddleware,
cryptoCache,
};
Let's breakdown what we've just done.
- Imported
node-cache
and set thenew Cache
to 5 minutes({ stdTTL: 60 * 5 })
- We'll make an async middleware function name
cryptoCacheMiddleware
. - Like any controller in express our middleware will take a
req
andres
argument. In addition to this we'll add anext
to skip this function if the conditions of our if statement is not met. - The
cryptoCache
checks if somethinghas
been stored under the namecrypto-list
- If something is stored under
crypto-list
then theget
will return it rather than skipping to the controller.
Services
Now we'll create a services
folder which will store all our api calls.
mkdir services
touch services/fetch.js services/crypto.services.js
First, let's create a async fetch function using axios. Paste the following code into our fetch.js
file.
const axios = require("axios");
const FetchApi = async (url) => {
try {
const res = await axios.get(url);
return res.data;
} catch (err) {
console.log(err);
throw err;
}
};
module.exports = FetchApi;
This is a service function which we'll use to pass a url to make our api calls. By making it a seperate function, it becomes reusable and we won't have to import axios
and export the .data
from the response every time.
Next, we'll import that FetchApi
function into our crypto.services.js
file and create our api call.
const FetchApi = require("./fetch");
const cryptoApi = async (amount) => {
try {
const result = await FetchApi(
"https://api2.binance.com/api/v3/ticker/24hr"
);
return result.slice(0, amount);
} catch (err) {
console.log(err);
throw err;
}
};
module.exports = {
cryptoApi,
};
Let's quickly breakdown the code:
- We've made an async function which takes the argument name
amount
. - Then we'll use
FetchApi
to make an api call from:https://api2.binance.com/api/v3/ticker/24hr
- Finally we'll return the results and the number of results is determined by our amount argument.
Controllers
Finally we'll create our controllers so let's run the following command in our terminal:
mkdir controllers
touch controllers/crypto.controllers.js
This should return a directory named controllers
contianing a file named crypto.controllers.js
.
const { cryptoCache } = require("../middleware/crypto.cache");
const { cryptoApi } = require("../services/crypto.services");
const cryptoController = async (req, res) => {
try {
const data = await cryptoApi(25);
cryptoCache.set("crypto-list", data);
res.send(data);
res.status(200);
} catch (err) {
res.status(500);
console.log(err);
throw err;
}
};
module.exports = {
cryptoController,
};
Updating our router
Finally let's update router.js
file but adding our middleware and controller.
const { Router } = require("express");
const router = Router();
const { cryptoController } = require("./controllers/crypto.controllers");
const { cryptoCacheMiddleware } = require("./middleware/crypto.cache");
router.get("/", (req, res) => {
res.send("Cache Project Home Page");
res.status(200);
});
router.get("/crypto", cryptoCacheMiddleware, cryptoController);
module.exports = router;
Run the server:
node index.js
Running our server
Make the a GET request using the following link: http://localhost:8000/crypto.
You'll notice that the first call will take a couple seconds, but then if you re-run the call, for the next 5 minutes, it will return the same result from your first call instantly.
And that's all she wrote, quick and painlesss! Thanks for reading!
Here is the github repo!
Posted on June 29, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.