<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Osamuyi</title>
    <description>The latest articles on DEV Community by Osamuyi (@osamuyi).</description>
    <link>https://dev.to/osamuyi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F613945%2F66053e89-eb7c-434c-ba64-7ebfd0681b23.jpg</url>
      <title>DEV Community: Osamuyi</title>
      <link>https://dev.to/osamuyi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/osamuyi"/>
    <language>en</language>
    <item>
      <title>How to Cache Database Results with Redis in Node.js</title>
      <dc:creator>Osamuyi</dc:creator>
      <pubDate>Sun, 19 Nov 2023 05:00:09 +0000</pubDate>
      <link>https://dev.to/osamuyi/how-to-cache-database-results-with-redis-in-nodejs-b5b</link>
      <guid>https://dev.to/osamuyi/how-to-cache-database-results-with-redis-in-nodejs-b5b</guid>
      <description>&lt;p&gt;The speed with which an application responds to user queries is an important performance metric that the application can be rated by. A major factor that has been proven to improve the response speed of an application is caching. Caching helps to enhance the performance of distributed systems.&lt;/p&gt;

&lt;p&gt;When dealing with data that does not change too often, it is recommended that the results of the request be cached; this helps to reduce the number of API calls made to the database.&lt;/p&gt;

&lt;p&gt;There are several tools for caching; however, in this article, we will be using &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt;, an in-memory database that stores data in the server memory.&lt;/p&gt;

&lt;p&gt;This article will be focused on caching and how to perform caching on database results with Redis in Node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why should you perform caching?&lt;/strong&gt;&lt;br&gt;
There are several reasons why developers should employ caching in their applications, amongst which are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To reduce latency, thus reducing response time.&lt;/li&gt;
&lt;li&gt;To save or reduce costs. This is possible because caching reduces the load on the backend database(s), especially if the database charges per throughput.&lt;/li&gt;
&lt;li&gt;Caching can greatly improve the performance of your application and, in the long run, lead to user satisfaction.&lt;/li&gt;
&lt;li&gt;By implementing caching, developers can anticipate the performance of their applications, particularly during periods of high network requests.&lt;/li&gt;
&lt;li&gt;When data is stored in the cache, users can still access this data even when there is a network outage.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Prerequisite
&lt;/h3&gt;

&lt;p&gt;To follow through with this tutorial, a basic understanding of Node.js and how to build REST APIs' is required. You should have the following installed on your computer;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/download" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Redis: You can either have a local instance of Redis running on your local machine or use the Redis cloud service. For the purpose of this tutorial, we will be using a local instance of Redis.&lt;br&gt;
For Windows users, you can follow through on &lt;a href="https://www.youtube.com/watch?v=qTN0GqF_Gq8&amp;amp;t=87s" rel="noopener noreferrer"&gt;how to download and install Redis on your local computer&lt;/a&gt;. For other operating systems, check out &lt;a href="https://redis.io/docs/install/install-stack/" rel="noopener noreferrer"&gt;install Redis&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;RedisInsight: is a Redis Graphical User Interface (GUI) tool that helps with visualizing data stored in the Redis database. It also helps in monitoring real-time changes in the database. &lt;a href="https://redis.com/redis-enterprise/redis-insight/?_gl=1*1j606fs*_gcl_au*Mzk0OTcxNjI4LjE2OTkyNjYwMzA.*_ga*NjQxNTIzMzI0LjE2OTkyNjYwMzE.*_ga_8BKGRQKRPV*MTY5OTM4NTQwNC4yLjEuMTY5OTM5MDQ2MS41MC4wLjA" rel="noopener noreferrer"&gt;Download and install RedisInsight&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;
&lt;h5&gt;
  
  
  Step 1: Project Setup
&lt;/h5&gt;

&lt;p&gt;We will start with installing all the dependencies needed for this project and start an express server&lt;br&gt;
i. create the directory for the project using the &lt;code&gt;mkdir&lt;/code&gt; command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir node_cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ii. Navigate into the project directory using the &lt;code&gt;cd&lt;/code&gt; command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd node_cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;iii. Initialize your project and create a &lt;code&gt;package.json&lt;/code&gt; file in the root folder of the project directory using the &lt;code&gt;npm init&lt;/code&gt; command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-y&lt;/code&gt; flag accepts all default suggestions automatically.&lt;br&gt;
iv. Install the following dependencies from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;express&lt;/code&gt;, &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ioredis&lt;/code&gt;: a Redis client for Node.js which can be used to connect your application to the Redis server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fetch&lt;/code&gt; If you are using the latest version of Node (&amp;gt; version 17.5), then you don't need to install the fetch API, as it comes inbuilt with the latest Node version. You can also use the &lt;code&gt;axios&lt;/code&gt; API instead of the node fetch API, but to use &lt;code&gt;axios&lt;/code&gt; you will need to install the package from the npm store. For the purpose of this project, we will be using the inbuilt node &lt;code&gt;fetch&lt;/code&gt; API.
To install the required packages all at once
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm i express ioredis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;v. Now that the dependencies have all been installed, create an &lt;code&gt;app.js&lt;/code&gt; file in the root directory of your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch app.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Windows OS users, you can achieve the same method of file creation through &lt;strong&gt;Windows Powershell&lt;/strong&gt;, using the command &lt;code&gt;new-item&lt;/code&gt;. Thus to create an &lt;code&gt;app.js&lt;/code&gt; file in windows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new-item app.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also create the &lt;code&gt;app.js&lt;/code&gt; file in your preferred text editor.&lt;br&gt;
vi. Open the file in your preferred text editor. I will be using &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VS Code&lt;/a&gt; as my preferred text editor. In the &lt;code&gt;app.js&lt;/code&gt; file, we are going to create a simple Express server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');

const app = express();
const PORT = 3300;

