Caching in NodeJS with Redis
Tags: node, webdev
Published: 2021-01-12 14:33:10

Full post available [here](https://taslangraham.com/2021/01/12/caching-in-nodejs-with-redis/).
<!-- wp:paragraph -->
<p>Speed performance is critical in modern-day applications. Most of the time your application may have to make requests to an endpoint/server to get some data. Or your application may frequently request a specific dataset. <br><br>Depending on the size of your dataset along with other things like query database and network speed, the speed at which your application can fetch certain data to display to users may get slower over time (as data increases).<br><br>This is where caching comes in handy and can dramatically improve your application's speed. In this tutorial we will look at how to implement redis caching in a node application  (API) to improve the speed at which we are able to serve data to client apps. Let's dive in!</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>What is Caching</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Before we dive into creating our own Redis cache, we have to first answer the question of <em>what is caching</em>?  <br><em><strong>In computing, a cache is a high-speed data storage layer which stores a subset of data, typically transient(existing for a short  period of time) in nature, so that future requests for that data are served up faster than is possible by accessing the data’s primary storage location. Caching allows you to efficiently reuse previously retrieved or computed data</strong></em> -  <a href="https://aws.amazon.com/caching/">https://aws.amazon.com/caching/</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Here's a scenario to help you think about how caching works. Imagine you're watching your favorite sport (Soccer/Football for me ) or the news or a movie.<br> <br>You're also a big fan of Potato chips, so you decide that every 15 minutes you'll go to the kitchen to get a little potato chips to eat.<br> <br>You then noticed that going to the kitchen every 15 minutes is time consuming, not to mention the fact that you miss out a minute or two of what you're watching.<br> <br>So instead of repeatedly making trips to the kitchen you decide fill a large bowl with chips and have it right next to you while watching the TV. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now you can get your chips much faster and you don't need to go back to the kitchen unless your bowl is empty or you want a different kind or chips/snack . That bowl of chips is your cache. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In the world of IT, caching is similar. Data is stored somewhere (the bowl) where it can be accessed fast without having to go to the original source (the kitchen) unless the data needed is not inside the bowl.<br></p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>What is Redis</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Seeing that we will be using Redis to implement caching inside our node application it makes sense to first discuss what is Redis. Redis is an in memory key value pair database. Yes, you read that right, Redis stores data in memory (RAM). <br>Reading and writing to RAM is magnitudes faster than reading from a disk drive. This makes Redis perfect for caching.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Benefits of caching</h2>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li>Redis cache uses RAM as its storage (more on this further down) which is faster than disk storage, reading from cache is extremely fast. Being able to  read data at higher rates will significantly improve application performance.<br></li><li>Caching  frequently requested data will result in a reduction in the number of database queries needed retrieved particular data.<br></li><li>Following up on the previous benefit, if we are making less database queries or even less network request to fetch external resources then our application will have lower latency.<br></li><li>Your application can scale better since you can cache that is requested more frequently as more person uses your application.</li></ul>
<!-- /wp:list -->

<!-- wp:heading -->
<h2>Node App</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Now that we understand what caching is and got an introduction to Redis  we will create a node application that utilizes caching through Redis.<br>Our application will be a simple e-commerce API server that allows users to fetch a list products. Let's start coding!</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Create a folder name node-redis-cache (or whatever you like )</li><li>open the folder inside your text editor(I use VScode)</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>We'll be using a few npm packages in our app:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>express - handle routing in our app</li><li>redis - use redis commands in node</li><li>axios - to make API calls</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Open your terminal inside the project folder (<em>node-redis-cache</em>) and run the following command to install the needed packages:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong><em>npm install express redis axios</em></strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The command above installs the express, redis, and axios packages</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Create Server</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Now lets finally write some code. We'll first create our express server. Create a file name <em>index.js</em>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Add the  following imports to <em>index.js</em></p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"jscript"} -->
<pre class="wp-block-syntaxhighlighter-code">const express = require('express'); 
const app = express();
const axios = require('axios');
const PORT = 9000;

const redis = require("redis");
const cacheClient= redis.createClient(); // redis client used to interact with redis database

app.listen(PORT, () => console.log(`listening on port ${PORT}`));</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>We've created our server and set it to listen on port 9000. We've also required in the redis and axios packages which we'll use later on.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3><br>Route</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Now we'll add a route that returns a list of products to the user. Add the following to <em>index.js</em></p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"jscript"} -->
<pre class="wp-block-syntaxhighlighter-code">app.get('/products', async (req, res) => {
  const { data } = await axios.get('https://fakestoreapi.com/products'); // This is a real API ;)
  return res.send(data);
});</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>Here we've created a route handler for <strong><em>/products</em></strong> that will return a list of products. We are making a request to an external API to get these products.<br><br>Lets assume that this external API also makes a database request get this list of products. As you can see, when a user requests the list of available products it may take a while for them to get a response. </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>API Speed (without cache)</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Let's test our endpoint using <a rel="noreferrer noopener" href="https://www.postman.com/" target="_blank">postman</a> (or your favorite API testing tool).  This will show us the speed performance of our application without caching.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":1193,"sizeSlug":"large","linkDestination":"media"} -->
<figure class="wp-block-image size-large"><a href="https://taslangraham.files.wordpress.com/2021/01/request-1.jpg"><img src="https://taslangraham.files.wordpress.com/2021/01/request-1.jpg?w=1024" alt="" class="wp-image-1193"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Without caching implemented our API request takes <strong>1540 milliseconds</strong> (or 1.54 seconds) to be processed. Now let's add caching to our route handler.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Adding caching</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Update the <em><strong>/products</strong></em> route handler to the following. </p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"jscript"} -->
<pre class="wp-block-syntaxhighlighter-code">app.get('/products', async (req, res) => {
    const TIME_TO_LIVE = 1800; // 30 minutes as seconds

    cacheClient.get("products", async (err, cachedProducts) => {
        if (cachedProducts) {
            res.send(JSON.parse(cachedProducts));
        } else {
            const { data } = await axios.get('https://fakestoreapi.com/products');
            cacheClient.setex("products", TIME_TO_LIVE, JSON.stringify(data))
            return res.send(data);
        }
    });
});
</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>Here, we are changing how our <strong><em>/products</em></strong> route handler operates. When we get a request to fetch for products, we first check to see if we already have that data available in cache.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><br>If the cached data is available then we return that to the user. If there's no cached data available, we first make a call to the external API for the data.  Then we cache the newly fetched data. <br></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The <strong><em>sete</em>x()</strong><em> </em>method allows us to set the Time To Live (TTL) for the cached data. This means that after the specified amount of time (in seconds) the cached data will be deleted. Finally we return the data to the user.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>API Speed (with cache)</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>This will show us the speed performance of our application with caching implemented. Lets make a call to the API endpoint.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":1201,"sizeSlug":"large","linkDestination":"media"} -->
<figure class="wp-block-image size-large"><a href="https://taslangraham.files.wordpress.com/2021/01/request-3-1.jpg"><img src="https://taslangraham.files.wordpress.com/2021/01/request-3-1.jpg?w=1024" alt="" class="wp-image-1201"/></a></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Whoa, wait, that's not much faster! Why is that so? On the first request, there's no data in the cache, so we'd have to the make a call to the external API which will take some time. The fetched data is then cached and is available on subsequent requests. So, let's make another request.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":1202,"sizeSlug":"large","linkDestination":"media"} -->
<figure class="wp-block-image size-large"><a href="https://taslangraham.files.wordpress.com/2021/01/request-4.jpg"><img src="https://taslangraham.files.wordpress.com/2021/01/request-4.jpg?w=1024" alt="" class="wp-image-1202"/></a><figcaption>Now look at that! Our request took only <strong>2 milliseconds</strong> (or 0.002 seconds). That's fast, very fast compared to when we don't have cache implemented.<br><br>As you can see, caching can significantly improve your application's performance. There's a lot more to redis caching and caching in general. If you're interested in learning more about caching and redis, see the following links:</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>https://aws.amazon.com/caching/</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>https://www.cloudflare.com/learning/cdn/what-is-caching/</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>https://wp-rocket.me/blog/different-types-of-caching/</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>https://redis.io/documentation</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>https://www.npmjs.com/package/redis<br><br>If you found this helpful leave a comment below and share with devs who will find it useful. Until next time <em>think, learn, create, repeat</em>.</p>
<!-- /wp:paragraph -->