app.listen(PORT, () =&amp;gt; {
  console.log(`App listening on port ${PORT}`);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step 2: Retrieve data from an API without caching
&lt;/h5&gt;

&lt;p&gt;We will make an API call to a third-party service, which, in turn, fetches data from a database, in order to retrieve the data we need. We will be making the API call from the Express server we built in step 1 above. Just so you know, the API call will be made without caching.&lt;br&gt;
To begin, still, inside your &lt;code&gt;app.js&lt;/code&gt; file, we will be making an API call to the &lt;a href="https://restcountries.com/v3.1/name/" rel="noopener noreferrer"&gt;REST COUNTRIES&lt;/a&gt; API to retrieve some data.&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;app.js&lt;/code&gt;, create a &lt;code&gt;GET&lt;/code&gt; route. The &lt;code&gt;GET&lt;/code&gt; method accepts two parameters, which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;route parameter: It defines what should happen when a request is made to that specific route, in this case, &lt;code&gt;'/country/:countryName'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;callback function
&lt;code&gt;app.get('/country/:countryName', async (req, res) =&amp;gt; {})&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: The usage of the &lt;code&gt;async&lt;/code&gt; keyword in the callback function of the &lt;code&gt;GET&lt;/code&gt; route above is necessary due to the asynchronous nature of the &lt;code&gt;fetch&lt;/code&gt; API. As the &lt;code&gt;fetch&lt;/code&gt; function is asynchronous, we use &lt;code&gt;async&lt;/code&gt; to declare the callback function as asynchronous. This allows us to use the &lt;code&gt;await&lt;/code&gt; keyword within the function to wait for the result of the &lt;code&gt;fetch&lt;/code&gt; API, ensuring that the data is fully retrieved before proceeding with further logic.&lt;/p&gt;

&lt;p&gt;In the body of the callback function for our &lt;code&gt;GET&lt;/code&gt; route, we will include a &lt;code&gt;try{} catch{}&lt;/code&gt; block to effectively manage and handle any runtime errors that may occur&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/country/:countryName', async (req, res) =&amp;gt; {  
  try {

  } catch (error) {

  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;try{} catch{}&lt;/code&gt; block, we will call the node &lt;code&gt;fetch&lt;/code&gt; API, which we will use to make an API call to &lt;a href="https://restcountries.com/v3.1/name/" rel="noopener noreferrer"&gt;REST COUNTRIES&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try {
   const data = await fetch(`https://restcountries.com/v3.1/name/${countryName}`)
  } catch (error) {
    console.log(error)
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When making a &lt;code&gt;fetch&lt;/code&gt; request, it's necessary to invoke the &lt;code&gt;.json()&lt;/code&gt; method on the response object to obtain the returned JSON data. Remember to include the &lt;code&gt;await&lt;/code&gt; keyword, as you might get unparsed JSON data without it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let result = await data.json();
    return res.status(200).send(result);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our final code output will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');

const app = express();
const PORT = 3300;

app.get('/country/:countryName', async (req, res) =&amp;gt; {
  const {countryName} = req.params;

  try {
    const data = await fetch(`https://restcountries.com/v3.1/name/${countryName}`);

let result = await data.json();
    return res.status(200).send(result);
  } catch (error) {
    console.log(error);
  }
});

app.listen(PORT, () =&amp;gt; {
  console.log(`App listening on port ${PORT}`);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can start our server by running &lt;code&gt;$ node app.js&lt;/code&gt; and then open any API test tool of your choice. I will be using &lt;a href="https://www.postman.com/downloads/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; for this. You can also download the &lt;a href="https://marketplace.visualstudio.com/items?itemName=Postman.postman-for-vscode" rel="noopener noreferrer"&gt;Postman VS code extension&lt;/a&gt;.&lt;br&gt;
The REST COUNTRIES API accepts many country's name initials, but we will use only the &lt;code&gt;eest&lt;/code&gt; as a route parameter on the endpoint we will be testing throughout this tutorial.&lt;br&gt;
In your postman, make a request to the country endpoint.&lt;br&gt;
&lt;code&gt;http://localhost:3300/country/eest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2mpl7rrfpvasvrbmaq9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2mpl7rrfpvasvrbmaq9.png" alt="postman_api_testing_without_caching" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the image displayed above, you'll notice that there's a highlighted section indicating that it takes approximately &lt;code&gt;1281 milliseconds&lt;/code&gt; for the request to be completed. This delay can be better optimized using caching, considering that the data being requested doesn't change frequently. Additionally, as your user base expands, the number of requests to this particular endpoint will increase, potentially leading to excessive strain on the database. But this issue can be resolved with caching&lt;/p&gt;
&lt;h5&gt;
  
  
  Step 3: Implementing Caching using Redis
&lt;/h5&gt;

&lt;p&gt;Here, we will begin by starting our Redis server. In your terminal (wsl for windows users or redis-cli), type &lt;code&gt;redis-server&lt;/code&gt;; this script will start the local redis server. &lt;br&gt;
&lt;strong&gt;PS&lt;/strong&gt;: You must have Redis installed in your computer.&lt;br&gt;
To confirm if your local redis instance is up and running, open another terminal window and type &lt;code&gt;redis-cli ping&lt;/code&gt;, and you will get back a response &lt;code&gt;PONG&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that our redis server is up, we are going to connect our Express application to the local Redis server.&lt;/p&gt;

&lt;p&gt;Firstly, inside your &lt;code&gt;app.js&lt;/code&gt; file, import the &lt;code&gt;ioredis&lt;/code&gt; module that was installed as a depency in step 1&lt;br&gt;
&lt;code&gt;const Redis = require('ioredis');&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;At the top of your &lt;code&gt;GET&lt;/code&gt; route in the &lt;code&gt;app.js&lt;/code&gt; file, create a function that connects to the Redis server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let client;
(() =&amp;gt; {  
    client = new Redis({
      port: 6379,
      host: '127.0.0.1',
    });

    client.on('connect', () =&amp;gt; {
      console.log('Connected to Redis yo!');
    });

    client.on('error', (error) =&amp;gt; {
      console.error(error);
    });
})();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, we declared a variable and then created an anonymous IIFE (Immediately Invoked Function Expression) function to connect our Express application to redis using &lt;code&gt;ioredis&lt;/code&gt;. The variable &lt;code&gt;client&lt;/code&gt; is declared outside of the IIFE function, so that it can be globally accessible outside of the function.&lt;/p&gt;

&lt;p&gt;Inside the function, we called the &lt;code&gt;new Redis()&lt;/code&gt; class to create a Redis instance and passed the connection parameters into the object. This method will come in handy if you are also trying to connect to the Redis cloud service. The new Redis instance is assigned to the &lt;code&gt;client&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;Also, call on the Node.js &lt;code&gt;on()&lt;/code&gt; method which registers events on whichever object it is called on (in this case, the ioredis object). The &lt;code&gt;on()&lt;/code&gt; method accepts two arguments; the name of the event and a callback function.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;client.on('connect', () =&amp;gt; {})&lt;/code&gt; function checks if the new Redis instance has successfully connected.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;client.on('error', () =&amp;gt; {})&lt;/code&gt; function checks if there is an error while trying to connect to the Redis server.&lt;/p&gt;

&lt;p&gt;Next, we are going to implement &lt;strong&gt;cache hit&lt;/strong&gt; logic. A cache hit is when data is successfully served from the cache memory. This code will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let cachedData = await client.get(countryName);
    if (cachedData ) {
      return res.status(200).send(JSON.parse(cachedData));
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ioredis &lt;code&gt;get()&lt;/code&gt; method is used to get data from the redis server. We pass the &lt;code&gt;countryName&lt;/code&gt; as an argument into the &lt;code&gt;get()&lt;/code&gt; method.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;if(cachedData){}&lt;/code&gt; conditional statement checks if the cachedData variable has data, if it returns true, this is known as a &lt;strong&gt;cache hit&lt;/strong&gt;. The cacheData variable is then converted to a JavaScript object using the &lt;code&gt;JSON.parse()&lt;/code&gt; method, and the result is returned to the user.&lt;/p&gt;

&lt;p&gt;After implementing the cache hit logic, next we will implement the &lt;strong&gt;cache miss&lt;/strong&gt; logic. This is what happens when the cache hit fails, meaning there is no data with that key name in the redis server. The code logic for the cache miss would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;client.set(countryName, JSON.stringify(result));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ioredis &lt;code&gt;set()&lt;/code&gt; method plays a crucial role in storing data on our Redis cache server. This method requires two arguments: the key and data (in this case, &lt;code&gt;countryName&lt;/code&gt; and &lt;code&gt;result&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To elaborate further, the first argument, &lt;code&gt;countryName&lt;/code&gt;, serves as the key under which the data is stored on the Redis server. It's essential to recall that &lt;code&gt;countryName&lt;/code&gt; is a dynamic value, initially parsed in our endpoint &lt;code&gt;'/country/:countryName'&lt;/code&gt;. Therefore, when users access the endpoint &lt;code&gt;'/country/eest'&lt;/code&gt;, the &lt;code&gt;countryName&lt;/code&gt; dynamically becomes and is stored as &lt;code&gt;eest&lt;/code&gt; on the Redis server.&lt;/p&gt;

&lt;p&gt;The second argument holds the result retrieved either directly from the database or through a third-party API call. To ensure compatibility, we employ the &lt;code&gt;JSON.stringify()&lt;/code&gt; method on the result. This step converts the obtained data into a JSON string. Also, recall that in our cache hit logic, when we retrieve data using the &lt;code&gt;get()&lt;/code&gt; method, we subsequently use &lt;code&gt;JSON.parse()&lt;/code&gt; on the &lt;code&gt;cachedData&lt;/code&gt;. This action converts the data back into a JavaScript object, ensuring seamless integration into our application's logic.&lt;/p&gt;

&lt;p&gt;Your updated code should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const Redis = require('ioredis');

const app = express();
const PORT = 3300;

// Connect to the redis server
let client;
(() =&amp;gt; {
  client = new Redis({
    port: 6379,
    host: '127.0.0.1',
  });

  client.on('connect', () =&amp;gt; {
    console.log('Connected to Redis yo!!');
  });

  client.on('error', (error) =&amp;gt; {
    console.error(error);
  });
})();


app.get('/country/:countryName', async (req, res) =&amp;gt; {
  const {countryName} = req.params;

  try {
    //cache hit
    let cachedData = await client.get(countryName);

    if (cachedData) {
      return res.status(200).send(JSON.parse(cachedData));
    }

const data = await fetch(`https://restcountries.com/v3.1/name/${countryName}`);

    let result = await data.json();

    //cache miss
    client.set(countryName, JSON.stringify(result));

    return res.status(200).send(result);
  } catch (error) {
    console.log(error);
  }
});

app.listen(PORT, () =&amp;gt; {
  console.log(`App listening on port ${PORT}`);
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save your code and navigate to Postman to test the endpoint&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ufgxc29ajmxt38t46bl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ufgxc29ajmxt38t46bl.png" alt="API call withought caching" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the above image, we can see that the response time was high (1789ms). When we requested the data from the endpoint, the API call was made directly to the Rest Countries API, the &lt;code&gt;cachedData&lt;/code&gt; variable returns null because there is no data with the key &lt;code&gt;countryName&lt;/code&gt; stored in our Redis cache server yet. Thus there is a cache miss, then the rest codes after the &lt;code&gt;if(cachedData){}&lt;/code&gt; condition would run, and eventually, the data is saved to the Redis cache server. &lt;/p&gt;

&lt;p&gt;If you make the same request to the same API endpoint as shown below, you will see that the response time would significantly reduce, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45ln0p4x6jpdt4ydkwv8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45ln0p4x6jpdt4ydkwv8.png" alt="caching implemented" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the image above, we can see that it took 311ms to return data to the user, this is because, the data was already saved in the Redis server, thus faster retrieval. &lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The significance of caching in software development cannot be overstated. Its impact extends beyond just enhancing our application; it also plays a crucial role in cost savings, particularly when our service/application relies on data from paid API services or databases.&lt;/p&gt;

&lt;p&gt;The complete code can be found &lt;a href="https://github.com/Muyixone/Caching-with-Redis-Tutorial/tree/main" rel="noopener noreferrer"&gt;Here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>api</category>
      <category>caching</category>
    </item>
    <item>
      <title>Count Number of Times an Item Appears in an Array</title>
      <dc:creator>Osamuyi</dc:creator>
      <pubDate>Sat, 15 Apr 2023 11:32:23 +0000</pubDate>
      <link>https://dev.to/osamuyi/count-number-of-times-an-item-appears-in-an-array-56eh</link>
      <guid>https://dev.to/osamuyi/count-number-of-times-an-item-appears-in-an-array-56eh</guid>
      <description>&lt;p&gt;JavaScript array methods are very powerful functions(methods) that have abstracted a lot of their functionalities. These methods help developers ease the manipulation of arrays to achieve the desired result.&lt;br&gt;
check &lt;a href="https://javascript.info/array-methods" rel="noopener noreferrer"&gt;array methods&lt;/a&gt; for a list of some array methods in JavaScript.&lt;/p&gt;

&lt;p&gt;For example; imagine you are working with the array below and are required to count the number of times each element in the array appears.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const data = [
  'car',
  'car',
  'truck',
  'truck',
  'bike', 'SUV', 'van','car',
  'walk',
  'car',
  'van',
  'bike',
  'walk',
  'car',
  'van',
  'car',
  'truck',
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A couple of array methods can be used to get the desired result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Count the number of items using &lt;code&gt;reduce()&lt;/code&gt; method
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//set the result to a variable
let itemsObject = data.reduce((accumulator, item) =&amp;gt; {
  if (accumulator[item]) {
    ++accumulator[item];
} else {
    accumulator[item] = 1;
}
return accumulator;
}, {})


//USING TENARY OPERATOR
let itemsObject = data.reduce((accumulator, item) =&amp;gt; {
 return accumulator[item] ? ++accumulator[item] : (accumulator[item] = 1), accumulator
}, {})


console.log(itemsObject)
/*
 {
  bike: 2,
  car: 6,
  SUV: 1,
  truck: 3,
  van: 3,
  walk: 2
}
*/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;reduce()&lt;/code&gt; is a method that helps in getting the number of occurrences of each item in an array.&lt;/p&gt;

&lt;h3&gt;
  
  
  Count the number of items using &lt;code&gt;for of&lt;/code&gt; loop
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;for of&lt;/code&gt; loop is a modification of the &lt;code&gt;for loop&lt;/code&gt;. It makes it easier to iterate through iterables such as arrays, maps, strings etc. It functions operates just like the &lt;code&gt;forEach()&lt;/code&gt; method. The major difference between the &lt;code&gt;for of&lt;/code&gt; loop and &lt;code&gt;forEach()&lt;/code&gt; method is that, the &lt;code&gt;for of&lt;/code&gt; loop is more compatible with &lt;code&gt;async&lt;/code&gt; functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//initialize an empty object to store the items
let countVal = {};
for (val of data) {
  if (countVal[val]) {
    countVal[val] += 1;
  } else {
    countVal[val] = 1;
  }
}

console.log(countVal)
/*
 {
  bike: 2,
  car: 6,
  SUV: 1,
  truck: 3,
  van: 3,
  walk: 2
 }
*/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Several other array methods can also be used to accomplish this task, however, if you need to count the number of items present in an array, using the &lt;code&gt;for of&lt;/code&gt; loop is preferable because of its compatibility with &lt;code&gt;async&lt;/code&gt; functions. The &lt;code&gt;reduce()&lt;/code&gt; method is also a good option to use. &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>array</category>
    </item>
    <item>
      <title>Solving Leetcode's "Richest Customer Wealth" Challange with Javascript</title>
      <dc:creator>Osamuyi</dc:creator>
      <pubDate>Tue, 21 Feb 2023 12:54:07 +0000</pubDate>
      <link>https://dev.to/osamuyi/solving-leetcodes-richest-customer-wealth-challange-with-javascript-59p4</link>
      <guid>https://dev.to/osamuyi/solving-leetcodes-richest-customer-wealth-challange-with-javascript-59p4</guid>
      <description>&lt;p&gt;This problem was quite challenging for me at the beginning, cos one needs to have a fairly good understanding of how multi-dimensional arrays work. Eventually, I was able to figure it out, and I will walk you through my solution.&lt;/p&gt;

&lt;p&gt;The question states thus;&lt;/p&gt;

&lt;p&gt;You are given an m x n integer grid accounts where accounts[i][j] is the amount of money the I​​​​​​​​​​​th​​​​ customer has in the j​​​​​​​​​​​th​​​​ bank. Return the wealth that the richest customer has.&lt;/p&gt;

&lt;p&gt;A customer's wealth is the amount of money they have in all their bank accounts. The richest customer is the customer that has the maximum wealth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: accounts = [[1,5],[7,3],[3,5]]
Output: 10
Explanation: 
1st customer has wealth = 6
2nd customer has wealth = 10 
3rd customer has wealth = 8
The 2nd customer is the richest with a wealth of 10.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;br&gt;
Firstly as with all programming challenges, we first need to understand the problem here, so we can come up with an algorithm for the solution.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We are expected to iterate through each embedded array.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since it's a multi-dimensional array, we would need a nested loop&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get the sum of elements in each array&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Push these sums into a new array&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Return the highest number in the new array&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function richestCus(accounts) {
    let newArr = [];
    for(let i = 0; i &amp;lt; accounts.length; i++) {
        let sum = 0;
        for(let j = 0; j &amp;lt; accounts[i].length; j++) {
            sum += accounts[i][j]
        }
        newArr.push(sum)
    }
    return Math.max.apply(null, newArr)

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;&lt;em&gt;Explanation&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
What we did above was&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We initialized a new array variable &lt;code&gt;let newArr = [];&lt;/code&gt; inside the function. So that we can push our results into the array&lt;/li&gt;
&lt;li&gt;Iterate through the outer array. If we log/print the result of the outer array we will see that the outer array has been broken down into single arrays. for example if;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;accounts = [[1,2,3],[1,2,3],[6, 8, 10]]
console.log(accounts)// [1,2,3][1,2,3][6, 8, 10]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Inside the outer loop, initialize a variable &lt;code&gt;let sum = 0&lt;/code&gt;, so that we can use it to add up elements in each array&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a nested loop inside the initial loop, so that we can have access to the elements in each sub-array. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the elements in each sub-array inside the nested loop and assign the result to the &lt;code&gt;sum&lt;/code&gt; variable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At the end of each iteration of the nested loop, the sum result is pushed unto the new array variable that was created.&lt;br&gt;
&lt;code&gt;newArr.push(sum)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, to get the highest number in our new array, we call the &lt;code&gt;Math.max()&lt;/code&gt; function on our array. &lt;br&gt;
The &lt;code&gt;Math.max()&lt;/code&gt; function returns the largest of zero or more numbers, and we can pass any number of arguments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;console.log(Math.max(5,9,7,3)); // logs 9&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But you can't pass an array of numbers on the &lt;code&gt;Math.max()&lt;/code&gt; function like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var num = [5,9,7,3];
console.log(Math.max(num)); // logs NaN

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thus we introduce the &lt;code&gt;apply()&lt;/code&gt; method which accepts arguments in an array, like&lt;br&gt;
&lt;code&gt;Math.max.apply(null, newArr)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;N:B =&amp;gt; The first argument to the &lt;code&gt;apply()&lt;/code&gt; method, sets the value to &lt;code&gt;this&lt;/code&gt;, and since we don't have a need for it, hence we passed &lt;code&gt;null&lt;/code&gt; as our first argument.&lt;/p&gt;

&lt;p&gt;With the above explanation, I hope you've learned a thing or two from this article. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;: I'm open to more efficient solutions&lt;/p&gt;

&lt;p&gt;Cheers!!!&lt;/p&gt;

</description>
      <category>discord</category>
    </item>
    <item>
      <title>A step-by-step Guide to Creating a Blogging API/App with Nodejs/Express and MongoDb</title>
      <dc:creator>Osamuyi</dc:creator>
      <pubDate>Tue, 10 Jan 2023 15:22:33 +0000</pubDate>
      <link>https://dev.to/osamuyi/a-step-by-step-guide-to-creating-a-blogging-apiapp-with-nodejsexpress-and-mongodb-27dj</link>
      <guid>https://dev.to/osamuyi/a-step-by-step-guide-to-creating-a-blogging-apiapp-with-nodejsexpress-and-mongodb-27dj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A blog is a web page that is frequently updated, and which can be used for personal personal commentary or business content.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The features of the Api will include&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users (logged in or not) will be able able to access the homepage which displays a list of all published blog articles&lt;/li&gt;
&lt;li&gt;Users will provide their email and password to login&lt;/li&gt;
&lt;li&gt;Emails used for registering to the application will be unique&lt;/li&gt;
&lt;li&gt;Users will have the option to register/sign-up so they can have the right to update and publish blog articles&lt;/li&gt;
&lt;li&gt;Before anyone can login to the blog, an authentication will first be carried out to ensure that the user's credentials are available in the database, before access can be granted to such user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get started, in your terminal initialize an empty Node.js project with default settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;installation&lt;/strong&gt;&lt;br&gt;
Then, let's install the Express framework, and some other depencies for the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express body-parser dotenv jsonwebtoken bcrypt mongoose validator  --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.npmjs.com/package/body-parser" rel="noopener noreferrer"&gt;Body-parser&lt;/a&gt; middleware helps parse incoming requests from the body of the request before it gets to the handler.&lt;br&gt;
dotenv package serves as a file that helps save sensitive information such as passwords, API keys; out of the main code&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/bcrypt" rel="noopener noreferrer"&gt;bcrypt&lt;/a&gt;: is a function hashing function, that helps in hashing a password before it is saved in the database. This will make it difficult for malicious hackers to be able to decrypt the passwords if they get access to the database.&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/jsonwebtoken" rel="noopener noreferrer"&gt;jsonwebtoken&lt;/a&gt;: is used for both authentication and authorization. We would get into it eventually in this article.&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/mongoose" rel="noopener noreferrer"&gt;mongoose&lt;/a&gt;; is an ORM used to query and manipulate data in the database. For the purpose of this project, we'll be working with MongoDb.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.js&lt;/strong&gt;&lt;br&gt;
This is going to be the entry point for our blog api. So create a file called &lt;code&gt;index.js&lt;/code&gt; in the root folder, and type in the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express')
const bodyParser = require('body-parser')

const app = express()
const PORT = 3333;

app.get('/api', function (req, res) {
  return res
    .status(201)
    .json({ test_page: 'A step further to becoming a worldclass developer' });
});


app.listen(PORT, () =&amp;gt; {
  console.log(`Server listening on port: ${PORT}`)
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we required the express function, and then created an express server. After which, a custom route handler was created with the &lt;code&gt;app.get()&lt;/code&gt; function. Now if you restart your server and go to &lt;code&gt;http://localhost:3333/api&lt;/code&gt;, you will get a custom message displayed in the response header.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database configuration&lt;/strong&gt;&lt;br&gt;
Create a *&lt;em&gt;config *&lt;/em&gt; folder in the root directory of your project. Then create a &lt;code&gt;dbconfig.js&lt;/code&gt; file. It should contain the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const moogoose = require('mongoose');
require('dotenv').config();

const MONGODB_URI = process.env.MONGODB_URI;

// connect to mongodb
function connectToMongoDB() {
    moogoose.connect(MONGODB_URI);

    moogoose.connection.on('connected', () =&amp;gt; {
        console.log('Connected to MongoDB successfully');
    });

    moogoose.connection.on('error', (err) =&amp;gt; {
        console.log('Error connecting to MongoDB', err);
    })
}

module.exports = { connectToMongoDB };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure to provide a url for the &lt;strong&gt;MONGODB_URI&lt;/strong&gt; variable in the dotenv file, and also a JWT_SECRET of your choice&lt;br&gt;
Also, require the connectToMongoDB function in the &lt;code&gt;index.js&lt;/code&gt; folder like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require('./config/dbconfig').connectToMongoDB()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create a model folder in the root directory of our project.&lt;br&gt;
&lt;strong&gt;models&lt;/strong&gt;&lt;br&gt;
In here, we will be having two services/models. One for the user, and the other for the blog.&lt;br&gt;
  &lt;code&gt;user_Model.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const validator = require('validator');
const saltRounds = 10;

const Schema = mongoose.Schema;

const userSchema = new Schema(
  {
    firstname: {
      type: String,
      required: [true, 'Your First name is required'],
    },
    lastname: {
      type: String,
      required: [true, 'Your last name is required'],
    },
    email: {
      type: String,
      required: [true, 'Your email address is required'],
      unique: [true, 'This email already exists'],
      lowercase: true,
      validate: [validator.isEmail, 'Provide a valid email address'],
    },
    password: {
      type: String,
      required: true,
      minlength: [8, 'Password must be at least 8 characters long'],
      select: false,
    },
    articles: [
      {
        type: Schema.Types.ObjectId,
        ref: 'Blog',
      },
    ],
  },
  { timestamps: true }
);

// Using bcrypt to hash user password before saving into database
userSchema.pre('save', function (next) {
  const user = this;

  bcrypt.hash(user.password, saltRounds, (err, hash) =&amp;gt; {
    user.password = hash;
    next();
  });
});

const User = mongoose.model('user', userSchema);
module.exports = User;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, firstly we created a mongoose user schema, to help us define the structure of our document. Note that we referenced the blog in the article property. This is to makesure there is a link between a blog article and the user that posted the blog. &lt;br&gt;
Also note the pre('save') function at the bottom of the schema, it ensures that the password given by the user when registering is hashed before is can be saved into the database. We achieved this using the external library which was installed earlier in the project "bcrypt".&lt;br&gt;
   &lt;code&gt;blog_Model.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');
const user = require('./users_model');

const Schema = mongoose.Schema;

//BlogPost schema
const BlogPostSchema = new Schema(
  {
    title: {
      type: String,
      required: [true, 'Title missing, provide a title'],
      unique: [true, 'Title name already exists'],
    },
    description: {
      type: String,
      required: [true, 'Description missing, provide a description'],
    },
    author: {
      type: Schema.Types.ObjectId,
      ref: 'User',
      required: true,
    },
    state: {
      type: String,
      enum: ['Draft', 'Published'],
      default: 'Draft',
    },
    read_count: {
      type: Number,
      default: 0,
    },
    reading_time: {
      type: String,
      required: [true, 'Provide a reading_time'],
    },
    tags: {
      type: String,
      required: [true, 'Specify tags'],
    },
    body: {
      type: String,
      required: [true, 'Body is needed'],
    }
  },
  {
    timestamps: true,
  }
);

const Blog = mongoose.model('BlogPost', BlogPostSchema);
module.exports = Blog;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Controller&lt;/strong&gt;&lt;br&gt;
The controller will contain the logic for our project. We will created three files in our controller folder: userController, BlogpostController and ErrorController&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');

const util = require('util');

const userModel = require('../models/users_model');
const tryCatchErr = require('../utilities/catchErrors');
const serverErr = require('../utilities/serverError');
const CONFIG = require('../config/config');

const JWT_SECRET = CONFIG.JWT_SECRET;

//Create token function and set expiration to 1hr
const signInToken = (id) =&amp;gt; {
  return jwt.sign({ id }, JWT_SECRET, { expiresIn: '1h' });
};

////////////////////////////////////////////////////////////////
/*
 * SIGN IN NEW USER
 */
/////////////////////////////////////////////////////////////////

exports.createUser = tryCatchErr(async (req, res, next) =&amp;gt; {
  const user = await userModel.create({
    firstname: req.body.firstname,
    lastname: req.body.lastname,
    email: req.body.email,
    password: req.body.password,
  });

  const token = signInToken(user._id);
  res.status(200).json({
    status: 'success',
    token,
    data: {
      user: user,
    },
  });
});

////////////////////////////////////////////////////////////////
/*
 * LOGIN IN USER
 */
/////////////////////////////////////////////////////////////////

exports.login = tryCatchErr(async (req, res, next) =&amp;gt; {
  const { email, password } = req.body;


  const user = await userModel.findOne({ email })
  if (!user) {
    return next(new serverErr('User not found', 401));
  }
  bcrypt.compare(password, user.password, (error, result) =&amp;gt; {
  if (error) return next (error)
  if (!result) {
     return next(new serverErr('Wrong email and/or password', 401));
}
};

  const token = signInToken(user._id);
  res.status(201).json({
    status: 'success',
    token,
  });
});

////////////////////////////////////////////////////////////////////////
/*
 * Authenticating routes
 */
///////////////////////////////////////////////////////////////////////

exports.authenticate = tryCatchErr(async (req, res, next) =&amp;gt; {
  let bearerToken;
  if (
    req.headers.authorization &amp;amp;&amp;amp;
    req.headers.authorization.startsWith('Bearer')
  ) {
    bearerToken = req.headers.authorization.split(' ')[1];
  }
  if (!bearerToken) {
    return next(new serverErr('Unauthirized, Login to continue', 401));
  }

  //Verify token
  const user = await util.promisify(jwt.verify)(bearerToken, JWT_SECRET);

  //Confirm if user still exists
  const currentUser = await userModel.findById(user.id);
  if (!currentUser) {
    return next(new serverErr('User does not exist', 401));
  }
  req.user = currentUser;
  next();
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;blog_controller.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const blogModel = require('../models/blog_model');
const userModel = require('../models/users_model');
//const userService = require('../Services/UserServices');

const tryCatchErr = require('../utilities/catchErrors');
const serverError = require('../utilities/serverError');

require('dotenv').config();

///////////////////////////////////////////////////////////////
/*
 * Get all blog posts
 *
 */

///////////////////////////////////////////////////////////////

exports.getAllBlogs = tryCatchErr(async (req, res, next) =&amp;gt; {
  const objectQuerry = { ...req.query };

  /// Filteration
  const removedFields = ['page', 'sort', 'limit', 'fields'];
  removedFields.forEach((field) =&amp;gt; delete objectQuerry[field]);

  let query = blogModel.find(objectQuerry);

  // Sorting
  if (req.query.sort) {
    const sortParams = req.query.sort.split(',').join(' ');
    query = query.sort(sortParams);
  } else {
    // sorting by the most recent blog posted
    query = query.sort('-createdAt');
  }

  //Pagination
  const page = req.query.page * 1 || 1;
  const limit = req.query.limit * 1 || 20;
  const skip = (page - 1) * limit;

  if (req.query.page) {
    const numArticles = await blogModel
      .countDocuments()
      .where({ state: 'Published' });
    if (skip &amp;gt;= numArticles) {
      throw new serverError('Page does not exist', 404);
    }
  }

  query = query.skip(skip).limit(limit);

  //Displaying a single published blop post
  const publishedBlogPost = await blogModel
    .find(query)
    .where({ state: 'Published' })
    .populate('user', { firstname: 1, lastname: 1, _id: 1 });

  res.status(200).json({
    status: 'success',
    result: publishedBlogPost.length,
    curentPage: page,
    limit: limit,
    totalPages: Math.ceil(publishedBlogPost.length / limit),
    data: {
      publishedBlogPost,
    },
  });
});

////////////////////////////////////////////////////////////////
/*
 * CREAT A NEW BLOG ARTICLE
 * route: get /api/blogs
 */
////////////////////////////////////////////////////////////////
exports.creatBlog = tryCatchErr(async (req, res, next) =&amp;gt; {
  const { title, description, state, tags, body } = req.body;

  if (!title || !description || !state || !tags || !body) {
    return next(new serverError('Provide all required information', 401));
  }

  // Get/Authenticate the user creating the blog
  const user = await userModel.findById(req.user._id);
  console.log(req.user._id);

  //Calculating the average read time of the blog
  let avgWPM = 250;
  const readTime = Math.ceil(body.split(/\s+/).length / avgWPM);
  const reading_time =
    readTime &amp;lt; 1 ? `${readTime + 1} minute read` : `${readTime} minutes read`;

  const author = `${user.firstname} ${user.lastname}`;

  const newblogArticle = new blogModel({
    title: title,
    description: description,
    author: req.user._id,
    reading_time: reading_time,
    state: state,
    tags: tags,
    body: body,
    user: user._id,
  });

  //   //save the blog article
  const savedBlogArticle = await newblogArticle.save();

  //Add the article to the author's blogs
  user.articles = user.articles.concat(savedBlogArticle._id);

  await user.save();
  res.status(201).json({
    message: 'Blog Article Created successfully',
    data: {
      blog: savedBlogArticle,
    },
  });
});

/////////////////////////////////////// ////////////////////////
/*
 * Get a single blog post
 * Get /api/blogs/:id
 */
////////////////////////////////////////////////////////////////

exports.getBlogById = tryCatchErr(async (req, res, next) =&amp;gt; {
  const blog = await blogModel
    .findById(req.params.id)
    .where({ state: 'Published' })
    .populate('user', { firstname: 1, lastname: 1, _id: 1 });

  if (!blog) {
    return next(new serverError('Blog article not found', 404));
  }

  //Updating the read count
  blog.read_count += 1;

  //Save to DB
  blog.save();

  res.status(201).json({
    status: 'Success',
    blog,
  });
});

//////////////////////////////////////////////////////////////////
/*
 * Get all blog posts by user ID
 * Get /api/blogs
 */
//////////////////////////////////////////////////////////////////
exports.getUserArticle = tryCatchErr(async (req, res, next) =&amp;gt; {
  const user = req.user;

  const queryObject = { ...req.query };

  const removedFields = ['page', 'sort', 'limit'];
  removedFields.forEach((field) =&amp;gt; delete queryObject[field]);

  let blogQuerry = blogModel.find({ user });

  // Sorting
  if (req.blogQuerry.sort) {
    const sortBy = req.blogQuerry.sort.split(',').join(' ');
    blogQuerry = blogQuerry.sort(sortBy);
  } else {
    blogQuerry = blogQuerry.sort('-createdAt'); // default sorting : starting from the most recent
  }

  // Pagination
  // convert to number and set default value to 1
  const page = req.blogQuerry.page * 1 || 1;
  const limit = req.blogQuerry.limit * 1 || 20;
  const skip = (page - 1) * limit;

  if (req.blogQuerry.page) {
    const numArticles = await blogQuerry.countDocuments();
    if (skip &amp;gt;= numArticles)
      throw new serverError('This page does not exist', 404);
  }
  blogQuerry = blogQuerry.skip(skip).limit(limit);

  blogQuerry = blogQuerry.populate('user', {
    firstname: 1,
    lastname: 1,
    _id: 1,
  });

  const articles = await blogQuerry;

  return res.status(200).json({
    status: 'success',
    result: articles.length,
    data: {
      articles: articles,
    },
  });
});

/////////////////////////////////////////////////////////////////////
/*
 * Update blog post by Author

 */
////////////////////////////////////////////////////////////////////////////////////////////////

exports.updateBlog = tryCatchErr(async (req, res, next) =&amp;gt; {
  const { title, description, state, tags, body } = req.body;

  const user = req.user;

  const blogPostId = await blogModel.findById(req.params.id);
  //confirm user credentials
  if (user.id !== blogPostId.user._id.toString()) {
    return next(
      new serverError('Authorization is required to update this document', 401)
    );
  }

  //Update Blog
  const updatedBlogPost = await blogModel.findByIdAndUpdate(
    { _id: req.params.id },
    {
      $set: {
        title: title,
        description: description,
        state: state,
        tags: tags,
        body: body,
      },
    },
    {
      new: true,
    }
  );
  res.status(201).json({
    status: 'Success',
    data: {
      updatedBlogPost,
    },
  });
});

//////////////////////////////////////////////////////////////////////
/*
 *Delete blog post by Author
 * Protected route
 */
//////////////////////////////////////////////////////////////////////
exports.deleteBlog = tryCatchErr(async (req, res, next) =&amp;gt; {
  const user = req.user;

  const blogPostId = await blogModel.findById(req.params.id);
  const blogAuthor = await userModel.findById(user.id);

  //console.log(blogPostId, blogAuthor);

  if (user.id !== blogPostId.user._id.toString()) {
    return next(
      new serverError('Authorization is required to delete this document')
    );
  }
  await blogModel.findByIdAndDelete(req.params.id);

  const index = blogAuthor.articles.indexOf(req.params.id);
  if (index === -1) {
    return next(new serverError('Blog post not found', 404));
  }
  blogAuthor.articles.splice(index, 1);
  await blogAuthor.save();

  res.status(201).json({
    status: 'Success',
    message: 'Blog post deleted successfully',
  });
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;error_controller.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = (err, req, res, next) =&amp;gt; {
  err.statusCode = err.statusCode || 500;
  err.status = err.status || 'error';
  res.status(err.statusCode).json({
    status: err.status,
    message: err.message,
  });
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Routes&lt;/strong&gt;&lt;br&gt;
In the route folder, create a "user_route.js" and "blog_route.js" files&lt;br&gt;
   &lt;code&gt;user_route.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; const express = require('express');

const { createUser, login } = require('./../controllers/users_controller');

const router = express.Router();

router.post('/register', createUser);
router.post('/authenticate', login);

module.exports = router;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;blog_route.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');

const {
  getAllBlogs,
  creatBlog,
  getBlogById,
  getUserArticle,
  updateBlog,
  deleteBlog,
} = require('../controllers/blog_controller');
const { authenticate } = require('../controllers/users_controller');

const router = express.Router();

router.route('/').get(getAllBlogs).post(authenticate, creatBlog);

router.route('/:id').get(getBlogById);

router
  .route('/blog_aticles/:id')
  .get(authenticate, getUserArticle)
  .put(authenticate, updateBlog)
  .delete(authenticate, deleteBlog);

module.exports = router;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the project's root folder, create a utilites folder will store our errors. It will contain two files "catchErrors.js" and "serverError.js"&lt;br&gt;
  &lt;code&gt;catchError.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const tryCatchError = (name) =&amp;gt; {
  return (req, res, next) =&amp;gt; {
    name(req, res, next).catch(next);
  };
};

module.exports = tryCatchError;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;serverError.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class serverErr extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
    this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
    this.isOperational = true;
    Error.captureStackTrace(this, this.constructor);
  }
}

module.exports = serverErr;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we update our index.js file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const logger = require('morgan');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');

const users = require('./app/api/routes/user_routes');
const blogs = require('./app/api/routes/blog_route');
const CONFIG = require('./app/api/config/config');
const connectToDb = require('./app/api/Db/mongodb');
const errorHandler = require('./app/api/controllers/error_controllers');
const serverError = require('././app/api/utilities/serverError');

const app = express();
app.use(logger('dev'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

//CONNECT to MongoDB
connectToDb();

app.use('/api/users', users);
app.use('/api/blogs', blogs);

app.get('/api', function (req, res) {
  return res
    .status(201)
    .json({ test_page: 'A step further to becoming a worldclass developer' });
});

//Undefined route error handler
app.all('*', function (req, res, next) {
  next(new serverError('Undefined route, page not found.', 404));
});

//HANDLE ERROR
app.use(errorHandler);

app.listen(CONFIG.PORT, () =&amp;gt; {
  console.log('Node server listening on port 3000');
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can connect to our database and test our code. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
In this project we created a blog API that performs basic CRUD operations, using Express.js, MongoDb and jsonwebtoken for authentication. I would appreciate your reviews. Thank you&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>mongodb</category>
    </item>
  </channel>
</rss>
