<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ node js - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ node js - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 22 May 2026 17:40:14 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/node-js/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build an Application With Node.js ]]>
                </title>
                <description>
                    <![CDATA[ Node.js it’s a runtime environment that allows you to run JavaScript code on the server side for building server-side applications. It works well for creating fast and scalable applications. In this article, I will use a simple event management app a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-an-event-app-with-node-js/</link>
                <guid isPermaLink="false">66b9f47353d7ef738812303f</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ijeoma Igboagu ]]>
                </dc:creator>
                <pubDate>Mon, 05 Aug 2024 17:56:13 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741114813767/a2786471-5a6a-4450-bdb1-f7d1162c2a90.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Node.js it’s a runtime environment that allows you to run JavaScript code on the server side for building server-side applications. It works well for creating fast and scalable applications.</p>
<p>In this article, I will use a simple event management app as an example to show you how to build an application using Node.js, Express.js, and MongoDB.</p>
<p>By the end, you’ll know how to set up a Node.js project, create a server with Express.js, show dynamic pages with embedded JavaScript, and connect to a MongoDB database to handle your data.</p>
<h3 id="heading-what-youll-learn">What You'll Learn</h3>
<ul>
<li><p>Setting up a Node.js project</p>
</li>
<li><p>Creating a server with Express.js</p>
</li>
<li><p>Rendering dynamic pages with ejs</p>
</li>
<li><p>Connecting to a MongoDB database</p>
</li>
<li><p>Creating models and schemas for your data</p>
</li>
<li><p>Handling HTTP requests and responses</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#step-1-set-up-your-development-environment%22">Set Up Your Development Environment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-set-up-the-server">Set Up the Server</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-install-and-set-up-expressjs">Install and Set Up Express.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-create-a-dynamic-template">Create a Dynamic Template</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-save-your-data-to-mongodb">Save Your Data to MongoDB</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-connect-to-the-database">Connect to the Database</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-7-create-the-model-for-the-document-structure">Create the Model for the Document Structure</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-8-create-html-pages">Create HTML Pages</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-9-create-partials">Create Partials</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-10-create-an-environment-variable-file-env">Create an Environment Variable File</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-further-steps">Further Steps</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-56.png" alt="Let's get started 🚀" width="600" height="400" loading="lazy"></p>
<p><em>Let's get started 🚀</em></p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p><a target="_blank" href="https://nodejs.org/en">Node.js</a> installed on your system.</p>
</li>
<li><p>A good understanding of <a target="_blank" href="https://www.mongodb.com/">MongoDB</a>.</p>
</li>
<li><p>A code editor that you prefer, such as <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a> or <a target="_blank" href="https://www.sublimetext.com/download">Sublime Text</a>.</p>
</li>
</ul>
<h2 id="heading-step-1-set-up-your-development-environment">Step 1: Set Up Your Development Environment</h2>
<h3 id="heading-install-nodejs-and-npm">Install Node.js and npm</h3>
<p>First, you'll need to download and install Node.js from <a target="_blank" href="https://nodejs.org/">nodejs.org</a>. Then you can verify the installation by running: <code>node -v</code> and <code>npm -v</code>.</p>
<h3 id="heading-initialize-a-new-project">Initialize a New Project</h3>
<p>Create a new directory for your project. Then initialize the project with npm: <code>npm init -y</code> in your terminal.</p>
<pre><code class="lang-js">mkdir event-app
cd event-app
npm init -y
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/ShareX_OnHiLv8GvS-1.gif" alt="Initializing the project" width="600" height="400" loading="lazy"></p>
<p><em>Initializing the project</em></p>
<p>Running <code>npm init -y</code> creates the <code>package.json</code> file, as shown above. This file is crucial. It stores and tracks all third-party libraries (dependencies) needed for your application.</p>
<h2 id="heading-step-2-set-up-the-server">Step 2: Set Up the Server</h2>
<p>To set up your server, create a file called <code>server.js</code> or <code>app.js</code>. These are common names. They are used for their descriptive nature. But, you can name the file whatever you prefer.</p>
<p>The <code>server.js</code> file will be used to create a server which will be used to manage, control, and route to the necessary page in our application.</p>
<h2 id="heading-step-3-install-and-set-up-expressjs">Step 3: Install and Set Up Express.js</h2>
<p>Express.js is a popular web application framework for Node.js and a third-party library that we use in our application.</p>
<p>Express simplifies the handling and definition of various routes for HTTP requests. It enables you to manage the application's routing and connect it to the server.</p>
<h3 id="heading-to-use-express">To use Express:</h3>
<p>Install Express.js by running the following command in your terminal:</p>
<pre><code class="lang-javascript">npm install express
</code></pre>
<p>Require Express in your <code>server.js</code> file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)
</code></pre>
<p>Initialize Express so you can use it in your application.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> app = express()
</code></pre>
<p>Create a routing path to get the HTTP request.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//routing path</span>
app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'Hello World!'</span>);
});
</code></pre>
<p>Lastly, we need to ensure that the connection to the server is set up correctly. When we start the server in the terminal, it will open in the browser.</p>
<p>To do this, use the <code>listen()</code> method.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Start the server</span>
app.listen(<span class="hljs-number">3000</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server started on port 3000'</span>);
});
</code></pre>
<p>This method will <code>listen()</code> to requests from the server.</p>
<p><strong>Here's the complete code process:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);


<span class="hljs-comment">// Next initialize the application</span>
<span class="hljs-keyword">const</span> app = express();

<span class="hljs-comment">// routing path</span>
app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'Hello World!'</span>);
});

<span class="hljs-comment">// Start the server</span>
app.listen(<span class="hljs-number">3000</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server started on port 3000'</span>);
});
</code></pre>
<p><strong>Note:</strong> The routing path above was only for testing purposes to confirm that the server is working and connected. We will provide a different file for the event app we are creating.</p>
<p>With Express.js installed in your application, you can now create a server that will handle all your routing and connections.</p>
<p>To start the server, go to your terminal.</p>
<p>Use the keyword <code>node</code>, then type <code>--watch</code>, a flag to start and automatically restart the server whenever you make changes:</p>
<pre><code class="lang-javascript">node --watch server.js
</code></pre>
<p>Or you can install <code>[nodemon](https://www.npmjs.com/package/nodemon)</code> for the same purpose. <code>Nodemon</code> detects changes in the directory and restarts your application.</p>
<pre><code class="lang-javascript">npm install -g nodemon
</code></pre>
<p>Then run your server with:</p>
<pre><code class="lang-javascript">nodemon server.js
</code></pre>
<h2 id="heading-step-4-create-a-dynamic-template">Step 4: Create a Dynamic Template</h2>
<p>We need a templating engine to render <code>HTML</code> code in the browser using Node.js. We'll use ejs <strong>(Embedded JavaScript)</strong> for this tutorial but there are others such as <a target="_blank" href="https://pugjs.org/api/getting-started.html">Pug (formerly known as Jade)</a> and <a target="_blank" href="https://www.npmjs.com/package/express-handlebars">Express Handlebar</a>, which also render HTML on the server.</p>
<p><code>ejs</code> allows you to embed JavaScript in HTML to create dynamic web pages.</p>
<p>To install <code>ejs</code>, run:</p>
<pre><code class="lang-bash">npm install ejs
</code></pre>
<p>To set up <code>ejs</code> in <code>server.js</code>, require and set <code>ejs</code> as the templating engine:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-51.png" alt="requiring ejs template in our application" width="600" height="400" loading="lazy"></p>
<p><em>Requiring</em> <code>ejs</code> template in your application</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> app = express();

app.set(<span class="hljs-string">'view engine'</span>, <span class="hljs-string">'ejs'</span>);
</code></pre>
<p>With this setup, you can now enable dynamic rendering of <code>HTML</code> code in your Node.js application.</p>
<h2 id="heading-step-5-save-your-data-to-mongodb">Step 5: Save Your Data to MongoDB</h2>
<p>To save the data you create for your application, you will use MongoDB.</p>
<p>MongoDB is a "Not Only SQL" (NoSQL) database that's designed for storing document collections. Traditional SQL databases organize data into tables, but MongoDB is optimised for handling large volumes of data.</p>
<p>To read more about this, <a target="_blank" href="https://www.mongodb.com/resources/basics/databases/nosql-explained">check out this article</a>.</p>
<h2 id="heading-step-6-connect-to-the-database">Step 6: Connect to the Database</h2>
<p>Now we need to connect to the database which will be MongoDB for this tutorial.</p>
<p>Using MongoDB provides you with a Uniform Resource Locator (URL) to connect to your application. This URL connect you and acts as a communicator between the database and your application.</p>
<h3 id="heading-how-to-get-the-url">How to get the URL</h3>
<p>To get the URL, follow these simple steps:</p>
<ol>
<li><p><strong>Sign Up/Log In</strong>: Go to the <a target="_blank" href="https://www.mongodb.com/">MongoDB website</a> and sign up for an account or log in if you already have one.</p>
</li>
<li><p><strong>Create a Cluster</strong>: Once logged in, create a new cluster. This will set up your database.</p>
</li>
<li><p><strong>Connect to Your Cluster</strong>: After your cluster is created, click the "Connect" button.</p>
</li>
<li><p><strong>Choose a Connection Method</strong>: Select "Connect your application".</p>
</li>
<li><p><strong>Copy the Connection String</strong>: MongoDB will provide a connection string (URL) like this:</p>
</li>
</ol>
<pre><code class="lang-js">mongodb+srv:<span class="hljs-comment">//&lt;username&gt;:&lt;password&gt;@cluster0.mongodb.net/&lt;dbname&gt;?retryWrites=true&amp;w=majority</span>
</code></pre>
<ol start="6">
<li><strong>Replace the Placeholders</strong>: Replace <code>&lt;username&gt;</code>, <code>&lt;password&gt;</code>, and <code>&lt;dbname&gt;</code> with your actual username, password, and database name.</li>
</ol>
<p>Now that you have the URL, you can easily connect to your database.</p>
<p>To make this connection easier, we will use a tool called Mongoose.</p>
<h3 id="heading-what-is-mongoose">What is Mongoose?</h3>
<p><a target="_blank" href="https://mongoosejs.com/">Mongoose</a> is a JavaScript library that makes it easier to work with MongoDB in a Node.js environment. It provides a simple way to model your data. You can define schemas, do data validation, and build queries as well.</p>
<h3 id="heading-how-to-make-a-connection">How to make a connection</h3>
<p>MongoDB has already provided you with a URL for connection. Now you'll use Mongoose to send your documents to the database.</p>
<p>To use Mongoose in your project, follow these steps:</p>
<p>Install Mongoose using npm.</p>
<pre><code class="lang-js">npm i mongoose
</code></pre>
<p>In your <code>server.js</code> file, you need to require Mongoose to use it as a connector to the database.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);
</code></pre>
<p>After you require Mongoose, you need to define the connection <code>URl</code> provided in your <code>server.js</code> file.</p>
<p><code>server.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-comment">// Replace &lt;username&gt;, &lt;password&gt;, and &lt;dbname&gt; with your actual credentials</span>
<span class="hljs-keyword">const</span> dbURL = <span class="hljs-string">'mongodb+srv://&lt;username&gt;:&lt;password&gt;@cluster0.mongodb.net/&lt;dbname&gt;?retryWrites=true&amp;w=majority'</span>;

mongoose
  .connect(process.env.dbURL)
  .then(<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected to MongoDB'</span>);
    app.listen(<span class="hljs-number">3000</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server started on port 3000'</span>);
    });
  })
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Could not connect to MongoDB:'</span>, err);
  });
</code></pre>
<p>This setup ensures that Mongoose acts as the connector. It connects your application to the MongoDB database.</p>
<h2 id="heading-step-7-create-the-model-for-the-document-structure">Step 7: Create the Model for the Document Structure</h2>
<p>Next, we need to create a model document called a Schema so that when you post data to your database it will be saved accordingly.</p>
<p>To create this model:</p>
<ol>
<li><p>Create a folder named <code>models</code> to keep your application organized.</p>
</li>
<li><p>Inside the <code>model's</code> folder, create a file called <code>event.js</code>.</p>
</li>
</ol>
<p>In the<code>event.js</code> file, you will use Mongoose to define the schema for the event documents. You'll specify the structure and data types for the documents you will send to your database.</p>
<p>Here's the <code>event.js</code> file created inside the <code>model</code> folder:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-comment">// Schema</span>
<span class="hljs-keyword">const</span> EventSchema = <span class="hljs-keyword">new</span> mongoose.Schema(
  {
    <span class="hljs-attr">title</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">date</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Date</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">organizer</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">price</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">time</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">location</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">description</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
  },
  { <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span> }
);

<span class="hljs-keyword">const</span> Event = mongoose.model(<span class="hljs-string">'event'</span>, EventSchema);

<span class="hljs-built_in">module</span>.exports = Event;
</code></pre>
<p>When this is done, export so you can use it in your <code>server.js</code> file by simply using the <strong>require keyword</strong>.</p>
<p>With the schema created, it can now be exported to the <code>server.js</code> file.</p>
<p>Your <code>server.js</code> will look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> ejs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ejs'</span>);
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);
<span class="hljs-keyword">const</span> Event = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/Events'</span>);<span class="hljs-comment">// the event.js file</span>
</code></pre>
<h2 id="heading-step-8-create-html-pages">Step 8: Create HTML Pages</h2>
<p>As we talked about earlier, we're using <code>ejs</code> in step 4 to render <code>HTML</code> code, allowing us to view the code in the browser.</p>
<h3 id="heading-form-page">Form Page</h3>
<p>First, let's create a form page. With the form page created, you'll be able to make POST requests which will enable you to send data to your MongoDB database.</p>
<p>To create a basic form, ensure it includes:</p>
<ul>
<li><p>An <code>action</code> attribute which specifies the route to send the data.</p>
</li>
<li><p>A <code>method</code> attribute which specifies the HTTP request method – in this case, the POST request.</p>
</li>
</ul>
<p>A basic form:</p>
<pre><code class="lang-js">&lt;form action=<span class="hljs-string">"/submit-event"</span> method=<span class="hljs-string">"POST"</span>&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Event Creation Form<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"title"</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span></span>
  &lt;input type="text" id="title" name="title" required&gt;

  &lt;label for="date"&gt;Date&lt;/label&gt;
  &lt;input type="date" id="date" name="date" required&gt;

  &lt;label for="organizer"&gt;Organizer&lt;/label&gt;
  &lt;input type="text" id="organizer" name="organizer" required&gt;

  &lt;label for="price"&gt;Price&lt;/label&gt;
  &lt;input type="text" id="price" name="price" required&gt;

  &lt;label for="time"&gt;Time&lt;/label&gt;
  &lt;input type="text" id="time" name="time" required&gt;

  &lt;label for="location"&gt;Location&lt;/label&gt;
  &lt;input type="text" id="location" name="location" required&gt;

  &lt;label for="description"&gt;Description&lt;/label&gt;
  &lt;textarea id="description" name="description" rows="4" required&gt;&lt;/textarea&gt;

  &lt;button type="submit"&gt;Submit&lt;/button&gt;
&lt;/form&gt;
</code></pre>
<p>NB: Make sure to add the <strong>name</strong> attribute to each input, or it won't post.</p>
<p>The form created above will let you post data to the specified route. You will then process and store it in your database.</p>
<p><strong>Here's the result:</strong></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-53.png" alt="The form page" width="600" height="400" loading="lazy"></p>
<p><em>The form page</em></p>
<p>After creating the form page, we need to go back to the <code>server.js file</code> and create a POST request to handle the form submission.</p>
<p><code>server.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-comment">// posting a data</span>

app.post(<span class="hljs-string">'/submit-event'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> event = <span class="hljs-keyword">new</span> Event(req.body);
  event.save()
    .then(<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
      res.redirect(<span class="hljs-string">'/'</span>);
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.error(err);
    });
});
</code></pre>
<h3 id="heading-the-homepage">The Homepage</h3>
<p>Now that the form can post data to the database, we can create the homepage to display the created events in the browser.</p>
<p>First, in your <code>server.js</code> file, you need to create a function. It will fetch all the events posted from the form and stored in the database.</p>
<p>Here’s how to set it up:</p>
<p>This is a function created at <code>server.js</code> to fetch all data from the database:</p>
<pre><code class="lang-js"><span class="hljs-comment">// To get all the event</span>

router.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  Event.find()
    .then(<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
      res.render(<span class="hljs-string">'index'</span>, { <span class="hljs-attr">title</span>: <span class="hljs-string">'All event'</span>, <span class="hljs-attr">events</span>: result })
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.error(err); 
  })
})
</code></pre>
<p>Next, we will dynamically loop through each part using a <code>forEach</code> loop in the homepage file. Since we are using <code>ejs</code>, the <code>HTML</code> file extension will be <code>.ejs</code>.</p>
<pre><code class="lang-js">&lt;div&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>All events<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">if</span> (<span class="hljs-attr">events.length</span> &gt;</span> 0) { %&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">events.forEach</span>(<span class="hljs-attr">event</span> =&gt;</span> { %&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">event.title</span> %&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">event.description</span> %&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/event/&lt;%= event.id %&gt;"</span>&gt;</span>
            Read More
          <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">%</span> }) %&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">%</span> } <span class="hljs-attr">else</span> { %&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>No events available at the moment.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">%</span> } %&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/div&gt;
</code></pre>
<p>Here is an explanation of what each part of the code does:</p>
<ul>
<li><p><strong>Heading (</strong><code>&lt;h2&gt;All events&lt;/h2&gt;</code>): Displays "All events" as a heading.</p>
</li>
<li><p><strong>Event List (</strong><code>&lt;div&gt;</code>): Container for displaying a list of events.</p>
</li>
<li><p><strong>Conditional Check (</strong> <code>&lt;% if (events.length &gt; 0) { %&gt; ... &lt;% } else { %&gt; ... &lt;% } %&gt;</code>): Checks if there are any events (<code>events.length &gt; 0</code>). If events exist, it loops through each event (<code>events.forEach</code>) to display its details.</p>
</li>
<li><p>For each event, it creates a <code>&lt;div&gt;</code> containing the event's title (<code>event.title</code>) in a<code>&lt;h3&gt;</code> tag, the event's description (<code>event.description</code>) in a <code>&lt;p&gt;</code> tag, and a link (<code>&lt;a&gt;</code>) to view more details about the event (<code>Read More</code>). The link directs to <code>/event/event.id</code>, where <code>event.id</code> is the unique identifier of the event.</p>
</li>
<li><p><strong>No Events Message (</strong><code>&lt;% } else { %&gt; ... &lt;% } %&gt;</code>): If no events are present (<code>events.length &lt;= 0</code>), it displays a message saying "No events available at the moment."</p>
</li>
</ul>
<h2 id="heading-step-9-create-partials">Step 9: Create Partials</h2>
<p>Remember that you installed <code>ejs</code> into your application to facilitate more dynamic components. It allows you to break your code down further to be more dynamic.</p>
<p>To further organize your code, you'll use something called <strong>Partials</strong>.</p>
<p>Partials let you break down your code into scalable, modular, and manageable parts, keeping your HTML organized.</p>
<p>First, let's create a partial for the navbar.</p>
<h3 id="heading-how-to-create-a-partial">How to Create a Partial:</h3>
<ul>
<li><p>Inside your <code>views</code> folder, create a new folder named <code>partials</code></p>
</li>
<li><p>Inside the <code>partials</code> folder, create a new file called <code>nav.ejs</code>.</p>
</li>
<li><p>Cut out the navbar code from your homepage file and paste it into <code>nav.ejs</code>.</p>
</li>
</ul>
<h3 id="heading-example">Example:</h3>
<p>First, create the Partials folder and file:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/partial.png" alt="nav partial" width="600" height="400" loading="lazy"></p>
<p><em>nav partial</em></p>
<p>Use the <code>&lt;%- include() %&gt;</code> syntax from <code>ejs</code> to include the <code>nav.ejs</code> partial across pages in your application where you want the navbar to appear.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/include.png" alt="Include ()" width="600" height="400" loading="lazy"></p>
<p><em>Include () syntax</em></p>
<p>Here's the code:</p>
<pre><code class="lang-js">&lt;!DOCTYPE html&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">%-</span> <span class="hljs-attr">include</span>('<span class="hljs-attr">.</span>/<span class="hljs-attr">partial</span>/<span class="hljs-attr">head.ejs</span>') %&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">%-</span> <span class="hljs-attr">include</span>('<span class="hljs-attr">.</span>/<span class="hljs-attr">partial</span>/<span class="hljs-attr">nav.ejs</span>') %&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
      hello
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">%-</span> <span class="hljs-attr">include</span>('<span class="hljs-attr">.</span>/<span class="hljs-attr">partial</span>/<span class="hljs-attr">footer.ejs</span>') %&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></span>
</code></pre>
<p>With this setup, your HTML code will be organized. It will be easy to manage and update components like the navbar across different pages. You can use this approach on other parts of your application. For example, the head tag, footer tag, and other reusable components.</p>
<h2 id="heading-step-10-create-an-environment-variable-file-env">Step 10: Create an Environment Variable File (.Env)</h2>
<p>In this tutorial, we'll upload the project to GitHub. You'll protect your port number and MongoDB URL with secure storage. You'll also use an environment variable file, a configuration file known as .env. This file keeps sensitive information safe. It includes passwords and API URLs and prevents exposure.</p>
<p>Here's how to set it up using Node.js:</p>
<p>First, install the <code>[dotenv](https://www.npmjs.com/package/dotenv)</code> package.</p>
<pre><code class="lang-js">npm i dotenv
</code></pre>
<p>Then create a <code>.env</code> file. Inside it, add your PORT number and MongoDB URL. It should look something like this:</p>
<pre><code class="lang-plaintext">PORT=3000
dbURl='mongodb+srv://&lt;username&gt;:&lt;password&gt;@cluster0.mongodb.net/&lt;dbname&gt;?retryWrites=true&amp;w=majority';
</code></pre>
<p>Then update your <code>.gitignore</code> file:</p>
<pre><code class="lang-plaintext">
/node_modules
.env
</code></pre>
<p>Adding .env to your .gitignore ensures that it is not included in your GitHub repository. This tells Git to ignore the .env file when uploading your code.</p>
<p>Then in your <code>server.js</code> file, require the <code>dotenv</code> package. Load the variables with this line at the top of the file:</p>
<p>To require it, simply type:</p>
<pre><code class="lang-js"><span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config();
</code></pre>
<p>This way, you don't need to hardcode the PORT number and MongoDB URL in your <code>server.js</code> file. Instead, you can access them using <code>process.env.PORT</code> and <code>process.env.dbURl</code>.</p>
<p>So your <code>server.js</code> file will be cleaner and not messy 😵‍💫</p>
<pre><code class="lang-js"><span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config();
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> ejs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ejs'</span>);
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

mongoose
  .connect(process.env.dbURL)
  .then(<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected to MongoDB'</span>);
    app.listen(<span class="hljs-number">3000</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server started on port 3000'</span>);
    });
  })
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Could not connect to MongoDB:'</span>, err);
  });
</code></pre>
<h2 id="heading-further-steps">Further Steps</h2>
<p>To expand on this basic application, consider adding features such as:</p>
<ul>
<li><p>User authentication</p>
</li>
<li><p>Event search and filter functionality</p>
</li>
<li><p>Event editing and deletion</p>
</li>
<li><p>Notifications for upcoming events</p>
</li>
</ul>
<h3 id="heading-how-to-style-the-application">How to Style the Application</h3>
<p>If you want to add some styling to your application, follow these steps:</p>
<p>First, create a <code>public</code> folder. Inside this folder, create a <code>style.css</code> file where you will write your custom CSS.</p>
<p>Then in your <code>HTML</code> file, link the <code>style.css</code> file in the <code>&lt;head&gt;</code> tag as you normally would:</p>
<pre><code class="lang-js">&lt;link rel=<span class="hljs-string">"stylesheet"</span> href=<span class="hljs-string">"/style.css"</span>&gt;
</code></pre>
<p>To ensure your CSS file is served correctly, add the following line to your <code>server.js</code> file:</p>
<pre><code class="lang-js">app.use(express.static(<span class="hljs-string">'public'</span>));
</code></pre>
<p>This application uses Tailwind CSS for styling. But using Tailwind is optional. You can use any CSS framework or write custom CSS to achieve your desired layout.</p>
<h3 id="heading-how-to-include-images">How to Include Images</h3>
<p>All images should be stored in the <code>public</code> folder and referenced in your HTML files. You should also ensure that the <code>public</code> folder is correctly set up in your <code>server.js</code> file to serve static files.</p>
<p>Here's an example of how to serve static files in <code>server.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> app = express();


<span class="hljs-comment">// Serve static files from the 'public' folder</span>
app.use(express.static(<span class="hljs-string">'public'</span>));
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You've built a simple application using Node.js, Express.js, ejs, and MongoDB. With these fundamentals, you can expand and enhance your application to meet more specific needs and features.</p>
<p>Feel free to share your progress or ask questions if you encounter any issues.</p>
<p>If you found this article helpful, share it with others who may also find it interesting.</p>
<p>Stay updated with my projects by following me on <a target="_blank" href="https://https//twitter.com/ijaydimples">Twitter</a>, <a target="_blank" href="https://www.linkedin.com/in/ijeoma-igboagu/">LinkedIn</a> and <a target="_blank" href="https://github.com/ijayhub">GitHub</a></p>
<p>Thank you for reading 💖.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A Guide to the Node.js Event Loop ]]>
                </title>
                <description>
                    <![CDATA[ Node.js is an open-source JavaScript runtime environment that allows you to run JavaScript outside the browser. Although Node.js is single-threaded, it has an event loop that makes it multi-threaded. The Node.js event loop is a crucial mechanism in N... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-guide-to-the-node-js-event-loop/</link>
                <guid isPermaLink="false">66d46040c7632f8bfbf1e445</guid>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Musab Habeeb ]]>
                </dc:creator>
                <pubDate>Tue, 28 May 2024 07:00:35 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/Node.js-event-loop.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Node.js is an open-source JavaScript runtime environment that allows you to run JavaScript outside the browser. Although Node.js is single-threaded, it has an event loop that makes it multi-threaded.</p>
<p>The Node.js event loop is a crucial mechanism in Node.js that makes Node.js programs run concurrently and asynchronously. Mastering the Node.js event loop helps a Node.js developer understand how Node.js programs run under the hood.</p>
<p>In this article, you will learn the basics of the event loop, starting with threads and processes, then how the JavaScript event loop works, and finally, how the Node.js event loop works.</p>
<h2 id="heading-what-are-threads-and-process">What are Threads and Process?</h2>
<p>To master the Node.js event loop, you must understand processes and threads.</p>
<p>A programmer can write programs that perform different tasks with different programming languages. While some programming languages can run just one task at a time, other programming languages can run several tasks simultaneously.</p>
<p>A process involves several tasks running in a program from start to finish, while a thread is the running of an individual task.</p>
<p>A process consists of all the steps a program takes to run till completion. It is a currently executing program. A program may have one or more independent processes, each having its own memory space or address. A process may have one or more threads in it.</p>
<p>A thread is a single unit of execution that is part of a process, like a task in a program. A thread has a thread ID, a register set, and a stack. A thread also shares its code section, data section, operating system resources, and memory space with other threads in a process.</p>
<p>The code below contains an <code>isNumberEven</code> function that checks if a number is even and an <code>isNumberOdd</code> function that checks if a number is odd. A process involves running this code from start to finish, while a thread involves running individual functions.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isNumberEven</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">if</span> (number % <span class="hljs-number">2</span> === <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
  }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isNumberOdd</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">if</span> (number % <span class="hljs-number">2</span> !== <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
  }
}

isNumberEven(<span class="hljs-number">6</span>);
isNumberOdd(<span class="hljs-number">1</span>);
</code></pre>
<h3 id="heading-what-are-single-threads-and-multi-threads">What are Single-threads and Multi-threads?</h3>
<p>All programming languages have a runtime engine that runs their code. Some runtime engines are single-threaded (which means they can only run one thread at a time), while some are multi-threaded (which means they can run more than one thread at a time).</p>
<p>The diagram below shows a single-threaded process and a multi-threaded process:</p>
<p><img src="https://hackmd.io/_uploads/SJkCXfQTa.jpg" alt="Single threads and Multi threads" width="600" height="400" loading="lazy"></p>
<p><em>Single-threaded and Multi-threaded Processes</em></p>
<p>A single-threaded programming language has a single-threaded runtime engine that runs tasks in a program sequentially. A multi-threaded programming language has a multi-threaded runtime engine that runs tasks in a program simultaneously. A multi-threaded runtime engine is more performant than a single-threaded runtime engine.</p>
<p>Programming languages like Java, C#, and so on are multi-threaded, while languages like JavaScript, Python, and so on are single-threaded.</p>
<p>Single-threaded programming languages are synchronous, which means they run the task in their programs sequentially. JavaScript is synchronous, but its event loop makes it asynchronous.</p>
<p>In the upcoming sections, you will learn how the JavaScript event loop works and then master the Node.js event loop.</p>
<h2 id="heading-how-the-javascript-event-loop-works">How the JavaScript Event Loop Works</h2>
<p>You must understand how the JavaScript runtime engine runs JavaScript code for you to understand the JavaScript event loop.</p>
<p>The JavaScript runtime engine consists primarily of the:</p>
<ul>
<li><p>Memory heap and</p>
</li>
<li><p>Call stack</p>
</li>
</ul>
<p>The memory heap is where variables declared in the program are allocated memory space, and the call stack is where the runtime engine stores functions in the program for execution.</p>
<p>The JavaScript runtime engine runs the code below synchronously and in this step-by-step process:</p>
<ul>
<li><p>It allocates memory space for all the variables in the code.</p>
</li>
<li><p>It executes the <code>exponentiation</code> function after pushing onto the call stack.</p>
</li>
<li><p>It executes the <code>validatePassword</code> function after pushing it onto the call stack.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exponentiation</span>(<span class="hljs-params">base, exponent</span>) </span>{
  <span class="hljs-keyword">let</span> result = <span class="hljs-number">1</span>;
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; exponent; i++) {
    result *= base;
  }
  <span class="hljs-keyword">return</span> result;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">validatePassword</span>(<span class="hljs-params">password</span>) </span>{
  <span class="hljs-keyword">const</span> hasUppercase = <span class="hljs-regexp">/[A-Z]/</span>.test(password);
  <span class="hljs-keyword">const</span> hasLowercase = <span class="hljs-regexp">/[a-z]/</span>.test(password);
  <span class="hljs-keyword">const</span> hasNumber = <span class="hljs-regexp">/[0-9]/</span>.test(password);
  <span class="hljs-keyword">const</span> isValidLength = password.length &gt;= <span class="hljs-number">8</span>;

  <span class="hljs-keyword">if</span> (hasUppercase &amp;&amp; hasLowercase &amp;&amp; hasNumber &amp;&amp; isValidLength) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"password is valid"</span>;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"password is invalid"</span>;
  }
}

exponentiation(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>);
validatePassword(<span class="hljs-string">"Ab01234"</span>);
</code></pre>
<p>If your code contains a blocking function, which is a function that takes a lot of time to run, the function will block other functions from running until it completes. Users can’t interact with a website that has a blocking function as part of its code while the function runs.</p>
<p>The code below contains the <code>fibonacci</code> function, which takes time to run. The runtime engine starts running the <code>factorial</code> function first, then the <code>fibonacci</code> function, during which the <code>findMin</code> function can’t run.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">factorial</span>(<span class="hljs-params">n</span>) </span>{
  <span class="hljs-keyword">if</span> (n === <span class="hljs-number">0</span> || n === <span class="hljs-number">1</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
  }
  <span class="hljs-keyword">let</span> result = <span class="hljs-number">1</span>;
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">2</span>; i &lt;= n; i++) {
    result *= i;
  }
  <span class="hljs-keyword">return</span> result;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fibonacci</span>(<span class="hljs-params">num</span>) </span>{
  <span class="hljs-keyword">if</span> (num &lt;= <span class="hljs-number">1</span>) {
    <span class="hljs-keyword">return</span> num;
  }
  <span class="hljs-keyword">return</span> fibonacci(num - <span class="hljs-number">1</span>) + fibonacci(num - <span class="hljs-number">2</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findMin</span>(<span class="hljs-params">numbers</span>) </span>{
  <span class="hljs-keyword">if</span> (!numbers || numbers.length === <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Empty array provided"</span>);
  }

  <span class="hljs-keyword">let</span> min = numbers[<span class="hljs-number">0</span>];
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>; i &lt; numbers.length; i++) {
    <span class="hljs-keyword">if</span> (numbers[i] &lt; min) {
      min = numbers[i];
    }
  }
  <span class="hljs-keyword">return</span> min;
}

<span class="hljs-keyword">let</span> numbers = [<span class="hljs-number">4</span>, <span class="hljs-number">2</span>, <span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">6</span>];

factorial(<span class="hljs-number">5</span>);

fibonacci(<span class="hljs-number">45</span>);

findMin(numbers);
</code></pre>
<p>To make the program in the example above run asynchronously, you should make the <code>fibonacci</code> function non-blocking with JavaScript web APIs.</p>
<p>JavaScript web APIs do not run on the main thread but instead create their threads, which enables them to run concurrently and not block the execution of other functions in your code.</p>
<p>You can use these JavaScript web APIs to make your functions non-blocking:</p>
<ul>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/setTimeout">setTimeout</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/AJAX">AJAX</a> and</p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction">DOM</a></p>
</li>
</ul>
<p>So, if you add a <code>setTimeout</code> to your code like this:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">factorial</span>(<span class="hljs-params">n</span>) </span>{
  <span class="hljs-keyword">if</span> (n === <span class="hljs-number">0</span> || n === <span class="hljs-number">1</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
  }
  <span class="hljs-keyword">let</span> result = <span class="hljs-number">1</span>;
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">2</span>; i &lt;= n; i++) {
    result *= i;
  }
  <span class="hljs-keyword">return</span> result;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fibonacci</span>(<span class="hljs-params">num</span>) </span>{
  <span class="hljs-keyword">if</span> (num &lt;= <span class="hljs-number">1</span>) {
    <span class="hljs-keyword">return</span> num;
  }
  <span class="hljs-keyword">return</span> fibonacci(num - <span class="hljs-number">1</span>) + fibonacci(num - <span class="hljs-number">2</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findMin</span>(<span class="hljs-params">numbers</span>) </span>{
  <span class="hljs-keyword">if</span> (!numbers || numbers.length === <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Empty array provided"</span>);
  }

  <span class="hljs-keyword">let</span> min = numbers[<span class="hljs-number">0</span>];
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>; i &lt; numbers.length; i++) {
    <span class="hljs-keyword">if</span> (numbers[i] &lt; min) {
      min = numbers[i];
    }
  }
  <span class="hljs-keyword">return</span> min;
}

<span class="hljs-keyword">let</span> numbers = [<span class="hljs-number">4</span>, <span class="hljs-number">2</span>, <span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">6</span>];

factorial(<span class="hljs-number">5</span>);

<span class="hljs-built_in">setTimeout</span>(fibonacci(<span class="hljs-number">45</span>), <span class="hljs-number">3000</span>);

findMin(numbers);
</code></pre>
<p>The <code>factorial</code> and <code>findMin</code> functions will run on the main thread, while the <code>fibonacci</code> function runs concurrently on a separate thread.</p>
<p>To properly understand how the program above runs, you must understand how the JavaScript event loop works. The JavaScript event loop is a mechanism by which tasks in a JavaScript program run asynchronously.</p>
<p>The JavaScript event loop has a callback queue that stores functions that take time to execute.</p>
<p>The event loop sends functions that execute immediately to the callback queue for execution and sends blocking functions to web API threads for execution.</p>
<p>Then, the event loop sends the blocking function back to the callback queue when the set time elapses. The event loop then checks if the call stack is empty before pushing the function in the callback queue to the call stack for execution.</p>
<p>The diagram below explains how the event loop in JavaScript works:</p>
<p><img src="https://hackmd.io/_uploads/B1AMVMQpa.jpg" alt="JavaScript event loop" width="600" height="400" loading="lazy"></p>
<p><em>The JavaScript event loop</em></p>
<p>The code above that contains <code>factorial</code>, <code>fibonacci</code>, and <code>findMin</code> functions is executed like this after adding a <code>setTimeout</code> function.</p>
<p>The event loop pushes the <code>factorial</code> function onto the call stack for execution. Then, the event loop pushes the <code>fibonacci</code> function onto the call stack, but the <code>fibonacci</code> function has a <code>setTimeout</code> function that prevents it from executing immediately. So, the event loop pushes the <code>fibonacci</code> function to a separate thread for web APIs to run concurrently.</p>
<p>Then, the event loop pushes the <code>findMin</code> function onto the call stack for execution. When the time set in the <code>setTimeout</code> elapses, the event loop pushes the <code>fibonacci</code> function to the call stack for execution.</p>
<h2 id="heading-how-the-nodejs-event-loop-works">How The Node.js Event Loop Works</h2>
<p>Node.js is a JavaScript runtime environment that enables JavaScript to run outside the browser, like on the command line interface, servers, and hardware.</p>
<p>Node.js has an event loop that is similar to the JavaScript event loop. The Node.js event loop and the JavaScript event loop have a call stack and a callback queue. The Node.js event loop is implemented and managed by a library named <a target="_blank" href="https://libuv.org/">libuv</a> written in C.</p>
<p>The Node.js event loop has six phases, which are:</p>
<ul>
<li><p>Timer phase</p>
</li>
<li><p>Pending Callbacks Phase</p>
</li>
<li><p>Idle Phase</p>
</li>
<li><p>Poll Phase</p>
</li>
<li><p>Check Phase</p>
</li>
<li><p>Close Callbacks Phase</p>
</li>
</ul>
<p>The diagram below shows how the Node.js event loop works:</p>
<p><img src="https://hackmd.io/_uploads/SkiVEMXTp.jpg" alt="Node.js event loop" width="600" height="400" loading="lazy"></p>
<p><em>The Node.js event loop</em></p>
<p>There is a microtask queue that exists outside of the Node.js event loop. The microtask queue consists of the <code>nextTick queue</code> and the <code>Promise queue</code>. The <code>nextTick queue</code> runs the <code>process.nextTick</code> function, while the <code>Promise queue</code> runs <code>.then</code>, <code>.catch</code>, and other promises.</p>
<p>In the upcoming sections, you will learn about each phase of the Node.js event loop.</p>
<h3 id="heading-timer-phase">Timer Phase</h3>
<p>There are three timers in Node.js: <code>setTimeout</code>, <code>setInterval</code>, and <code>setImmediate</code>. <code>setTimeout</code> and <code>setInterval</code> run in the timer phase. The code sample below runs during the timer phase:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"setTimeout callback executed"</span>);
}, <span class="hljs-number">1000</span>);

<span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"setInterval callback executed"</span>);
}, <span class="hljs-number">2000</span>);
</code></pre>
<h3 id="heading-pending-callbacks-phase">Pending Callbacks Phase</h3>
<p>I/O operations execute in the poll phase of the event loop. During the poll phase, some specific I/O operations callbacks defer to the pending phase of the next iteration of the event loop. I/O operations callbacks deferred from the previous iteration run in the pending callbacks phase.</p>
<p>The code sample below runs during the ‘pending callbacks’ phase:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

fs.readFile(__filename, <span class="hljs-function">(<span class="hljs-params">err, data</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">throw</span> err;
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"File data:"</span>, data);
});
</code></pre>
<h3 id="heading-idle-phase">Idle Phase</h3>
<p>The idle phase is not a normal phase of the Node.js event loop. It is a period whereby the event loop has nothing to do but perform background tasks like checking for low-priority results or running garbage collection.</p>
<p>To skip the idle phase and not perform background tasks, you can call the <code>idle.ignore()</code> method from the <a target="_blank" href="https://www.npmjs.com/package/idle-gc">idle-gc</a> package in your code.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { idle } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"idle-gc"</span>);

idle.ignore();
</code></pre>
<p>The <code>idle.ignore()</code> method ensures that the code continues to run without any idle period till completion. However, due to the performance issues it causes, the <code>idle.ignore()</code> method should be used sparingly.</p>
<h3 id="heading-poll-phase">Poll Phase</h3>
<p>The poll phase is where I/O operations execute. I/O operations transfer data to or from a computer. The event loop checks for new I/O operations and executes them in the poll queue.</p>
<p>The code sample below runs during the poll phase:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">"http"</span>);

http.get(<span class="hljs-string">"http://jsonplaceholder.typicode.com/posts/1"</span>, <span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"HTTP request response received"</span>);
  res.on(<span class="hljs-string">"data"</span>, <span class="hljs-function">(<span class="hljs-params">chunk</span>) =&gt;</span> {
    <span class="hljs-comment">// Do something with the data</span>
  });
});
</code></pre>
<h3 id="heading-check-phase">Check Phase</h3>
<p>The check phase is where the <code>setImmediate</code> timer runs. The Node.js event loop goes to the check phase when there is a <code>setImmediate</code> in the program, and the poll phase becomes idle or when the poll phase completes.</p>
<p>The code sample below runs during the check phase:</p>
<pre><code class="lang-javascript">setImmediate(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"setImmediate callback executed"</span>);
});
</code></pre>
<h3 id="heading-close-callbacks-phase">Close Callbacks Phase</h3>
<p>The close callbacks phase is the last phase of the Node.js event loop. The close callback phase is where callbacks from the close event of a socket and the closing of an <code>HTTP</code> server run.</p>
<p>The code sample below runs during the check phase:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">"http"</span>);

<span class="hljs-keyword">const</span> server = http.createServer(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.writeHead(<span class="hljs-number">200</span>, { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'text/plain'</span> });
  res.end(<span class="hljs-string">'Hello World\n'</span>);
});

server.listen(<span class="hljs-number">3000</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server listening on port 3000'</span>);
  server.close(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server closed'</span>);
  });
});
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The Node.js event loop is the mechanism that enables asynchronous programming in Node.js.</p>
<p>As a Node.js developer, you can understand how your Node.js code runs under the hood if you master the Node.js event loop.</p>
<p>This article explained processes and threads, the JavaScript event loop, and the Node.js event loop.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a QR Code Generator for URLs with Node.js, Next.js, and Azure Blob Storage ]]>
                </title>
                <description>
                    <![CDATA[ A while ago, a client asked me to help them create a special app for generating QR codes so users could receive payments. What set this app apart was that instead of users entering a URL to generate a QR code, they would initiate a request through th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-qr-code-generator-using-nodejs-nextjs-azure-blob-storage/</link>
                <guid isPermaLink="false">66d45dd5a3a4f04fb2dd2e2d</guid>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ qr code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ayomide Wilfred Adeyemi ]]>
                </dc:creator>
                <pubDate>Fri, 10 May 2024 15:41:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/qr-code-image-real.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A while ago, a client asked me to help them create a special app for generating QR codes so users could receive payments.</p>
<p>What set this app apart was that instead of users entering a URL to generate a QR code, they would initiate a request through the app. Then a unique QR code would be generated which would be associated with their account details. The QR code would then be displayed on their screen while the payer scans the QR code using their mobile device's camera.</p>
<p>In this tutorial, you'll learn how to develop a custom QR code generator for URLs using Node.js and Next.js. I'll walk you through the process step by step, including setting up Azure Blob Storage to store the generated URLs. These URLs will then be displayed in the form of QR codes in your Next.js frontend application.</p>
<p>We'll build the backend of the application using <code>Node.js</code> and the <code>Express</code> framework, and the frontend (which interacts with the backend) with <code>Next.js</code>.</p>
<p>I'll also provide explanations on QR codes, the concept of <code>buffers</code> for handling binary data in Node.js, and how it is being used to stream the QR code image data to Azure Blob Storage.</p>
<p>So, let dive in.</p>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>Before you begin you'll need an active <a target="_blank" href="https://azure.microsoft.com/en-us/get-started/azure-portal">Azure</a> account and subscription to create an Azure blob storage.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-a-qr-code">What is a QR Code</a>?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-azure-blob-storage">How to Set Up Azure Blob Storage</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-nodejs-qr-code">Node.js QR Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#code-overwiew">Code Overview</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-connect-the-frontend-application">How to Connect the Frontend Application</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-nextjs-code-walkthrough">Next.js Code Walkthrough</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-start-the-application-locally">How to Start the Application Locally</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-what-is-a-qr-code">What is a QR Code?</h2>
<p>According to <a target="_blank" href="https://www.investopedia.com/terms/q/quick-response-qr-code.asp">Investopedia</a>, a Quick Response (QR) code functions as a specialized barcode, scannable by digital devices, that stores data within a grid of square pixels.</p>
<p>QR codes are extensively employed in digital payments, cryptocurrency, and transmitting web addresses to mobile devices. They can encode URLs, facilitating webpage access.</p>
<p>Now, let's delve into the process of programmatically generating QR codes. Today, I'll demonstrate this step-by-step. To begin, you'll set up an <code>Azure Blob Storage</code> instance in your <code>Azure Portal</code>.</p>
<h2 id="heading-how-to-set-up-azure-blob-storage">How to Set Up Azure Blob Storage</h2>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-overview">Azure Blob Storage</a> is a cloud-based storage service provided by Microsoft Azure. It is part of the Azure Storage suite, which also includes services such as Azure Files, Azure Queues, and Azure Tables.</p>
<p>Azure Blob Storage is designed to store large amounts of unstructured data, such as text or binary data, in the form of objects called blobs. If you are familiar with AWS, Azure Blob Storage is similar to an S3 bucket. Storage accounts are primarily accessed via REST API.</p>
<h3 id="heading-step-1-create-a-storage-account">Step 1: Create a storage account</h3>
<p>You can create your storage account by simply searching for Storage account in the search bar at the top of the Azure Portal.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-16.08.23.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Create Storage Accounts in Azure Portal</em></p>
<p>You can then run through the steps to create your storage account. Just note that this name needs to be unique and it also needs to be all lower case – no spaces but it can include numbers.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-16.16.46.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Create a New Resource Group</em></p>
<h3 id="heading-step-2-create-a-container">Step 2: Create a container</h3>
<p>After creating your storage account, you can now create a <code>container</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-16.44.16.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Create a New Container</em></p>
<p>When accessing blob storage with the <code>QR codes</code> stored in Azure Storage, the URL typically follows a structure like <code>https://&lt;storage_account_name&gt;.blob.core.windows.net/&lt;container_name&gt;/&lt;blob_name&gt;</code>.</p>
<p>Having a container allows us to structure the URLs in a meaningful and organized way, making it easier to manage and share the generated QR codes.</p>
<h3 id="heading-step-3-obtain-azure-storage-connection-string">Step 3: Obtain Azure Storage connection string</h3>
<p>In the <code>Security + networking</code> section, select "Access keys."</p>
<p>Make sure to copy the connection string and save it somewhere as it's required to establish a secure connection between the Azure Storage account and the <code>Node.js</code> application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-16.54.39.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Obtain Access Key for the Container</em></p>
<p>That concludes the discussion on Microsoft Azure Storage. I must say, I thoroughly enjoyed exploring and solving these challenges.</p>
<p>Next, you will be diving into coding, specifically around <code>Nodejs</code> and and then moving on to frontend development, where you'll be using <code>Next.js</code>.</p>
<h2 id="heading-nodejs-qr-code">Node.js QR Code</h2>
<p>First, you need to install <code>Node.js</code> and <code>npm</code> on your computer. Go to the <a target="_blank" href="https://nodejs.org/">Node.js</a> website and download the version for your computer if you don't have it already.</p>
<p>Once you've installed them, check if Node.js and npm are installed correctly by typing these commands in your terminal:</p>
<pre><code class="lang-bash">node -v
npm -v
</code></pre>
<p>Next, go to this GitHub <a target="_blank" href="https://github.com/ayowilfred95/azure-qr-code-generator.git">link</a> to fork the project and then clone it to your preferred directory on your computer.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-17.26.39--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Github Repository Project</em></p>
<p>Once you've cloned the project repository, open the project with your code editor. I'm using <a target="_blank" href="https://code.visualstudio.com/download">VS Code</a>. You'll notice that the project has of two folders: <code>server</code> and <code>frontend</code>. You'll start by navigating to the <code>server</code> folder by typing <code>cd server</code> in your terminal and then press <code>Enter</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-17.48.03.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Change the current directory to a directory named "server."</em></p>
<p>Now you can install all the necessary dependencies by running <code>npm install</code>. This command will download and install all the required packages for the server-side application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-17.55.01.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>installation of dependencies</em></p>
<p>If everything went well, you should see something like this below after <code>npm install</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-17.51.59.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Successful Installation</em></p>
<p>Next, you need to create a <code>.env</code> file in the <code>server</code> directory to store your environment variables. It's not advisable to hardcode sensitive credentials. You can do this easily by running <code>touch .env</code> in your terminal.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-17.59.38.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Create a new file named ".env"</em></p>
<p>In the newly created <code>.env</code> file, you'll define three variables that your application depends on: <code>CONTAINER_NAME</code> , <code>AZURE_STORAGE_CONNECTION_STRING</code>, and <code>PORT</code> .</p>
<p>Assign 'qrcode' as the value for <code>CONTAINER_NAME</code>. This was the name of the container you created inside the Azure Storage account. Also, set the <code>PORT</code> to <code>8000</code>, which is the port your backend application will be listening on.</p>
<p>Now, for the <code>AZURE_STORAGE_CONNECTION_STRING</code>, you'll need to obtain the secret key from the access key you obtained earlier. Copy the connection string and paste it as the value for <code>AZURE_STORAGE_CONNECTION_STRING</code> in the <code>.env</code> file.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-18.18.00.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Store Secret Variables</em></p>
<p>Once you've added these environment variables to the <code>.env</code> file, save it and you're all set to run the server-side of the application!</p>
<p>Before you run the application, let me quickly explain the code. Click on the <code>index.js</code> file.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-18.18.28.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>View Index.js file</em></p>
<h3 id="heading-code-overview">Code overview:</h3>
<p>Below is the code snippet containing the necessary logic for generating QR codes and establishing a connection with the Azure storage account you previously created.</p>
<pre><code class="lang-bash">const express = require(<span class="hljs-string">'express'</span>);
const { BlobServiceClient, generateBlobSASQueryParameters, BlobSASPermissions } = require(<span class="hljs-string">'@azure/storage-blob'</span>);
const qrcode = require(<span class="hljs-string">'qrcode'</span>);
const { v4: uuidv4 } = require(<span class="hljs-string">'uuid'</span>);
const { Readable } = require(<span class="hljs-string">'stream'</span>);
const dotenv = require(<span class="hljs-string">'dotenv'</span>);

dotenv.config();

const app = express();
const port = process.env.PORT || 5000;

// Allowing CORS <span class="hljs-keyword">for</span> <span class="hljs-built_in">local</span> testing
const origins = [
    <span class="hljs-string">"http://localhost:3000"</span>
];

app.use((req, res, next) =&gt; {
    res.header(<span class="hljs-string">'Access-Control-Allow-Origin'</span>, origins.join(<span class="hljs-string">','</span>));
    res.header(<span class="hljs-string">'Access-Control-Allow-Headers'</span>, <span class="hljs-string">'Origin, X-Requested-With, Content-Type, Accept'</span>);
    next();
});


const containerName = process.env.CONTAINER_NAME;

const blobServiceClient = BlobServiceClient.fromConnectionString(process.env.AZURE_STORAGE_CONNECTION_STRING);

app.use(express.json());

app.post(<span class="hljs-string">'/generate-qr'</span>, async (req, res) =&gt; {
    const { url } = req.body;

    // Generate QR Code
    console.log(<span class="hljs-string">'Received URL:'</span>, url);
    const qrCode = await qrcode.toBuffer(url);

    const bufferStream = new Readable();
    bufferStream.push(qrCode);
    bufferStream.push(null);

    // Generate unique file name <span class="hljs-keyword">for</span> Azure Blob Storage
    const fileName = `qr_codes/<span class="hljs-variable">${uuidv4()}</span>.png`;

    try {
        const containerClient = blobServiceClient.getContainerClient(containerName);
        const blockBlobClient = containerClient.getBlockBlobClient(fileName);

        await blockBlobClient.uploadStream(bufferStream, 4 * 1024 * 1024, 20, {
            blobHTTPHeaders: {
                blobContentType: <span class="hljs-string">'image/png'</span>
            }
        });

        // Generate SAS token <span class="hljs-keyword">for</span> blob
        const sasToken = generateSasToken(blockBlobClient);

        // Generate the Blob URL with SAS token
        const blobUrlWithSasToken = `<span class="hljs-variable">${blockBlobClient.url}</span>?<span class="hljs-variable">${sasToken}</span>`;

        // Send response with the Blob URL containing SAS token
        res.json({ qr_code_url: blobUrlWithSasToken });
    } catch (error) {
        console.error(<span class="hljs-string">'Error generating QR Code:'</span>, error);
        res.status(500).json({ error: <span class="hljs-string">'Internal Server Error'</span> });
    }
});

// Function to generate SAS token <span class="hljs-keyword">for</span> blob
<span class="hljs-keyword">function</span> generateSasToken(blobClient) {
    const blobSAS = generateBlobSASQueryParameters({
        containerName: blobClient.containerName,
        blobName: blobClient.blobName,
        permissions: BlobSASPermissions.parse(<span class="hljs-string">"r"</span>), // Read permission
        startsOn: new Date(),
        expiresOn: new Date(new Date().valueOf() + 86400) // Token expires <span class="hljs-keyword">in</span> 24 hours
    }, blobClient.credential);

    <span class="hljs-built_in">return</span> blobSAS.toString();
}

app.listen(port, () =&gt; {
    console.log(`Server is running on port <span class="hljs-variable">${port}</span>`);
});
</code></pre>
<p>Now I'll give a detailed explanation of the code structure, functionalities, and key components of the application.</p>
<h4 id="heading-importing-required-modules">Importing required modules:</h4>
<ul>
<li><p><code>const express = require('express')</code>: This line imports the Express.js framework, which is a Node.js web application framework for building web applications and APIs. It allows you to define routes, handle HTTP requests, and more.</p>
</li>
<li><p><code>const { BlobServiceClient, generateBlobSASQueryParameters, BlobSASPermissions } = require('@azure/storage-blob')</code>: This line imports specific modules from the <code>@azure/storage-blob</code> package, which is the Azure Blob Storage SDK for JavaScript. It allows you to interact with Azure Blob Storage from our Node.js application.</p>
</li>
<li><p><code>const qrcode = require('qrcode')</code>: This line imports the <code>qrcode</code> module, which is a popular Node.js library for generating QR codes.</p>
</li>
<li><p><code>const{ v4: uuidv4 } = require('uuid')</code>: This line imports the <code>uuid</code> module and specifically extracts the <code>v4</code> function as <code>uuidv4</code>. The <code>uuid</code> module is used to generate universally unique identifiers (UUIDs) in Node.js.</p>
</li>
<li><p><code>const{ Readable } = require('stream')</code>: This line imports the <code>Readable</code> class from the built-in Node.js <code>stream</code> module. The <code>Readable</code> class is used to create readable streams, which are useful for handling data that can be read sequentially.</p>
</li>
</ul>
<h4 id="heading-configuring-environment-variables">Configuring environment variables:</h4>
<ul>
<li><code>dotenv.config();</code>: This line loads environment variables from a <code>.env</code> file into <code>process.env</code>. The <code>.env</code> file typically contains <code>CONTAINER_NAME</code> and <code>AZURE_STORAGE_CONNECTION_STRING</code> you specify in your <code>.env</code> file.</li>
</ul>
<h4 id="heading-initializing-the-express-application">Initializing the Express application:</h4>
<ul>
<li><code>const app = express();</code>: This line initializes an Express application instance, which you'll use to define routes, middleware, and other configurations for your web application.</li>
</ul>
<h4 id="heading-defining-port-configuration">Defining port configuration:</h4>
<ul>
<li><code>const port = process.env.PORT || 5000</code>: This line sets the port number for the Express application. It retrieves the port number from the <code>process.env.PORT</code> environment variable, if it exists. If not, it defaults to port <code>5000</code>. This allows flexibility for deploying the application in different environments where the port may be specified externally.</li>
</ul>
<h4 id="heading-allowing-cors-for-local-testing">Allowing CORS for local testing:</h4>
<ul>
<li><p>CORS (Cross-Origin Resource Sharing) is a security feature implemented by web browsers to restrict resources from being requested from another domain or application.</p>
</li>
<li><p>In this section, CORS is being configured to allow requests from a specific origin (<code>http://localhost:3000</code>), which is typically used during local development.</p>
</li>
<li><p>The <code>app.use()</code> function is used to add middleware to the Express application. Here, a middleware function is defined that sets the necessary CORS headers on every HTTP response.</p>
</li>
<li><p><code>res.header('Access-Control-Allow-Origin', origins.join(','))</code>: Sets the value of the <code>Access-Control-Allow-Origin</code> header to allow requests from the specified origins (in this case, <code>http://localhost:3000</code>).</p>
</li>
<li><p><code>res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept')</code>: Sets the allowed headers for the CORS request.</p>
</li>
<li><p><code>next()</code>: Calls the next middleware function in the stack.</p>
</li>
</ul>
<h4 id="heading-azure-blob-storage-configuration">Azure Blob Storage configuration:</h4>
<ul>
<li><p><code>containerName</code> and <code>blobServiceClient</code> are initialized using environment variables (<code>process.env.CONTAINER_NAME</code> and <code>process.env.AZURE_STORAGE_CONNECTION_STRING</code>) configured earlier.</p>
</li>
<li><p><code>blobServiceClient</code> is initialized using the <code>fromConnectionString()</code> method from the <code>BlobServiceClient</code> class provided by the <code>@azure/storage-blob</code> package. This allows the application to interact with Azure Blob Storage using the provided connection string.</p>
</li>
</ul>
<h4 id="heading-express-application-configuration">Express application configuration:</h4>
<ul>
<li><code>app.use(express.json())</code>: Adds middleware to parse JSON bodies of incoming requests. This enables the application to handle JSON data in requests.</li>
</ul>
<h4 id="heading-endpoint-for-generating-qr-codes">Endpoint for generating QR codes:</h4>
<ul>
<li><p>Defines a POST endpoint at <code>/generate-qr</code> to handle requests for generating QR codes.</p>
</li>
<li><p>Upon receiving a request, the endpoint extracts the URL from the request body and generates a QR code image using the <code>qrcode.toBuffer()</code> function.</p>
</li>
<li><p>The generated QR code image is then uploaded to Azure Blob Storage as a blob with a unique file name.</p>
</li>
<li><p>After successfully uploading the image, a Shared Access Signature (SAS) token is generated for the blob, which provides temporary access to the blob with specified permissions (in this case, read-only).</p>
</li>
<li><p>Finally, the endpoint responds with a JSON object containing the URL of the generated QR code image along with the SAS token.</p>
</li>
</ul>
<h4 id="heading-function-to-generate-sas-token-for-blob">Function to generate SAS token for blob:</h4>
<ul>
<li>Defines a function <code>generateSasToken()</code> to generate a SAS token for a given blob client (block blob client in this case). The SAS token is generated with read permissions and an expiration time set to 24 hours.</li>
</ul>
<h4 id="heading-listening-on-port">Listening on port:</h4>
<ul>
<li>The Express application listens on the configured port (<code>port</code>) for incoming HTTP requests. When the server starts, it prints a message indicating the port it is listening on.</li>
</ul>
<p>Now, you can start the application locally.</p>
<p>To start the application, simply run <code>npm start</code> as shown below. If all goes well, you'll observe the message <code>Server is running on port 8000</code> printed on your console.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-18.36.50.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Start the Application locally</em></p>
<h2 id="heading-how-to-connect-the-frontend-application">How to Connect the Frontend Application</h2>
<p>Now it is time to connect the frontend application with the backend application that is listening on Port 8000.</p>
<p>A typical full-stack application usually consists of at least two main components: a frontend (client-side) and a backend (server-side).</p>
<p><strong>Frontend Component</strong>: This is the part of the application that users interact with directly. It's typically built using technologies like HTML, CSS, and JavaScript frameworks like React, Angular, or Next.js.</p>
<p><strong>Backend Component</strong>: This is the part of the application that handles data storage, retrieval, and server side connectivity. It's usually built using server-side programming languages like Node.js (with frameworks like Express.js or Nest.js), Python (with frameworks like Django or Flask), Java (with frameworks like Spring), or Ruby (with frameworks like Ruby on Rails).</p>
<p>The backend communicates with the frontend, processes requests from users, interacts with databases, and generates responses.</p>
<p>To navigate to the frontend folder, open a new terminal by clicking the <code>+</code> , then use <code>cd frontend</code> to enter the frontend folder.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-18.57.14.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Navigate to Frontend Directory</em></p>
<p>Now, you can install all the necessary dependencies by running <code>npm install</code>. This command will download and install all the required packages for the Nextjs client-side application.</p>
<p>If everything went well, you should see something like this after <code>npm install</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-17.51.59-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Successful Installation of Dependencies</em></p>
<p>Before you run the application, let me quickly explain the code.Navigate to the frontend folder, then inside the <code>src/app</code> directory, click on the page.js file.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-18.50.17.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>View page.js file</em></p>
<h3 id="heading-nextjs-code-walkthrough">Next.js Code Walkthrough</h3>
<p>This code represents a React component serving as the frontend for the QR code generator backend application you've recently built. This component allows users to input a URL, submit it, and receive the corresponding QR code image for display.</p>
<pre><code class="lang-bash"><span class="hljs-string">'use client'</span>

import { useState } from <span class="hljs-string">'react'</span>;
import axios from <span class="hljs-string">'axios'</span>;

<span class="hljs-built_in">export</span> default <span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">Home</span></span>() {
  const [url, setUrl] = useState(<span class="hljs-string">''</span>);
  const [qrCodeUrl, setQrCodeUrl] = useState(<span class="hljs-string">''</span>);

  const handleSubmit = async (e) =&gt; {
    e.preventDefault();
    try {
      const response = await axios.post(<span class="hljs-string">'http://localhost:8000/generate-qr'</span>, { url });
      setQrCodeUrl(response.data.qr_code_url);
    } catch (error) {
      console.error(<span class="hljs-string">'Error generating QR Code:'</span>, error);
    }
  };

  <span class="hljs-built_in">return</span> (
    &lt;div style={styles.container}&gt;
      &lt;h1 style={styles.title}&gt;QR Code Generator&lt;/h1&gt;
      &lt;form onSubmit={handleSubmit} style={styles.form}&gt;
        &lt;input
          <span class="hljs-built_in">type</span>=<span class="hljs-string">"text"</span>
          value={url}
          onChange={(e) =&gt; setUrl(e.target.value)}
          placeholder=<span class="hljs-string">"Enter URL like https://www.google.com"</span>
          style={styles.input}
        /&gt;
        &lt;button <span class="hljs-built_in">type</span>=<span class="hljs-string">"submit"</span> style={styles.button}&gt;Generate QR Code&lt;/button&gt;
      &lt;/form&gt;
      {qrCodeUrl &amp;&amp; &lt;img src={qrCodeUrl} alt=<span class="hljs-string">"QR Code"</span> style={styles.qrCode} width=<span class="hljs-string">"200"</span> height=<span class="hljs-string">"200"</span> /&gt;}
    &lt;/div&gt;
  );
}

// Styles
const styles = {
  container: {
    minHeight: <span class="hljs-string">'100vh'</span>,
    display: <span class="hljs-string">'flex'</span>,
    flexDirection: <span class="hljs-string">'column'</span>,
    alignItems: <span class="hljs-string">'center'</span>,
    justifyContent: <span class="hljs-string">'center'</span>,
    backgroundColor: <span class="hljs-string">'#121212'</span>,
    color: <span class="hljs-string">'white'</span>,
  },
  title: {
    margin: <span class="hljs-string">'0'</span>,
    lineHeight: <span class="hljs-string">'1.15'</span>,
    fontSize: <span class="hljs-string">'4rem'</span>,
    textAlign: <span class="hljs-string">'center'</span>,
  },
  form: {
    display: <span class="hljs-string">'flex'</span>,
    flexDirection: <span class="hljs-string">'column'</span>,
    alignItems: <span class="hljs-string">'center'</span>,
  },
  input: {
    padding: <span class="hljs-string">'10px'</span>,
    borderRadius: <span class="hljs-string">'5px'</span>,
    border: <span class="hljs-string">'none'</span>,
    marginTop: <span class="hljs-string">'20px'</span>,
    width: <span class="hljs-string">'300px'</span>,
    color: <span class="hljs-string">'#121212'</span>

  },
  button: {
    padding: <span class="hljs-string">'10px 20px'</span>,
    marginTop: <span class="hljs-string">'20px'</span>,
    border: <span class="hljs-string">'none'</span>,
    borderRadius: <span class="hljs-string">'5px'</span>,
    backgroundColor: <span class="hljs-string">'#0070f3'</span>,
    color: <span class="hljs-string">'white'</span>,
    cursor: <span class="hljs-string">'pointer'</span>,
  },
  qrCode: {
    marginTop: <span class="hljs-string">'20px'</span>,
  },
};
</code></pre>
<p>Now I'll give a detailed explanation of the frontend application's code structure, functionalities, and key components.</p>
<h4 id="heading-state-management">State management:</h4>
<ul>
<li><p><code>import { useState } from 'react'</code> imports the <code>useState</code> hook from React to manage state within the component.</p>
</li>
<li><p><code>const [url, setUrl] = useState('')</code> and <code>const [qrCodeUrl, setQrCodeUrl] = useState('')</code>: This state variables, <code>url</code> and <code>qrCodeUrl</code>, are initialized using the <code>useState</code> hook. These variables hold the input URL and the generated QR code URL, respectively.</p>
</li>
</ul>
<h4 id="heading-form-submission">Form submission:</h4>
<ul>
<li><p>When the form is submitted, the <code>handleSubmit</code> function is triggered.</p>
</li>
<li><p>This function prevents the default form submission behavior by using <code>e.preventDefault()</code>.</p>
</li>
<li><p>It sends a POST request to the server (<code>http://localhost:8000/generate-qr</code>) with the input URL using the <a target="_blank" href="https://axios-http.com/docs/intro">Axios</a> library.</p>
</li>
<li><p>Upon successful response, the generated QR code URL is stored in the <code>qrCodeUrl</code> state variable.</p>
</li>
</ul>
<h4 id="heading-rendering">Rendering:</h4>
<ul>
<li><p>The component renders a title, a form with an input field for entering the URL, and a button to generate the QR code.</p>
</li>
<li><p>When the QR code URL is available (<code>qrCodeUrl</code> is not empty), an image element is rendered to display the generated QR code.</p>
</li>
</ul>
<h4 id="heading-styling">Styling:</h4>
<ul>
<li><p>The component includes inline styles defined using JavaScript objects.</p>
</li>
<li><p>Styles are applied to the container, title, form, input field, button, and QR code image.</p>
</li>
</ul>
<h2 id="heading-how-to-start-the-application-locally">How to Start the Application Locally</h2>
<p>Now, you can start the application locally.</p>
<p>To start the application, simply run <code>npm run dev</code> as shown below. If all goes well, you'll observe the message <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a> printed in your console.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-08-at-15.18.18.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Application ready to start</em></p>
<p>Open your browser and paste the URL <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a>. The browser should render the application and look exactly as shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-09-at-11.32.04.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Application running in Browser</em></p>
<p>Paste in the URL of a website – either your portfolio website or any website you wish to generate a QR code for. I pasted my portfolio website URL, <a target="_blank" href="https://wilfred-portfolio.vercel.app/"><code>https://wilfred-portfolio.vercel.app/</code></a>, into the URL box. See the result below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-07-at-20.32.40.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>QR Code generated successfully</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>When it comes to picking the right tools, technology choices are important. Next.js is great for making the front end of a website, while Node.js works well for handling server-side tasks. Also Azure blob storage is great for storing unstructured data such as binary data like QR code.</p>
<p>But remember, this journey is not just about writing code. It's also about learning about different technologies and picking the best ones for what you need to do.</p>
<p>As I finish up this tutorial, I'd like to keep asking for feedback to ensure that this tutorial stays helpful. Feel free to share your thoughts or comments with me.</p>
<p>Thanks for reading!</p>
<p>Happy coding! 🚀</p>
<h3 id="heading-contact-me"><strong>Contact Me:</strong></h3>
<ul>
<li><p><a target="_blank" href="https://twitter.com/ayomidewilfred9">Twitter</a></p>
</li>
<li><p><a target="_blank" href="https://www.linkedin.com/in/ayomide-wilfred-95083a104/">LinkedIn</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/Ayowilfred95">GitHub</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Run a Postgres Database in Azure Kubernetes Service and Integrate it with a Node.js Express Application ]]>
                </title>
                <description>
                    <![CDATA[ Hey everyone! Today, you're going to learn about deploying a Postgres container in Azure Kubernetes Service (AKS) and connecting it to a Node.js application. In this fast-paced development landscape, deploying via containers, particularly with Kubern... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-run-postgres-in-kubernetes/</link>
                <guid isPermaLink="false">66d45dd851f567b42d9f8435</guid>
                
                    <category>
                        <![CDATA[ containerization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Kubernetes ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgres ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ayomide Wilfred Adeyemi ]]>
                </dc:creator>
                <pubDate>Wed, 08 May 2024 20:43:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/Azure-K8s-article-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hey everyone! Today, you're going to learn about deploying a Postgres container in Azure Kubernetes Service (AKS) and connecting it to a Node.js application.</p>
<p>In this fast-paced development landscape, deploying via containers, particularly with Kubernetes, is becoming increasingly popular. Some companies perform numerous deployments daily, so it's crucial for you to learn these technologies.</p>
<p>Kubernetes is a popular choice to deploy containerized applications like web servers, databases, and APIs. You can set up Kubernetes either locally or in the cloud. In this tutorial, we'll explore setting up Kubernetes on a cloud platform, specifically Azure.</p>
<p>I'll walk you through the process of setting up Kubernetes using Azure Kubernetes Service (AKS). You'll configure your YAML file using StatefulSet, Persistent Volume, and Services to deploy a PostgreSQL database on Azure Kubernetes. Then, you'll obtain the PostgreSQL database credentials running inside the AKS and use them to establish a connection with a Node.js application.</p>
<p>We'll cover key concepts such as deployment, stateful sets, persistent volumes, and services, preparing you to deploy a Postgres container effectively on AKS. I'll also help you connect your Node.js Express app to the Postgres container within the AKS cluster.</p>
<p>So find a comfortable seat and get ready, as we're about to dive in.</p>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>Before you begin, it's important to understand some basic concepts in <a target="_blank" href="https://kubernetes.io">Kubernetes</a> like <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/pods/">pods</a>, <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">deployments</a>, <a target="_blank" href="https://kubernetes.io/docs/concepts/services-networking/service/">services</a>, and <a target="_blank" href="https://kubernetes.io/docs/concepts/architecture/nodes/">nodes</a>.</p>
<p>If you're new to this, I recommend checking out the Stashchuk freeCodeCamp <a target="_blank" href="https://www.youtube.com/watch?v=d6WC5n9G_sM">video</a> for a beginner-friendly tutorial.</p>
<p>You'll also need an active <a target="_blank" href="https://azure.microsoft.com/en-us/get-started/azure-portal">Azure</a> account and subscription to follow along.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#challenges-were-trying-to-solve">Challenges We're Trying to Solve</a><br>  – <a class="post-section-overview" href="#heading-deployments">Deployments</a><br>  – <a class="post-section-overview" href="#heading-statefulsets">StatefulSets</a><br>  – <a class="post-section-overview" href="#heading-persistent-volumes">Persistent Volumes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-azure-kubernetes-service-aks">Azure Kubernetes Service (AKS)</a><br>  – <a class="post-section-overview" href="#heading-step-1-sign-in-to-your-azure-portal">Sign in to Your Azure Portal</a><br>  – <a class="post-section-overview" href="#heading-step-2-create-a-resource">Create a Resource</a><br>  – <a class="post-section-overview" href="#heading-step-3-create-a-new-container">Create a new container</a><br>  – <a class="post-section-overview" href="#heading-step-4-create-a-new-azure-kubernetes-service-aks">Create a new Azure Kubernetes Service(AKS)</a><br>  – <a class="post-section-overview" href="#heading-step-5-create-a-new-resource-group">Create a new resource group</a><br>  – <a class="post-section-overview" href="#heading-step-6-give-your-kubernetes-cluster-a-name">Give your Kubernetes cluster a name</a><br>  – <a class="post-section-overview" href="#heading-step-7-navigate-to-the-node-pool-page">Navigate to the node pool page</a><br>  – <a class="post-section-overview" href="#heading-step-8-enable-container-logs-and-set-up-alerts">Enable container logs and set up alerts</a><br>  – <a class="post-section-overview" href="#heading-step-9-advanced-section">Advanced Section</a><br>  – <a class="post-section-overview" href="#heading-step-10-tags">Tags</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-connect-to-your-aks-cluster-using-the-command-line">Connect to Your AKS Cluster</a><br>  – <a class="post-section-overview" href="#heading-download-azure-cli-and-kubectl">Download Azure CLI and kubectl</a><br>  – <a class="post-section-overview" href="#heading-verify-if-the-azure-cli-is-installed-by-typing-the-command-az-version">Verify if Azure CLI is installed</a><br>  – <a class="post-section-overview" href="#heading-verify-if-kubectl-is-installed">Verify if kubectl is installed</a><br>  – <a class="post-section-overview" href="#heading-login-to-your-azure-account">Login to Azure account</a><br>  – <a class="post-section-overview" href="#heading-configure-kubectl-to-connect-to-your-azure-kubernetes">Configure kubectl</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-resources-with-yaml">How to Create Resources with YAML</a><br>  – <a class="post-section-overview" href="#heading-clone-the-repository">Clone the Repository</a><br>  – <a class="post-section-overview" href="#heading-open-the-cloned-repository-in-any-text-editor">Open the Repository</a><br>  – <a class="post-section-overview" href="#heading-install-project-dependencies">Install Dependencies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-yaml-configuration">YAML Configuration</a><br>  – <a class="post-section-overview" href="#heading-storageclass">StorageClass</a><br>  – <a class="post-section-overview" href="#heading-persistentvolumeclaim">PersistentVolumeClaim</a><br>  – <a class="post-section-overview" href="#heading-configmap">ConfigMap</a><br>  – <a class="post-section-overview" href="#heading-statefulset">StatefulSet</a><br>  – <a class="post-section-overview" href="#heading-service">Service</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-deploy-yaml-resource-to-azure-kubernetes-service-aks">How to Deploy YAML Resource to Azure</a><br>  – <a target="_blank" href="https://www.freecodecamp.org/news/p/a37cba54-1e70-4fb6-99d4-d9ee63e66e1b/deploy-the-yaml-resource">Deploy the YAML resource</a></p>
</li>
<li><p><a class="post-section-overview" href="#nodejs-application">Node.js Application</a><br>  – <a class="post-section-overview" href="#heading-configure-your-nodejs-application">Configure Nodejs</a><br>  – <a class="post-section-overview" href="#heading-run-your-nodejs-application">Run Nodejs Application</a><br>  – <a class="post-section-overview" href="#heading-test-the-application">Test the Application</a><br>  – <a class="post-section-overview" href="#heading-open-your-postman-application">Open Postman</a><br>  – <a class="post-section-overview" href="#heading-confirm-the-data">Confirm the Data</a><br>  – <a class="post-section-overview" href="#heading-delete-the-pod-to-confirm-data-persistence">Delete Pod</a><br>  – <a class="post-section-overview" href="#heading-data-persistence">Data Persistence</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-challenges-were-trying-to-solve">Challenges We're Trying to Solve</h2>
<p>Firstly, what is Kubernetes? Well, it's like a manager for your software containers. It helps you run and manage lots of containers like web servers, databases, microservices, and APIs which are like little packages holding your applications.</p>
<p>Kubernetes takes care of things like starting, stopping, and scaling these containers, so your apps run smoothly even when there is more load on your application. It's popular because it makes running software in the cloud easier and more reliable.</p>
<p>Now, let's talk about how to tackle some challenges you might face with a real-world application running Postgres in a Kubernetes production cluster.</p>
<p>Imagine that the infrastructure hosting your Postgres crashes, causing you to lose all the services and data stored in the database. Or, picture a scenario where the Postgres database becomes corrupted, leading to data loss.</p>
<p>In both cases, you need a way to back up your application so you can restore it to a working state if disaster strikes.</p>
<p>So, how do you capture a comprehensive application backup that includes all the necessary data? This backup should allow you to restore the entire application, including the database, if you lose your cluster or encounter data loss.</p>
<p>In Kubernetes, think of a Pod as the tiniest unit that you can deploy. It's like a small box that holds one thing, like a web server or a database. So, if your Pod isn't running, your web server or database isn't either.</p>
<p>This means that if the cluster where your Pod runs gets destroyed, all the data in the Pod disappears too. All the nodes (virtual machines that run your application over the network) will also be wiped out.</p>
<p>How can you make a pod stay on one specific node where the data is and never move? And how can you make sure that each pod can be found separately when you're using a load balancer?</p>
<p>One solution is to consider how you deploy your application on Kubernetes. Typically, you create a <strong>deployment</strong> and expose it using a service, specifying the service type as either Cluster type, NodePort, or LoadBalancer.</p>
<p>But not all applications are the same when it comes to state. Some applications, known as stateless applications, don't rely on storing data locally, so losing their state isn't a big issue.</p>
<p>But for applications like databases or caches, maintaining state is crucial because they rely on storage. In Kubernetes, deploying stateful applications like databases using just deployment isn't ideal. You need a solution that ensures your application's data is safely stored and can be recovered in case of failure.</p>
<h3 id="heading-deploymentshttpskubernetesiodocsconceptsworkloadscontrollersdeployment"><a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">Deployments</a></h3>
<p>You might be wondering why we can't just use a Kubernetes deployment to deploy Postgres in the Kubernetes cluster? Well, the thing is, many people aren't aware of the difference between a deployment and a stateful set.</p>
<p>Let's imagine you have a pod running in your cluster that you created using a deployment. Then you scaled up to two pods, so you now have Pod A and Pod B.</p>
<p>The problem arises because, by default, pods created as part of the same deployment share the same <strong>persistent volume</strong> (PV) across the cluster. So, when you scaled up, both instances of Postgres would write to the same storage, which could lead to data corruption.</p>
<p>Another issue arises from a networking perspective. Pods A and B don't have a dependable way to communicate with each other over the network. By default, Kubernetes pods don't have their own DNS names. Instead, you rely on <strong>services</strong> to expose ports to other applications in the cluster.</p>
<p>If you take a closer look at pod names, you'll notice that pods are assigned a random hash at the end of their names. Because of this, pods lack a consistent network identity. Every time a pod is destroyed and recreated, it receives a new randomized name. This inconsistency isn't ideal for reliable networking.</p>
<p>Postgres isn't naturally made for <strong>Kubernetes</strong>, and Kubernetes can be tough when handling stateful tasks. To set up a Postgres instance, you've got to know the right Kubernetes setup. You can't just throw it in a pod, because if the pod goes down, so does your data. But, for a quick integration, a pod could work fine.</p>
<p>Deployments aren't ideal either, since you don't want your pod randomly placed on a node. But for testing, deployments are handy if you just need a Postgres instance to run temporarily.</p>
<p>What you really want is a pod that sticks to a particular node where your data resides, and stays put. Plus, you also want your pod to be individually addressable. for this we need what we called a <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/"><strong>statefulSet</strong></a>.</p>
<h3 id="heading-statefulsetshttpskubernetesiodocsconceptsworkloadscontrollersstatefulset"><a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/"><strong>StatefulSets</strong></a></h3>
<p>When you update your deployment to become a <strong>StatefulSet</strong>, Kubernetes introduces some improvements for deploying stateful workloads. One major change is how it handles scaling.</p>
<p>If you specify that you want three replicas of your StatefulSet, Kubernetes won't create all three pods at once. Instead, it creates them one by one. Each pod gets its own unique DNS name, starting with the pod's name followed by an ordinal number starting from zero. So, when you scale up, the ordinal number increases for each new pod.</p>
<p>Here's the cool part: if a pod like Pod-0 is destroyed and needs to be remade, it will return with the same name. This means each pod has a specific address, even if it's replaced.</p>
<p>And here's another cool feature: each pod in a StatefulSet gets its own persistent volume (PV). This lets you keep the same storage even if you scale up or down. This brings us to another concept called persistent volumes.</p>
<h3 id="heading-persistent-volumeshttpskubernetesiodocsconceptsstoragepersistent-volumes"><a target="_blank" href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/">Persistent Volumes</a></h3>
<p>Let's forget about pods, deployment, and containers for a moment. What exactly is "state"? In simple terms, state is the data that your applications need to work properly.</p>
<p>Now, when we talk about processes, there are two types: stateless and stateful. <strong>Stateless</strong> processes don't rely on any data to work. They just do their thing without needing any specific information. On the other hand, <strong>stateful</strong> processes need data or state to function properly.</p>
<p>Now, where do you store this state? There are two main places: memory and disk. <strong>Memory</strong> allows for quick access to data, which is great for applications like Redis, MongoDB, Postgres, or MySQL. They store their state on memory for quick access. But for persistent, they store it on <strong>disk</strong> on the file system (for more permanent storage).</p>
<p>Why the file system? Because it's the only way to keep the state persistent even when the system reboots. So, when a process dies and gets recreated, it can read its state from the file system.</p>
<p>I like breaking things down because I used to teach tech stuff. Now, let's get into setting up Kubernetes in Azure.</p>
<h2 id="heading-azure-kubernetes-service-aks"><strong>Azure Kubernetes Service (AKS)</strong></h2>
<p>In this section, I'll guide you through setting up a Kubernetes cluster on Azure.</p>
<h3 id="heading-step-1-sign-in-to-your-azure-portal">Step 1: Sign in to your Azure portal</h3>
<p>To begin, you will have to sign into your <a target="_blank" href="https://azure.microsoft.com/en-us/get-started/azure-portal">Azure</a> portal. Once logged in, you should see a dashboard similar to this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.39.46.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Azure portal homepage</em></p>
<h3 id="heading-step-2-create-a-resource">Step 2: Create a resource</h3>
<p>Click on "create a resource" to create a resource.</p>
<p>Resources are the various services, components, and assets that you can create and manage within the Azure cloud platform. These resources can include virtual machines, databases, storage accounts, networking components, web applications, and more.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.39.46--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating a resource in Azure portal</em></p>
<h3 id="heading-step-3-create-a-new-container">Step 3: Create a new container</h3>
<p>Next, navigate to the "Containers" category from the options available on the left pane. Click on Containers as shown by the arrow in the screenshot.</p>
<p>Again, Kubernetes is a container orchestration platform. It manages and orchestrates the deployment, scaling, and operation of application containers across clusters of machines. Kubernetes provides a framework for automating the deployment, scaling, and management of containerized applications.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.42.12--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating new container (Kubernetes) in Azure</em></p>
<h3 id="heading-step-4-create-a-new-azure-kubernetes-service-aks"><strong>Step 4: Create a new Azure Kubernetes Service (AKS)</strong></h3>
<p>Select "Azure Kubernetes Service (AKS)" from the list of available container services and click Create. This will take you to the AKS creation page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.42.37--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating a new Azure Kubernetes service</em></p>
<h3 id="heading-step-5-create-a-new-resource-group">Step 5: Create a new resource group</h3>
<p>In the "Resource group" section, click on "Create new" to create a new resource group for your Azure Kubernetes Service (AKS) deployment.</p>
<p>In Azure, a "resource group" is a logical container used to group together related Azure resources. It serves as a way to organize and manage these resources collectively, rather than individually.</p>
<p>When you create resources such as virtual machines, databases, storage accounts, or any other Azure service, you typically associate them with a resource group.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.43.09--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating a new resource group in azure portal</em></p>
<p>Let's name the resource group "AZURE-POSTGRES-RG" as shown below. You can name it anything you like. Then click ok.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.43.45.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Inputting name for the resource group</em></p>
<h3 id="heading-step-6-give-your-kubernetes-cluster-a-name">Step 6: Give your Kubernetes cluster a name</h3>
<p>Now let's name the session for configuring the Kubernetes cluster "Kubernetes Cluster Name".</p>
<p>In Azure, a Kubernetes cluster is a managed container orchestration service provided by Azure Kubernetes Service (AKS). It allows you to deploy, manage, and scale containerized applications using Kubernetes without having to manage the underlying infrastructure.</p>
<p>Give it a name like "AZURE-POSTGRES-KC" and and select a region that's close to you. In my case I select (Asia Pacific) East Asia and click next.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.47.34--3-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Naming the Kubernetes cluster name</em></p>
<h3 id="heading-step-7-navigate-to-the-node-pool-page">Step 7: Navigate to the node pool page</h3>
<p>Now it's time to configure the node pool session by clicking on the agentpool.</p>
<p>In Azure, a node pool is a group of virtual machines (VMs) that are provisioned and managed together within an Azure Kubernetes Service (AKS) cluster. Each node pool runs a specific version of Kubernetes and has its own set of configurations, such as VM size, OS image, and node count.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.47.50--1-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Editing agentpool</em></p>
<p>Set the minimum node count to 1, maximum node count to 2, and the maximum pods per node to 30 to minimise cost. Then click update.</p>
<p>These parameters help control the size and behavior of the node pool in an Azure Kubernetes Service (AKS) cluster:</p>
<ol>
<li><p><strong>Minimum Node Count</strong>: Ensures a minimum number of nodes are always available for consistent performance and availability, even during low-demand periods.</p>
</li>
<li><p><strong>Maximum Node Count</strong>: Sets an upper limit on the number of nodes in the node pool to manage costs and prevent over-provisioning.</p>
</li>
<li><p><strong>Maximum Pods per Node</strong>: Defines the maximum number of pods that can run on each node, optimizing resource utilization and preventing overcrowding.</p>
</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.48.29--1-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Updating agentpool details</em></p>
<p>Once you've clicked "Update," you'll be directed to the "Networking" section as shown below. Keep the page as is and proceed by clicking "Next." This will take you to Integration session.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.48.55--1-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Navigating to Next Page</em></p>
<p>Azure Container Registry (ACR) is a fully managed private Docker registry service provided by Microsoft Azure. It enables developers to store, manage, and deploy Docker container images securely within their Azure environment.</p>
<p>You will need a place to store the Docker image that's pulled.</p>
<p>To begin, select "Create New" to set up a new container registry. This action will bring up a page where you can input the necessary details, as illustrated on the right side of the image below. Enter the details as indicated by the arrows and then click "Okay." Once you're done, proceed by clicking "Next."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.49.36--1-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Naming and editing Azure Container Registry details</em></p>
<h3 id="heading-step-8-enable-container-logs-and-set-up-alerts">Step 8: Enable container logs and set up alerts</h3>
<p>The <strong>Enable Container Logs</strong> option allows you to turn on logging for your containers. Logging records important information about what's happening inside your containers, like errors, warnings, and other events. It's useful for troubleshooting and monitoring your applications.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.50.25--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Choosing container logs</em></p>
<h3 id="heading-step-9-advanced-section">Step 9: Advanced section</h3>
<p>Keep the Monitoring section unchanged and proceed by clicking "Next."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.50.32.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Navigating to Next Page</em></p>
<h3 id="heading-step-10-tags">Step 10: Tags</h3>
<p>Keep the Tags section unchanged and proceed by clicking "Next."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.50.44.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Navigating to Next Page</em></p>
<h3 id="heading-step-11-click-review-create-to-finalize-the-deployment">Step 11: Click "Review + create" to finalize the deployment</h3>
<p>Once completed, your resource group, Azure Kubernetes Service (AKS), Azure Container Registry, and Kubernetes cluster will be created.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.51.39--1-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Completing Azure Kubernetes Setup</em></p>
<p>The screenshot below shows that the deployment was successful.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-18.01.53.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Successful Deployment</em></p>
<p>You've just successfully created an Azure Kubernetes Service from the Azure portal. Congrats!</p>
<h2 id="heading-how-to-connect-to-your-aks-cluster-using-the-command-line">How to Connect to Your AKS Cluster Using the Command Line</h2>
<p>After successfully creating a new AKS in the Azure portal, the next step is to establish a connection to that cluster.</p>
<p>In this section, I'll guide you through Azure login, configuring kubectl to use the current context, and creating the YAML file for our Postgres container. This file will include StatefulSet, persistent volume, persistent volume claim, config map, and using Azure File for data storage.</p>
<p>I'll also show you how to run a Node.js Express application locally, use Postman to test the endpoints, and receive a response confirming that data was sent to the database successfully.</p>
<h3 id="heading-download-azure-cli-and-kubectl">Download Azure CLI and kubectl</h3>
<p>To start, you'll need to download the Azure CLI and kubectl.</p>
<ul>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/cli/azure/install-azure-cli"><strong>Azure CLI</strong></a> <strong>(Command-Line Interface)</strong>: a command-line tool provided by Microsoft for managing Azure resources. It allows users to interact with Azure services and resources directly from the command line, making it easy to automate tasks, create scripts, and manage Azure resources programmatically.</p>
</li>
<li><p><a target="_blank" href="https://kubernetes.io/docs/tasks/tools/"><strong>kubectl</strong></a>: a command-line tool for managing Kubernetes clusters, used to deploy, scale, and manage containerized applications. It allows users to perform operations like deploying applications, managing pods, services, and deployments, inspecting cluster resources, scaling applications, and debugging issues, simplifying management of containerized workloads in a Kubernetes environment.</p>
</li>
</ul>
<p>I'm using the warp terminal. <a target="_blank" href="https://www.warp.dev/">Warp</a> is the terminal reimagined with AI and collaborative tools for better productivity. You can run the command using PowerShell on Windows or Terminal on Mac. I'm using a MacBook.</p>
<h3 id="heading-verify-if-the-azure-cli-is-installed-by-typing-the-command-az-version">Verify if the Azure CLI is installed by typing the command <code>az --version</code></h3>
<p>Once the download finishes, verify whether Azure CLI is installed on your computer by running the command <code>az --version</code>. If the installation is successful, you should see an output similar to this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-21.18.48.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Verifying Azure CLI Installation</em></p>
<h3 id="heading-verify-if-kubectl-is-installed">Verify if kubectl is installed</h3>
<p>To check if kubectl is installed, just type <code>kubectl version</code> in the command line.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-21.31.01.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Verifying Kubectl Installation</em></p>
<h3 id="heading-login-to-your-azure-account">Login to your Azure account</h3>
<p>Enter <code>az login</code> in the command line. This will open your browser and prompt you to sign in to your Azure account.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-21.47.47.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Logging into Azure</em></p>
<p>After signing in, it shows details about your Azure subscription, including the subscription name, ID, and user information.</p>
<h3 id="heading-select-an-azure-subscription">Select an Azure subscription</h3>
<p>Azure subscriptions are logical containers used to provision resources in Azure. You'll need to locate the subscription ID that you plan to use in this module. Use the command to list your Azure subscriptions:</p>
<pre><code class="lang-bash">az account list --output table
</code></pre>
<p>Use the following command to ensure you're using an Azure subscription that allows you to create resources for the purpose of this module, substituting your subscription ID (SubscriptionId):</p>
<pre><code class="lang-bash">az account <span class="hljs-built_in">set</span> --subscription <span class="hljs-string">"Name of the subscription"</span>
</code></pre>
<h3 id="heading-configure-kubectl-to-connect-to-your-azure-kubernetes">Configure kubectl to connect to your Azure Kubernetes</h3>
<p>Replace <code>Your_Azure_Resource_groups_name</code> in the code below with the name you chose when creating a resource group. Also, replace <code>your_azure_kubernetes_service_name</code> with the name of your Kubernetes cluster. Then, execute the following command:</p>
<pre><code class="lang-bash">az aks get-credentials --resource-group [Your_Azure_Resource_groups_name] --name [your_azure_kubernetes_service_name]
</code></pre>
<p>The output should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.07.20.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Merging kubectl with Azure Kubernetes Service</em></p>
<h3 id="heading-verify-if-kubectl-has-been-merged-successfully">Verify if kubectl has been merged successfully</h3>
<p>Run the following command <code>kubectl get nodes</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.09.33.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Verifying if merged is successful</em></p>
<p>When you run this command, Kubernetes communicates with the cluster's control plane to fetch a list of all the nodes that are part of the cluster you created. As you can see, this is the node that was running in the Kubernetes cluster we created inside Azure.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-18.04.07.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Virtual Node running in AKS cluster</em></p>
<h3 id="heading-run-the-command-kubectl-get-pods">Run the command <code>kubectl get pods</code></h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.18.19.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Displaying Pod Information</em></p>
<p>When you run the command <code>kubectl get pods</code>, Kubernetes attempts to retrieve information about all pods within the default namespace of your cluster. But in this case, the output indicates that there are no resources (pods) found within the default namespace, implying that no pods currently exist in that namespace.</p>
<p>A <strong>namespace</strong> in Kubernetes is a virtual cluster environment within which resources like pods, services, and deployments are organized and isolated. It's a way to divide cluster resources between multiple users, teams, or projects. Namespaces provide a scope for names and make it easier to manage and control access to resources.</p>
<p>By default, Kubernetes starts with a "default" namespace, but you can create additional namespaces to organize and manage resources more effectively. Namespaces help prevent naming conflicts and provide a logical separation of resources, allowing different teams or projects to work independently within the same Kubernetes cluster.</p>
<h3 id="heading-create-a-namespace">Create a namespace</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.24.40.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating Namespace</em></p>
<p>When you run the command <code>kubectl create namespace database</code>, Kubernetes creates a new namespace named "database." The output "namespace/database created" confirms that the namespace has been successfully created.</p>
<p>You can now use this namespace to organize and manage resources related to databases within the Kubernetes cluster.</p>
<h3 id="heading-confirm-the-namespace">Confirm the namespace</h3>
<p>The command <code>kubectl get namespace</code> lists all namespaces in the Kubernetes cluster including the database namespace we just created, showing their names, status (active), and age.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.26.22.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Confirming namespace</em></p>
<h3 id="heading-get-pod-information-in-database-namespace">Get pod information in database namespace</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.35.29.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Displaying Pod Information related to database namespace</em></p>
<p>This command, <code>kubectl get pods -n database</code>, attempts to fetch information about pods specifically within the "database" namespace. But the output <code>No resources found in database namespace</code> indicates that there are currently no pods deployed in the "database" namespace.</p>
<h2 id="heading-how-to-create-resources-with-yaml">How to Create Resources with YAML</h2>
<p>Let's explore creating resources with YAML to provision our PostgreSQL database running in an Azure Kubernetes cluster. But first, what exactly is YAML?</p>
<p>Kubernetes <a target="_blank" href="https://www.redhat.com/en/topics/automation/what-is-yaml"><strong>YAML</strong></a> is a configuration file written in YAML (YAML Ain't Markup Language). They define how Kubernetes resources like pods, deployments, and services should be set up within a cluster. These files are easy to read and specify details like resource names, types, specifications, labels, and annotations. They're crucial for deploying applications and infrastructure on Kubernetes clusters.</p>
<p>YAML is what you will use to create Kubernetes resources that will run Postgres.</p>
<p>First, you need to <a target="_blank" href="https://github.com/ayowilfred95/Azure-k8s-postgres.git">clone this GitHub repository</a>. Inside, you'll find a Node.js Express application and a YAML file. The Node.js app allows users to register with their email, password, and full name, and also enables them to log in by verifying their details in the database. If their details are found, it displays a success message.</p>
<h3 id="heading-clone-the-repository">Clone the repository</h3>
<p>Create a new folder on your computer and then clone this <a target="_blank" href="https://github.com/ayowilfred95/Azure-k8s-postgres.git">repository</a> into it.</p>
<p>Open your terminal or PowerShell, go to the folder you want, and use the command below to clone the repository into your computer in that location.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/ayowilfred95/Azure-k8s-postgres.git
</code></pre>
<h3 id="heading-open-the-cloned-repository-in-any-text-editor">Open the cloned repository in any text editor</h3>
<p>I'm using Visual Studio Code, but feel free to use any text editor you prefer. Here's the structure of the project:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-04.15.29.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Project folder structure</em></p>
<h3 id="heading-install-project-dependencies">Install project dependencies</h3>
<p>Open the terminal in VS Code and go to the main directory of the project. Next, execute the command <code>npm install</code> to install all the required packages and dependencies for the project:</p>
<pre><code class="lang-bash">npm install
</code></pre>
<p>Since the backend application is a Node.js Express app, you use npm to install dependencies (similar to how we use <code>maven clean install</code> in Java).</p>
<p>After the dependencies are installed, open the file named "postgres.yaml". It holds all the YAML configurations required to set up your PostgreSQL database that will run in the Kubernetes cluster.</p>
<h2 id="heading-yaml-configuration">YAML Configuration</h2>
<p>In the postgres.yaml file, there are five configurations separated by ---. It's important to use this "---" symbol when declaring different types of Kubernetes resources. If you forget to do this, you'll encounter an error.</p>
<h3 id="heading-storageclass">StorageClass</h3>
<p>The first one is the <code>StorageClass</code>. This YAML configuration defines a StorageClass in Kubernetes for managing storage resources.</p>
<pre><code class="lang-bash">kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: azuredisk-premium-retain
provisioner: kubernetes.io/azure-disk
reclaimPolicy: Retain   <span class="hljs-comment"># Retain or Delete</span>
volumeBindingMode: WaitForFirstConsumer   <span class="hljs-comment"># WaitForFirstConsumer or Immediate</span>
allowVolumeExpansion: <span class="hljs-literal">true</span>    <span class="hljs-comment"># true or false</span>
parameters:
  storageaccounttype: Premium_LRS   <span class="hljs-comment"># Premium or Standard</span>
  kind: Managed
</code></pre>
<p>Let's break down what each part means:</p>
<ul>
<li><p><code>kind: StorageClass</code>: Indicates the type of Kubernetes resource being defined, which is a <code>StorageClass</code>. A <code>StorageClass</code> defines the class of storage offered by a cluster.</p>
</li>
<li><p><code>apiVersion: storage.k8s.io/v1</code>: Specifies the Kubernetes API version being used for this resource.</p>
</li>
<li><p><code>metadata: name: azuredisk-premium-retain</code>: Provides metadata for the <code>StorageClass</code>, including its name, which in this case is "azuredisk-premium-retain".</p>
</li>
<li><p><code>provisioner: kubernetes.io/azure-disk</code>: Specifies the provisioner responsible for provisioning storage. In this case, it's "kubernetes.io/azure-disk", indicating that Azure Disk will be used as the storage provisioner.</p>
</li>
<li><p><code>reclaimPolicy: Retain</code>: Defines the reclaim policy for the storage resources. It specifies what action should be taken when the associated persistent volume is released. Here, it's set to "Retain", meaning the volume is retained even after it's no longer used by a pod.</p>
</li>
<li><p><code>volumeBindingMode: WaitForFirstConsumer</code>: Specifies the volume binding mode, which determines when volume binding should occur. In this case, it's set to "WaitForFirstConsumer", meaning the volume will be bound when the first pod using it is created.</p>
</li>
<li><p><code>allowVolumeExpansion: true</code>: Indicates whether volume expansion is allowed. Setting it to "true" means that the size of the volume can be increased if needed.</p>
</li>
<li><p><code>parameters</code>: Contains additional parameters specific to the provisioner. Here, it specifies the storage account type as "Premium_LRS" and the kind of storage as "Managed".</p>
</li>
</ul>
<p>Overall, this configuration sets up a <code>StorageClass</code> named "azuredisk-premium-retain" using Azure Disk as the provisioner, with specific policies and parameters tailored for Azure storage.</p>
<h3 id="heading-persistentvolumeclaim">PersistentVolumeClaim</h3>
<p>The second configuration in the postgres.yaml file is the <strong>persistent volume claim</strong>.</p>
<p>This YAML configuration defines a <code>PersistentVolumeClaim</code> (PVC) in Kubernetes, which is used to request storage resources.</p>
<pre><code class="lang-bash">apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: azure-managed-disk-pvc
spec:
  accessModes:
  - ReadWriteOnce   <span class="hljs-comment"># ReadWriteOnce, ReadOnlyMany or ReadWriteMany</span>
  storageClassName: azuredisk-premium-retain
  resources:
    requests:
      storage: 4Gi
</code></pre>
<p>Let's break down what each part means:</p>
<ul>
<li><p><code>apiVersion: v1</code>: Specifies the Kubernetes API version being used for this resource.</p>
</li>
<li><p><code>kind: PersistentVolumeClaim</code>: Indicates the type of Kubernetes resource being defined, which is a PersistentVolumeClaim. A PVC is used by pods to request storage resources.</p>
</li>
<li><p><code>metadata: name: azure-managed-disk-pvc</code>: Provides metadata for the PersistentVolumeClaim, including its name, which is "azure-managed-disk-pvc".</p>
</li>
<li><p><code>spec</code>: Describes the desired state of the PersistentVolumeClaim.</p>
</li>
<li><p><code>accessModes: - ReadWriteOnce</code>: Specifies the access mode for the volume. Here, it's set to "ReadWriteOnce", meaning the volume can be mounted as read-write by a single node at a time.</p>
</li>
<li><p><code>storageClassName: azuredisk-premium-retain</code>: Specifies the <code>StorageClass</code> to use for provisioning the volume. This PVC will use the <code>StorageClass</code> named "azuredisk-premium-retain" defined previously.</p>
</li>
<li><p><code>resources: requests: storage: 4Gi</code>: Specifies the desired storage capacity for the volume. Here, it requests 4 gigabytes (Gi) of storage.</p>
</li>
</ul>
<p>Overall, this configuration sets up a <code>PersistentVolumeClaim</code> named "azure-managed-disk-pvc" requesting storage resources with specific access modes, storage class, and storage capacity.</p>
<h3 id="heading-configmap">ConfigMap</h3>
<p>The third configuration in the postgres.yaml file is the <strong>config map</strong>. This YAML configuration defines a ConfigMap in Kubernetes, which is used to store configuration data in key-value pairs.</p>
<pre><code class="lang-bash">apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-config
  labels:
    app: postgres
data:
  POSTGRES_DB: freecodecamp
  POSTGRES_USER: freecodecamp1
  POSTGRES_PASSWORD: freecodecamp@
  PGDATA: /var/lib/postgresql/data/pgdata
</code></pre>
<p>Let's break down what each part means:</p>
<ul>
<li><p><code>apiVersion: v1</code>: Specifies the Kubernetes API version being used for this resource.</p>
</li>
<li><p><code>kind: ConfigMap</code>: Indicates the type of Kubernetes resource being defined, which is a <code>ConfigMap</code>. A <code>ConfigMap</code> is used to store non-confidential data in key-value pairs.</p>
</li>
<li><p><code>metadata: name: postgres-config</code>: Provides metadata for the <code>ConfigMap</code>, including its name, which is "postgres-config".</p>
</li>
<li><p><code>labels: app: postgres</code>: Labels are key-value pairs used to organize and select resources. Here, a label "app" with the value "postgres" is applied to the <code>ConfigMap</code>.</p>
</li>
<li><p><code>data</code>: Contains the key-value pairs of configuration data.</p>
</li>
<li><p><code>POSTGRES_DB: pisonitsha</code>: Specifies the name of the PostgreSQL database as "pisonitsha".</p>
</li>
<li><p><code>POSTGRES_USER: pisonitsha1</code>: Specifies the username for accessing the PostgreSQL database as "pisonitsha1".</p>
</li>
<li><p><code>POSTGRES_PASSWORD: pisonitsha@</code>: Specifies the password for accessing the PostgreSQL database as "pisonitsha@".</p>
</li>
<li><p><code>PGDATA: /var/lib/postgresql/data/pgdata</code>: Specifies the location of PostgreSQL data directory as "/var/lib/postgresql/data/pgdata".</p>
</li>
</ul>
<p>Overall, this configuration sets up a ConfigMap named "postgres-config" containing key-value pairs of configuration data, such as database name, username, password, and data directory location, which can be used by other Kubernetes resources.</p>
<p><strong>Note:</strong> It's recommended to avoid hardcoding secret variables such as <code>POSTGRES_DB</code>, <code>POSTGRES_PASSWORD</code>,<code>PGDATA</code> and instead store them in secret files, for the sake of simplicity in this tutorial, we'll keep them hardcoded.</p>
<h3 id="heading-statefulset">StatefulSet</h3>
<p>The fourth configuration is the <strong>stateful set</strong>.This YAML configuration defines a <code>StatefulSet</code> in Kubernetes, which is used to manage stateful applications like databases.</p>
<pre><code class="lang-bash">apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres
  selector:
    matchLabels:
      app: postgres
  replicas: 1
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:10.4
          imagePullPolicy: <span class="hljs-string">"IfNotPresent"</span>
          ports:
          - containerPort: 5432
          envFrom:
          - configMapRef:
              name: postgres-config
          volumeMounts:
          - name: azure-managed-disk-pvc
            mountPath: /var/lib/postgresql/data
      volumes:
      - name: azure-managed-disk-pvc
        persistentVolumeClaim:
          claimName: azure-managed-disk-pvc
    ```

Let<span class="hljs-string">'s break down what each part means:

* `apiVersion: apps/v1`: Specifies the Kubernetes API version being used for this resource.
* `kind: StatefulSet`: Indicates the type of Kubernetes resource being defined, which is a `StatefulSet`. `StatefulSets` are used to manage stateful applications by providing unique **identities** and stable **network** identities to each pod.
* `metadata: name: postgres`: Provides metadata for the `StatefulSet`, including its name, which is "postgres".
* `spec`: Describes the desired state of the `StatefulSet`.
* `serviceName: postgres`: Specifies the name of the Kubernetes service that will be used to access the `StatefulSet` pods.
* `selector: matchLabels: app: postgres`: Selects the pods controlled by this `StatefulSet` based on the label "app: postgres".
* `replicas: 1`: Specifies the desired number of replicas (instances) of the StatefulSet, which is 1 in this case.
* `template`: Defines the pod template used to create pods managed by the `StatefulSet`.
* `metadata: labels: app: postgres`: Labels applied to the pods created from this template.
* `spec`: Describes the specification of the containers within the pod.
* `containers`: Specifies the containers running in the pod.
* `name: postgres`: Defines the name of the container as "postgres".
* `image: postgres:10.4`: Specifies the Docker image used for the container, which is "postgres:10.4".
* `imagePullPolicy: "IfNotPresent"`: Specifies the policy for pulling the container image, which is "IfNotPresent", meaning it will only pull the image if it'</span>s not already present on the node.
* `ports: containerPort: 5432`: Specifies the port that the PostgreSQL service inside the container is listening on.
* `envFrom: configMapRef: name: postgres-config`: Injects environment variables from a ConfigMap named <span class="hljs-string">"**postgres-config**"</span> that you defined earlier.
* `volumeMounts: name: azure-managed-disk-pvc mountPath: /var/lib/postgresql/data`: Mounts a persistent volume claim named <span class="hljs-string">"azure-managed-disk-pvc"</span> to the container at the specified path.
* `volumes: name: azure-managed-disk-pvc persistentVolumeClaim: claimName: azure-managed-disk-pvc`: Defines the persistent volume claim named <span class="hljs-string">"azure-managed-disk-pvc"</span> to be used by the pod.

Overall, this configuration sets up a StatefulSet named <span class="hljs-string">"postgres"</span> with one replica, running a PostgreSQL container with specific settings and mounted persistent storage.

<span class="hljs-comment">### Service</span>

The fifth configuration is the **service**. This YAML configuration defines a **Service** <span class="hljs-keyword">in</span> Kubernetes, <span class="hljs-built_in">which</span> is used to expose the `StatefulSet` we declared earlier as a network service.

```bash
apiVersion: v1
kind: Service
metadata:
  name: postgres
  labels:
    app: postgres
spec:
  <span class="hljs-built_in">type</span>: LoadBalancer
  selector:
    app: postgres
  ports:
    - protocol: TCP
      name: https
      port: 5432
      targetPort: 5432
</code></pre>
<p>Let's break down what each part means:</p>
<ul>
<li><p><code>apiVersion: v1</code>: Specifies the Kubernetes API version being used for this resource.</p>
</li>
<li><p><code>kind: Service</code>: Indicates the type of Kubernetes resource being defined, which is a Service. <strong>Services</strong> allow pods to be accessed by other pods or external users.</p>
</li>
<li><p><code>metadata: name: postgres</code>: Provides metadata for the Service, including its name, which is "postgres".</p>
</li>
<li><p><code>labels: app: postgres</code>: Labels are key-value pairs used to organize and select resources. Here, a label "app" with the value "postgres" is applied to the Service.</p>
</li>
<li><p><code>spec</code>: Describes the desired state of the Service.</p>
</li>
<li><p><code>type: LoadBalancer</code>: Specifies the type of Service, which is "LoadBalancer". This type allows the <strong>Service</strong> to be exposed externally with a cloud provider's load balancer.</p>
</li>
<li><p><code>selector: app: postgres</code>: Selects the pods controlled by the Service based on the label "app: postgres".</p>
</li>
<li><p><code>ports</code>: Specifies the ports that the Service will listen on.</p>
</li>
<li><p><code>protocol: TCP</code>: Specifies the protocol used for the port, which is TCP.</p>
</li>
<li><p><code>name:https</code> : Specifies a name for the port, which is "https".</p>
</li>
<li><p><code>port: 5432</code>: Specifies the port number on which the Service will listen, which is 5432.</p>
</li>
<li><p><code>targetPort: 5432</code>: Specifies the target port on the pods to which traffic will be forwarded, which is also 5432. This means that traffic received on port 5432 of the Service will be forwarded to port 5432 on the pods.</p>
</li>
</ul>
<p>Overall, this configuration sets up a Service named "postgres" with a LoadBalancer type, forwarding traffic on port 5432 to pods labeled with "app: postgres".</p>
<h2 id="heading-how-to-deploy-yaml-resource-to-azure-kubernetes-service-aks">How to Deploy YAML Resource to Azure Kubernetes Service (AKS)</h2>
<p>You've previously connected "kubectl" with the Azure Kubernetes Service (AKS) you set up. Let's double-check it.</p>
<p>In your VS Code terminal, rerun the command <code>kubectl get nodes</code>. You'll see an output like this, though your node's value will be different.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/Screenshot-2024-05-06-at-05.49.43.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Displaying node information running in Azure Kubernetes cluster</em></p>
<p>Next, verify the namespace you previously created by executing the command: <code>kubectl get namespace database</code>. Your output should resemble this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-05.49.12.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Retrieving Namespace Information</em></p>
<h3 id="heading-deploy-the-yaml-resource">Deploy the YAML resource</h3>
<p>Once you've confirmed everything is set, you can deploy the YAML resource. This will establish your PostgreSQL database in the Azure Kubernetes cluster you've configured.</p>
<p>Run the below command in the main directory where the configuration file is located. Currently, I'm in the project's root directory (azure-k8s-postgres). To deploy the database, just execute this command below:</p>
<pre><code class="lang-bash">kubectl apply -n database -f postgres.yaml
</code></pre>
<p>Your output should look like this. This output confirms that all these components have been successfully created in Kubernetes.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-05.57.52.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Applying Configuration to Namespace</em></p>
<p>Execute the command below to verify that the pod is running:</p>
<pre><code class="lang-bash">kubectl get pods -n database
</code></pre>
<p>Your output should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-06.01.33.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Fetching Pods in Namespace</em></p>
<p>This output confirms that a pod name "postgres-0" is running in your Azure Kubernetes Cluster. But it was not the only pod you created. As I said earlier, to connect to a pod, you need what is called service. And you have declared a service resource in our configuration file which has also been deployed into your Kubernetes.</p>
<p>To get the status of the service, run this command:</p>
<pre><code class="lang-bash">kubectl get services -n database
</code></pre>
<p>Your output should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-06.07.12.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Retrieving Services in Namespace</em></p>
<p>This output displays the services in the "database" namespace, including a service named "postgres" with the type "LoadBalancer," its internal cluster IP, external IP, and port mappings. You'll utilize the external IP along with the Postgres port "5432" to connect your database with the Node.js application. Note that your external IP will differ from mine.</p>
<h2 id="heading-nodejs-application">Node.js Application</h2>
<p>In this section, I'll guide you through setting up your Node.js app to connect to a PostgreSQL database in your Azure Kubernetes Service.</p>
<p>We'll cover sending data into the database and retrieving it using Postman. Also, I'll demonstrate how to check if the data remains in the database even if the pod running PostgreSQL in the cluster is deleted.</p>
<h3 id="heading-configure-your-nodejs-application">Configure your Node.js application</h3>
<p>Go to the database folder and open the database.js file. Replace the host with your EXTERNAL-IP obtained from the service, and leave the rest unchanged since you've already defined those variables in your config map.</p>
<p>Your database.js file should resemble the CodeSnap below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/code.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>CodeSnap of database.js Configuration</em></p>
<h3 id="heading-run-your-nodejs-application">Run your Node.js application</h3>
<p>In your VS Code terminal, execute this command to start the Node.js application locally:</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>Your output should look like this if the connection is established successfully.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-06.27.25.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Server Listening on Port 4000</em></p>
<p>If your output looks the same as mine, it indicates that you've successfully connected your Node.js application to the PostgreSQL database running in your Azure Kubernetes cluster. Congratulations! 🎉</p>
<h3 id="heading-test-the-application">Test the application</h3>
<p>Testing is a fundamental principle in DevOps operations. It helps us understand the state of the application we've built before releasing it to users. Any application that doesn't pass the testing stage will not be deployed. This is a rule in DevOps.</p>
<p>For this tutorial, you'll be using Postman. You can download Postman <a target="_blank" href="https://www.postman.com/downloads/">here</a>. Postman enables you to test API endpoints by receiving status responses.</p>
<p>Check out this <a target="_blank" href="https://qalified.com/blog/postman-for-api-testing/">post</a> on how to use Postman to test APIs. If you want to learn more, <a target="_blank" href="https://www.freecodecamp.org/news/learn-how-to-use-postman-to-test-apis/">here's a full course</a> on the subject.</p>
<h3 id="heading-open-your-postman-application">Open your Postman application</h3>
<p>To begin using Postman, start by creating a new API request in your preferred workspace. Choose POST. POST requests add new data to the database or server. Then, paste the endpoint URL (localhost:4000/api/v1/admin/register) for your Postman test.</p>
<p>The below screenshot illustrates how you will create a POST request.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-15.32.32.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Postman URL Endpoint Configuration</em></p>
<p>In the body, paste the JSON data shown below inside it as shown below:</p>
<pre><code class="lang-bash">{   
    <span class="hljs-string">"fullName"</span>:<span class="hljs-string">"Azure postgres freecodecamp"</span>,
    <span class="hljs-string">"email"</span>:<span class="hljs-string">"freecodecamp@gmail.com"</span>,
    <span class="hljs-string">"password"</span>:<span class="hljs-string">"freecodecamp"</span>
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-15.34.58-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Postman Request Body</em></p>
<p>Once you've set up the request, just click the "Send" button to send it. Postman will then show you status codes, and the response payload as shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-06.56.39.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Postman API Response</em></p>
<h3 id="heading-confirm-the-data">Confirm the data</h3>
<p>To confirm that the data you sent into the database exists, make a GET request to this endpoint URL: localhost:4000/api/v1/admin/freecodecamp@gmail.com</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-15.45.41.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Postman GET Request URL Endpoint</em></p>
<p>When you click send, Postman will then show you status codes and the response payload as shown below. Notice that we didn't put anything in the body because this is a GET request.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-15.48.29.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Postman GET Request by Email Retrieval Response</em></p>
<h3 id="heading-delete-the-pod-to-confirm-data-persistence">Delete the pod to confirm data persistence</h3>
<p>We chose to create our PostgreSQL database using a <code>StatefulSet</code> to ensure that data persists even if the pod is destroyed. Let's test this by deleting the pod and checking if the data remains intact.</p>
<p>In your VS Code terminal, execute the command: <code>kubectl delete pod -n database postgres-0</code>.</p>
<p>This command deletes a pod named "postgres-0" in the "database" namespace from your Kubernetes cluster. Your output should look like this.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-07.09.41.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Deleting Pod in Namespace:</em></p>
<h3 id="heading-pod-recreation">Pod recreation</h3>
<p>Kubernetes has a built-in feature called replication controllers or replica sets that ensure a specified number of pod replicas are running at any given time. If a pod is deleted, Kubernetes will automatically recreate it to maintain the desired number of replicas, ensuring high availability</p>
<p>If you run <code>kubectl get pods -n database</code>, you'll notice that Kubernetes has created a new pod with the same name, "postgres-0", to replace the one that was deleted. This ensures that the application remains available and continues to function as expected.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-07.10.04.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Pod Recreated back in Namespace</em></p>
<h3 id="heading-data-persistence">Data persistence</h3>
<p>Navigate back to Postman and make a GET request to the endpoint URL localhost:4000/api/v1/admin/freecodecamp@gmail.com.</p>
<p>You should get the same response as before. So under the hood, when we delete the pod, the storage disk was not deleted. The storage disk is inside the Azure disk. How do we know that? If you run this command:</p>
<pre><code class="lang-bash">kubectl get pvc -n database
</code></pre>
<p>you should get this output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-16.04.48-3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Persistennce Volume Claim details in namespace</em></p>
<p>This shows details about a storage called "azure-managed-disk-pvc" in your Kubernetes. It's currently in use and has 4 gigabytes of space available. It's set up to be read and written to by one system at a time. This storage is provided by a service called "azuredisk-premium-retain" that we configured earlier.</p>
<h3 id="heading-clean-up-resources">Clean up resources</h3>
<p>In this tutorial, you created Azure resources in a resource group. If you won't need these resources later, delete the resource group from the Azure portal or run the following command in your terminal:</p>
<pre><code class="lang-bash">az group delete --name AZURE-POSTGRES-RG --yes
</code></pre>
<p>This command might take a minute to run.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We've gone on quite a journey here! You've learned how to deploy a Postgres container in Azure Kubernetes Service (AKS) and integrate it with a Node.js application.</p>
<p>In this tutorial, I guided you through the process of configuring Kubernetes using Azure Kubernetes Service (AKS). You learned to customize YAML files utilizing StatefulSet, Persistent Volume, and Services to deploy a PostgreSQL database on Azure Kubernetes. You also acquired PostgreSQL database credentials running within AKS to establish connectivity with a Node.js application. I then provided detailed instructions on connecting your Node.js Express app to the Postgres container within the AKS cluster.</p>
<p>Thank you for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Debug Node.js Applications Using the debugger; Statement ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you will learn the easiest and most efficient way to debug Node.js application code. So let's get started. Want to watch the video version of this tutorial? You can check out the video below: https://www.youtube.com/watch?v=B_oPWQ9W... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-debug-node-js-applications/</link>
                <guid isPermaLink="false">66bc551360ad5c1520c166e8</guid>
                
                    <category>
                        <![CDATA[ debugging ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Yogesh Chavan ]]>
                </dc:creator>
                <pubDate>Mon, 22 Apr 2024 19:50:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/debug_node_js_code_thumbnail-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you will learn the easiest and most efficient way to debug Node.js application code.</p>
<p>So let's get started.</p>
<p>Want to watch the video version of this tutorial? You can check out the video below:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/B_oPWQ9Wyew" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-table-of-contents">Table Of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-how-you-usually-debug-nodejs-applications">How You Usually Debug Node.js Applications</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-a-debugger-to-debug-your-code">How to Add a Debugger to Debug Your Code</a></li>
<li><a class="post-section-overview" href="#heading-how-to-run-the-application-for-debugging">How to Run the Application for Debugging</a></li>
<li><a class="post-section-overview" href="#heading-how-to-access-variables-during-debugging">How to Access Variables During Debugging</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-script-to-debug-nodejs-apps">How to Create a Script to Debug Node.js Apps</a></li>
<li><a class="post-section-overview" href="#heading-quick-recap">Quick Recap</a></li>
</ul>
<h2 id="heading-how-you-usually-debug-nodejs-applications"><strong>How You Usually Debug Node.js Applications</strong></h2>
<p>If you want to debug a Node.js application, usually you add a <code>console.log</code> statement in the code that you want to debug to find out the value of any variable.</p>
<p>This works, but you need to keep checking the console log to see the value that you're trying to print.</p>
<p>And if the data printed in the console contains nested objects or if it's a lot of data, then using <code>console.log</code> is not feasible.</p>
<p>Fortunately, there's a better way.</p>
<h2 id="heading-how-to-add-a-debugger-to-debug-your-code"><strong>How to Add a Debugger to Debug Your Code</strong></h2>
<p>Instead, you can add a <code>debugger;</code> statement in the code that you want to debug.</p>
<p>So let's say you have an Express.js API route for registering a user as shown in the below code:</p>
<pre><code class="lang-js"><span class="hljs-comment">// controllers/auth.js</span>

<span class="hljs-keyword">const</span> register = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { email, password } = req.body;
    <span class="hljs-keyword">const</span> existingUser = <span class="hljs-keyword">await</span> User.findOne({
      email,
    });
    <span class="hljs-keyword">if</span> (existingUser) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'User with the provided email already exist'</span>);
    }
    <span class="hljs-comment">// some more code</span>
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">201</span>).send();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
    <span class="hljs-keyword">return</span> res
      .status(<span class="hljs-number">500</span>)
      .send(<span class="hljs-string">'Error while registering a new user. Try again later.'</span>);
  }
};

<span class="hljs-built_in">module</span>.exports = { register };

<span class="hljs-comment">// routes/auth.js</span>
<span class="hljs-keyword">const</span> { register } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../controllers/auth'</span>);

<span class="hljs-keyword">const</span> Router = express.Router();

Router.post(<span class="hljs-string">'/api/register'</span>, register);
</code></pre>
<p>And there's some issue while registering a user, so you want to debug the <code>register</code> function's code.</p>
<p>In that case, you can just add a <code>debugger;</code> statement inside the <code>register</code> function code like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> register = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { email, password } = req.body;
    <span class="hljs-keyword">debugger</span>;
    <span class="hljs-keyword">const</span> existingUser = <span class="hljs-keyword">await</span> User.findOne({
      email,
    });
    <span class="hljs-keyword">if</span> (existingUser) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'User with the provided email already exist'</span>);
    }
    <span class="hljs-comment">// some more code</span>
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">201</span>).send();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
    <span class="hljs-keyword">return</span> res
      .status(<span class="hljs-number">500</span>)
      .send(<span class="hljs-string">'Error while registering a new user. Try again later.'</span>);
  }
};
</code></pre>
<h2 id="heading-how-to-run-the-application-for-debugging"><strong>How to Run the Application for Debugging</strong></h2>
<p>Normally, you start your Node.js application by executing the following command:</p>
<pre><code class="lang-javascript">node index.js
</code></pre>
<p>But instead, you can execute the following command:</p>
<pre><code class="lang-javascript">node inspect index.js
</code></pre>
<p>Here, we just added an <code>inspect</code> keyword in between.</p>
<p>If your main application file's name is <code>server.js</code>, you can execute the <code>node inspect server.js</code> command.</p>
<p>Once you execute the above command, you will see the output displayed as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/1_debugger_output.png" alt="Image" width="600" height="400" loading="lazy">
<em>Debugger Attached</em></p>
<p>As you can see from the output, the debugger is attached, so now you can start debugging the code.</p>
<p>To do that, open the Chrome browser and enter <code>chrome://inspect</code> in the browser URL.</p>
<p>You will see the output as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/2_chrome_inspect.png" alt="Image" width="600" height="400" loading="lazy">
<em>Chrome Inspect Page</em></p>
<p>Since you executed the <code>node inspect index.js</code> command to start inspecting, you can see a new target entry displayed under the <code>Remote Target</code> section.</p>
<p>Now, if you click on the displayed blue <code>inspect</code> link, then you will see a new browser dev tool opened as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/3_debugger_started.png" alt="Image" width="600" height="400" loading="lazy">
<em>Debugger Paused</em></p>
<p>As you can see in the right panel in the above image, the <code>Debugger paused</code> message is displayed. The debugging control is at the first line of code, as you can see from the highlighted yellow line.</p>
<p>But you don't want to start debugging from the first line of code. Instead, you want to just debug the registration code. To do this, click on the blue triangle icon which is displayed just above the <code>Debugger paused</code> message as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/4_debugging_stopped.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Continuing Debugging</em></p>
<p>Now don't close this window – instead, try registering a user from the application or making an API call using Postman, so the <code>/register</code> route handler code that we added previously will be executed.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/5_registering_user.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Registering User &amp; Debugging Code</em></p>
<p>As you can see above, when you click on create new account button, you're automatically redirected to the code where you added the <code>debugger;</code> statement.</p>
<p>Now, you can debug the code line by line and see the values of each variable during debugging to find out and fix the issue.</p>
<h2 id="heading-how-to-access-variables-during-debugging"><strong>How to Access Variables During Debugging</strong></h2>
<p>Sometimes when you mouse over any variable while debugging to see its actual value, the value might be too long (because it might be an object with many properties), so you can't see it easily by mousing over it.</p>
<p>In that case, while the debugger is still active, you can open the console tab and type the name of the variable whose value you want to see – as you can see in the below Gif:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/6_logging_variables_in_console.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Logging Variables In The Console</em></p>
<p>So that's how you can easily debug any of your Node.js application's code.</p>
<h2 id="heading-how-to-create-a-script-to-debug-nodejs-apps"><strong>How to Create a Script to Debug Node.js Apps</strong></h2>
<p>If you don't want to manually type the <code>node inspect index.js</code> command every time in the terminal, you can create a new <code>debug</code> script inside the <code>package.json</code> file like this:</p>
<pre><code class="lang-js"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"node index.js"</span>,
    <span class="hljs-string">"debug"</span>: <span class="hljs-string">"node inspect index.js"</span>,
    <span class="hljs-string">"dev"</span>: <span class="hljs-string">"nodemon index.js"</span>
},
</code></pre>
<p>So now, you can execute the <code>npm run debug</code> command to start your application in debug mode.</p>
<h2 id="heading-quick-recap"><strong>Quick Recap</strong></h2>
<p>To debug a Node.js application, you need to follow the below steps:</p>
<ul>
<li>Add a <code>debugger</code> statement inside the code that you want to debug.</li>
<li>Run the <code>node inspect index.js</code> or <code>node inspect server.js</code> command to start the application in debug mode.</li>
<li>Access the URL <code>chrome://inspect</code> in your Chrome browser.</li>
<li>Click on the <code>inspect</code> link under the <code>Remote Target</code> section.</li>
<li>Click on the blue triangle icon to skip debugging if you don't want to start debugging your application from the first line of the <code>index.js</code> or <code>server.js</code> file.</li>
<li>Make an API call or do something that will trigger the code where you added the <code>debugger;</code> statement. This way you can debug the code line by line and find out the issue.</li>
</ul>
<h2 id="heading-thanks-for-reading"><strong>Thanks for Reading</strong></h2>
<p>That's it for this tutorial. I hope you learned something new.</p>
<p>Want to watch the video version of this tutorial? You can check out <a target="_blank" href="https://www.youtube.com/watch?v=B_oPWQ9Wyew">this video.</a></p>
<p>If you want to master JavaScript, ES6+, React, and Node.js with easy-to-understand content, check out my <a target="_blank" href="https://www.youtube.com/@codingmastery_dev/">YouTube channel</a>. Don't forget to subscribe.</p>
<p>Want to stay up to date with regular content on JavaScript, React, and Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/">Follow me on LinkedIn</a>.</p>
<p><a href="https://www.youtube.com/watch?v=wcjCsMRZKxs" target="_blank"><img src="https://d31ezp3r8jwmks.cloudfront.net/7g60tc6qngrs80np7v12vana6w1s" alt="Learn How To Build Full Stack Link Sharing App Using MERN Stack" width="1600" height="900" loading="lazy"></a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Hash Passwords with bcrypt in Node.js ]]>
                </title>
                <description>
                    <![CDATA[ By Dennis Temoye Charity Security is critical in the field of web development, particularly when dealing with user credentials such as passwords. One security procedure that's critical in web development is password hashing.  Password hashing guarant... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-hash-passwords-with-bcrypt-in-nodejs/</link>
                <guid isPermaLink="false">66d45e01d14641365a05089a</guid>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 03 Apr 2024 22:01:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/How-to-Hash-Password-With-Bcrypt-In-Nodejs.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dennis Temoye Charity</p>
<p>Security is critical in the field of web development, particularly when dealing with user credentials such as passwords. One security procedure that's critical in web development is password hashing. </p>
<p>Password hashing guarantees that plaintext passwords are difficult for attackers to find, even in a situation where a database is compromised. But not all hashing methods are created equal, and this is where bcrypt stands out.</p>
<p>Node.js, a popular framework for developing web applications, provides a robust ecosystem for constructing secure authentication systems. In this article, we'll look at using bcrypt in Node.js to hash passwords. We'll look at how bcrypt may be smoothly incorporated into Node.js applications to improve security and safeguard user credentials effectively.</p>
<p>Whether you're an experienced Node.js developer looking to strengthen your authentication practices or a beginner looking to learn the best techniques for secure password management, this article will be helpful to you. Let's have a look at how you can use bcrypt to hash passwords in Node.js.</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-hashing">What is Hashing?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-bcrypt">What is Bcrypt?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-install-bcrypt-in-nodejs">How to Install Bcrypt in Nodejs</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-bcrypt-in-nodejs">How to Set Up Bcrypt in Node.js</a></li>
<li><a class="post-section-overview" href="#heading-how-to-hash-passwords-with-bcrypt">How to Hash Passwords With Bcrypt</a></li>
<li><a class="post-section-overview" href="#heading-how-to-verify-passwords-with-bcrypt">How to Verify Passwords With Bcryp</a>t</li>
<li><a class="post-section-overview" href="#heading-security-best-practices-with-bcrypt">Security Best Practices with Bcrypt</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-what-is-hashing">What is Hashing?</h2>
<p>Hashing involves converting a given key or string of characters into another value. This is typically represented by a shorter, fixed-length value or key that represents the original value and facilitates the retrieval.</p>
<h3 id="heading-what-is-password-hashing">What is Password Hashing?</h3>
<p>Password Hashing is a process of converting an input password into a fixed-length string of characters, typically for the purpose of securely storing and transmitting the password. </p>
<p>Password hash functions are designed to be one-way functions. This means it should not be computationally possible to reverse the process and get the original input password from the hashed value.</p>
<p>For example, suppose we want to hash a password like "password123". The password will be transformed into a fixed-length character string using a hash algorithm like bcrypt. And we'll get a hashed result once the hash function has processed our password. </p>
<p>The hashed output of "password123" using bcrypt, for instance, would look like this:</p>
<pre><code>e234dsdom3k2kmdl3l43iwes9vjro44223m3n32kn5n2ksdo4
</code></pre><p>Now that you understand the basics of how password hashing works, it's time to dive deeper into the practical application of hashing a password using the bcrypt algorithm. </p>
<p>But before we proceed with that, let's learn a bit more about bcrypt so you understand its workings and installation process, as well as how to integrate it into a Node.js project.</p>
<p>Firstly, let's gain insight into bcrypt – what it is, how it operates, and its significance in password security. Then we'll discuss how to install bcrypt and integrate it seamlessly within a Node.js environment. This will include a detailed walkthrough on setting up bcrypt within your project and leveraging its functionalities effectively.</p>
<p>By the end of this article, you'll have a comprehensive understanding of bcrypt, equipped with the knowledge to securely hash passwords in your Node.js applications. So, let's embark on this journey to enhance the security of our projects through bcrypt integration.</p>
<h2 id="heading-what-is-bcrypt">What is bcrypt?</h2>
<p>bcrypt is a type of cryptographic algorithm used to securely store passwords. It scrambles a user's password into a unique code. This way, even if a thief takes the database, they won't be able to recover the original passwords readily.</p>
<h3 id="heading-how-does-bcrypt-work">How Does bcrypt Work?</h3>
<p>bcrypt works by combining hashing and a technique known as salting, which is specifically developed to make stored passwords more safe. </p>
<p>Here's a breakdown of the procedure:</p>
<ol>
<li><strong>Hashing:</strong> Bcrypt processes a user's password using a sophisticated mathematical function. This function converts the password to a fixed-length string of characters that appear random and meaningless. The hashed value is what is kept in the database, not the original password. Because the hashing function is one-way, reversing the hash will not produce the original password.</li>
<li><strong>Salting:</strong> To improve security, bcrypt incorporates a random number called a salt. This salt is unique to each password and is attached to it before hashing. The combined value (password + salt) is then passed to the hashing function.</li>
</ol>
<h2 id="heading-how-to-install-bcrypt-in-nodejs">How to Install Bcrypt in Nodejs</h2>
<p>Before you install bcrypt, you'll need to have a Node.js project already set up. If you haven't created one yet, follow these steps to create a new Node.js project:</p>
<h3 id="heading-create-a-directory">Create a directory:</h3>
<p>This command creates a new directory (folder) where your Node.js project will reside. It's named <code>bcrypt-password-hash</code>.</p>
<pre><code>mkdir bcrypt-password-hash
</code></pre><ul>
<li><code>mkdir</code>: This command stands for "make directory." It's used to create a new directory.</li>
<li><code>bcrypt-password-hash</code>: This is the name of the directory you're creating. You can choose any name you prefer for your project directory.</li>
</ul>
<h3 id="heading-change-into-the-newly-created-directory">Change into the newly created directory:</h3>
<p>This command navigates you into the newly created directory so that you can start working on your project within it.</p>
<pre><code>cd bcrypt-password-hash
</code></pre><ul>
<li><code>cd</code>: This command stands for "change directory." It's used to move from one directory to another.</li>
<li><code>bcrypt-password-hash</code>: This is the name of the directory you want to navigate into.</li>
</ul>
<h3 id="heading-initialize-a-new-nodejs-project">Initialize a new Node.js project:</h3>
<p>This command initializes a new Node.js project within the directory you created. It creates a <code>package.json</code> file, which is used to manage dependencies and configuration for your Node.js project.</p>
<pre><code>npm init -y
</code></pre><ul>
<li><code>npm init</code>: This command initializes a new Node.js project using npm (Node Package Manager).</li>
<li><code>-y</code>: This flag automatically accepts all default values for the <code>package.json</code> file, so you don't have to manually provide input for each field.</li>
</ul>
<p>After running these commands, you should have a new directory (bcrypt-password-hash) with a package.json file, indicating that you successfully created a new Node.js project. You can now go ahead and install dependencies and write code.</p>
<h3 id="heading-create-a-file-named-indexjs-where-you-will-write-your-code">Create a file named <code>index.js</code> where you will write your code:</h3>
<p>To create a file named <code>index.js</code> where you will write your code, you can use the <code>touch</code> command in your terminal. Here's how to do it:</p>
<pre><code>touch index.js
</code></pre><ul>
<li><code>touch</code>: This command is used to create a new file. (Note that you must have already installed <code>touch</code> on your machine to use it. If<br>you haven't, you may run this command in your terminal to install<br>touch: <code>npm install touch-cli -g</code>.)</li>
<li><code>index.js</code>: This is the name of the file you want to create. In this case, you're creating a JavaScript file named <code>index.js</code>.</li>
</ul>
<p>After running this command, you'll have a new file named <code>index.js</code> in your project directory where you can write your Node.js code just like you can see in the image below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Bcrypt.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now that we've correctly constructed a Node.js project, we can install bcrypt in our project.</p>
<h3 id="heading-install-the-required-dependencies-bcrypt">Install the required dependencies (bcrypt):</h3>
<p>To install bcrypt, you'll use npm, the Node.js package manager. Here's the command to install bcrypt:</p>
<pre><code>npm install bcrypt
</code></pre><ul>
<li><code>npm install</code>: This command is used to install packages from the npm registry.</li>
<li><code>bcrypt</code>: This is the name of the package you want to install. bcrypt is a popular package for hashing passwords securely in Node.js.</li>
</ul>
<p>When you run this command, npm will download and install the bcrypt package and its dependencies in the <code>node_modules</code> directory of your project. This directory will include all of the dependencies required for your project, including bcrypt.</p>
<h2 id="heading-how-to-set-up-bcrypt-in-nodejs">How to Set Up Bcrypt in Node.js</h2>
<p>Once Bcrypt is installed in your Node.js project, you can seamlessly integrate its functionality into your application. Here's how to proceed:</p>
<p>Firstly, after installing the bcrypt package using npm, make sure you import it into your Node.js application <code>index.js</code> file to utilize its features effectively. </p>
<p>Here's how to do it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'bcrypt'</span>);
</code></pre>
<p>This line of code ensures that the bcrypt package is accessible within your application, allowing you to leverage its powerful capabilities for secure password hashing and verification. </p>
<p>With bcrypt integrated into your project, you can enhance the security of user authentication and data protection.</p>
<p>bcrypt provides two primary functions for password hashing and comparison:</p>
<ol>
<li><code>bcrypt.hash()</code>: This function is used to generate a hash of a plaintext password. It takes the plaintext password and a salt factor (optional) as input parameters and returns the hashed password asynchronously.</li>
<li><code>bcrypt.compare()</code>: This function is used to compare a plaintext password with its hashed counterpart. It takes the plaintext password and the hashed password as input parameters and returns a boolean value indicating whether the passwords match.</li>
</ol>
<h2 id="heading-how-to-hash-passwords-with-bcrypt">How to Hash Passwords With Bcrypt</h2>
<p>Having delved into the significance of password hashing, as well as the concepts of hash and salt, let's put theory into practice within our <code>index.js</code> file.</p>
<h3 id="heading-how-to-generate-a-salt-and-hash-the-password">How to Generate a Salt and Hash the Password</h3>
<p>As we've learned, a key aspect of secure password hashing involves incorporating a unique salt into the hashing process. bcrypt simplifies this by handling salt generation and password hashing seamlessly.</p>
<p>To begin, we require the bcrypt module in our Node.js application:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'bcrypt'</span>);
</code></pre>
<p>To ensure the strength of our password hashes, we determine the number of salt rounds. This value dictates the computational cost of hashing and, consequently, the level of security:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> saltRounds = <span class="hljs-number">10</span>; <span class="hljs-comment">// Typically a value between 10 and 12</span>
</code></pre>
<p>With our configuration established, we can generate a salt asynchronously using the <code>bcrypt.genSalt()</code> function. This salt will be unique for each password hash, enhancing security:</p>
<pre><code class="lang-javascript">bcrypt.genSalt(saltRounds, <span class="hljs-function">(<span class="hljs-params">err, salt</span>) =&gt;</span> {
<span class="hljs-keyword">if</span> (err) {
    <span class="hljs-comment">// Handle error</span>
    <span class="hljs-keyword">return</span>;
}

<span class="hljs-comment">// Salt generation successful, proceed to hash the password</span>
});
</code></pre>
<p>Once the salt is generated, we combine it with the user's password to compute the hash using the <code>bcrypt.hash()</code> function. This results in a securely hashed password ready for storage:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> userPassword = <span class="hljs-string">'user_password'</span>; <span class="hljs-comment">// Replace with the actual password</span>
bcrypt.hash(userPassword, salt, <span class="hljs-function">(<span class="hljs-params">err, hash</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-comment">// Handle error</span>
        <span class="hljs-keyword">return</span>;
    }

<span class="hljs-comment">// Hashing successful, 'hash' contains the hashed password</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hashed password:'</span>, hash);
});
</code></pre>
<p>By leveraging bcrypt for password hashing in our Node.js application, we ensure the robust security of user credentials. The incorporation of unique salts for each password hash, coupled with the computational complexity of bcrypt, fortifies our defense against unauthorized access and malicious attacks.</p>
<p>In the next section, we'll explore how to verify passwords and discuss best practices for securely managing hashed passwords.</p>
<h2 id="heading-how-to-verify-passwords-with-bcrypt">How to Verify Passwords With Bcrypt</h2>
<p>Now that we've covered the process of hashing passwords using bcrypt within our Node.js application, let's shift our focus to verifying passwords during user authentication. </p>
<p>In this section, we'll explore how bcrypt facilitates password verification, ensuring a secure and seamless authentication process.</p>
<h3 id="heading-how-to-retrieve-a-hashed-password-from-the-database">How to Retrieve a Hashed Password from the Database</h3>
<p>Before we can verify a user's password, we need to retrieve the hashed password associated with the user's account from the database. </p>
<p>Assuming you have a user authentication system in place, you'll typically query the database to fetch the hashed password based on the user's username or email.</p>
<p>Once you have retrieved the hashed password from the database, you're ready to proceed with the password verification process.</p>
<h3 id="heading-how-to-verify-passwords">How to Verify Passwords</h3>
<p>To verify a password using bcrypt, use the <code>bcrypt.compare()</code> function. This function compares a plaintext password provided by the user during login with the hashed password stored in the database.</p>
<p>Here's how you can implement password verification using bcrypt in your Node.js application:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> storedHashedPassword = <span class="hljs-string">'hashed_password_from_database'</span>;
<span class="hljs-keyword">const</span> userInputPassword = <span class="hljs-string">'password_attempt_from_user'</span>;

bcrypt.compare(userInputPassword, storedHashedPassword, <span class="hljs-function">(<span class="hljs-params">err, result</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-comment">// Handle error</span>
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error comparing passwords:'</span>, err);
        <span class="hljs-keyword">return</span>;
    }

<span class="hljs-keyword">if</span> (result) {
    <span class="hljs-comment">// Passwords match, authentication successful</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Passwords match! User authenticated.'</span>);
} <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Passwords don't match, authentication failed</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Passwords do not match! Authentication failed.'</span>);
}
});
</code></pre>
<p>In this code snippet, <code>storedHashedPassword</code> represents the hashed password retrieved from the database, while <code>userInputPassword</code> is the plaintext password provided by the user during login. The <code>bcrypt.compare()</code> function compares these two passwords and returns a boolean value indicating whether they match.</p>
<p>In the next section, we'll discuss best practices for securely managing hashed passwords, including considerations for password storage and handling.</p>
<h2 id="heading-security-best-practices-with-bcrypt">Security Best Practices with bcrypt</h2>
<p>Now that we've discussed the principles of password hashing and verification with bcrypt, let's look at some important security best practices to ensure the integrity of our authentication system.</p>
<h3 id="heading-robust-password-guidelines">Robust Password Guidelines</h3>
<p>Encourage users to create strong and complex passwords that are resistant to dictionary attacks. Provide guidance on password length, the inclusion of alphanumeric characters, symbols, and the avoidance of common patterns.</p>
<h3 id="heading-salting">Salting</h3>
<p>Always use a unique salt for each password hash. This prevents attackers from using precomputed rainbow tables to crack passwords. bcrypt automatically handles salt generation, ensuring that each hash is unique.</p>
<h3 id="heading-adaptive-hashing">Adaptive Hashing</h3>
<p>bcrypt employs adaptive hashing, allowing developers to adjust the computational cost of hashing over time. Periodically increase the number of hashing rounds to keep pace with advancements in hardware and computational power.</p>
<h3 id="heading-secure-storage">Secure Storage</h3>
<p>Store hashed passwords securely in your database. Ensure that access controls are in place to prevent unauthorized access to user credentials. Avoid storing plaintext passwords or using reversible encryption algorithms.</p>
<h3 id="heading-error-handling">Error Handling</h3>
<p>Implement proper error handling mechanisms when working with bcrypt functions. Handle errors gracefully and avoid leaking sensitive information that could aid attackers in exploiting vulnerabilities.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, we have explored the essential aspects of password security and the role of bcrypt in safeguarding user credentials within Node.js applications. From understanding the fundamentals of password hashing and salting to implementing secure authentication mechanisms, we have covered a wide array of topics aimed at enhancing the security posture of our applications.</p>
<p>By leveraging bcrypt for password hashing and verification, we ensure that sensitive user data remains protected against unauthorized access and malicious attacks. bcrypt's robust algorithm, combined with adaptive hashing and salt generation, provides a reliable defense mechanism against common password-based vulnerabilities.</p>
<p>We also discussed security best practices, including strong password policies, secure storage practices, and error handling. By adhering to these best practices and staying vigilant against evolving threats, we can create a secure authentication system that instills confidence in our users and upholds the integrity of our applications.</p>
<p>Let's continue to prioritize security and strive for excellence in our pursuit of building robust and trustworthy applications.</p>
<p>Thank you for joining me on this exploration of password security with bcrypt. Together, we can create a safer digital environment for all users.</p>
<p>Happy Coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Custom API Gateway with Node.js ]]>
                </title>
                <description>
                    <![CDATA[ In the era of microservices, where applications are divided into smaller, independently deployable services, managing and securing the communication between these services becomes crucial. This is where an API gateway comes into play.  An API gateway... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-custom-api-gateway-with-node-js/</link>
                <guid isPermaLink="false">66baee892c1f85b4545c8bf4</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Microservices ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Iroro Chadere ]]>
                </dc:creator>
                <pubDate>Fri, 08 Mar 2024 23:16:38 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/Building-custom-API-gateway.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the era of <a target="_blank" href="https://www.brightsidecodes.com/blog/understanding-microservices-and-api-gateway">microservices</a>, where applications are divided into smaller, independently deployable services, managing and securing the communication between these services becomes crucial. This is where an API gateway comes into play. </p>
<p>An API gateway serves as a central entry point for all client requests. It provides various functionalities such as routing, load balancing, authentication, and rate limiting.</p>
<p>In this article, we’ll explore how you can build out a custom API gateway using Node.js.</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-an-api-gateway">What is an API Gateway?</a></li>
<li><a class="post-section-overview" href="#heading-security-in-api-gateways">Security in API Gateways</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-a-custom-api-gateway-with-nodejs">How to Build a Custom API Gateway with Node.js</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>This is a beginner's guide that should be relatively easy to follow. But to fully understand and get the most out of it, basic knowledge of <a target="_blank" href="https://nodejs.org/">Node.js</a> such as installation, setting up, and spinning up a server is vital. </p>
<p>Without further ado, let's dig in!</p>
<h2 id="heading-what-is-an-api-gateway">What is an API Gateway?</h2>
<p>API gateways act as intermediaries between clients and back-end services in a Microservices architecture. They abstract the complexity of the underlying services and expose a unified API to clients. </p>
<p>By consolidating multiple service endpoints into a single entry point, API gateways simplify client-side code and improve the overall scalability and performance of the system.</p>
<p>Compared to other popular API gateway solutions like Kong, AWS API Gateway, and Tyke, building a custom API gateway using Node.js offers flexibility and customization options tailored to your specific project requirements.</p>
<p>To get a little more understanding of what an API gateway is, I recommend you <a target="_blank" href="https://www.brightsidecodes.com/blog/understanding-microservices-and-api-gateway">check out this article</a> if you haven’t.</p>
<h3 id="heading-benefits-of-using-an-api-gateway">Benefits of Using an API Gateway:</h3>
<ul>
<li><strong>Improved scalability and performance through request routing and load balancing:</strong> API gateways facilitate request routing and load balancing, distributing incoming traffic across multiple backend services to ensure optimal performance and scalability.</li>
<li><strong>Simplified client-side code by providing a unified API endpoint</strong>: With a unified API endpoint provided by the API gateway, clients can interact with multiple services seamlessly, reducing complexity and improving the maintainability of client-side code.</li>
<li><strong>Enhanced Security</strong>: API gateways offer robust security features such as authentication, authorization, and rate limiting, protecting backend services from unauthorized access and potential security threats.</li>
</ul>
<h2 id="heading-security-in-api-gateways">Security in API Gateways</h2>
<p>Security is paramount in modern software development, especially when dealing with distributed systems and microservices. API gateways play a crucial role in enforcing security measures to safeguard sensitive data and prevent unauthorized access to APIs.</p>
<p>Common security features implemented in API gateways include:</p>
<ul>
<li>JWT Authentication: Verifying the identity of clients using JSON Web Tokens (JWT) to ensure secure communication between clients and backend services.</li>
<li>OAuth2 Integration: Providing secure access control and authorization mechanisms using OAuth2 protocols to authenticate and authorize client requests.</li>
<li>SSL Termination: Encrypting traffic between clients and the API gateway using SSL/TLS protocols to protect data in transit from eavesdropping and tampering.</li>
</ul>
<p>Now you should have a general overview of what an API gateway is and why it's important.</p>
<p>In the next section, we will delve into the process of building a custom API gateway using Node.js. I'll demonstrate how to implement security features using the http-proxy-middleware package.</p>
<h2 id="heading-how-to-build-a-custom-api-gateway-with-nodejs">How to Build a Custom API Gateway with Node.js</h2>
<p>As I've already discussed, we'll be using Node.js for this tutorial. In my opinion, Node.js is by far the easiest and most popular web framework. Anyone can learn how to use it.</p>
<p>For this guide, I assume you already know or have a basic understanding of Node.js and how to set up a server.</p>
<h3 id="heading-getting-started-installations-and-setup">Getting Started – Installations and Setup</h3>
<p>To get started, create a new folder called “API-gateway” entirely outside your front-end or your back-end code. Once the folder is created, open it on your terminal and run <code>npm init -y</code>. This will set up <code>npm</code> and then you’re ready to roll things out!</p>
<p>We’ll be using a couple of NPM packages, and it’s best to install them now. The most important one is the <code>http-proxy-middleware</code>. This middleware or package is what will route our requests from one endpoint (www.domain.com/auth ) to each corresponding endpoint (www.externaldomain.com/v1/bla/auth, www.externaldomain.com/v1/bla/projects ) as defined in our microservices.</p>
<p>To install the http-proxy-middleware, simply run <code>npm i http-proxy-middleware</code> on the root folder on your terminal. If it's installed, you’re good to go.</p>
<p>Next, we’ll need the remaining packages. Simply run <code>npm install express cors helmet morgan</code> on your terminal in the root folder of the API gateway. </p>
<p>The above command installs the following:</p>
<ul>
<li><strong>Express</strong>: our Node.js library for creating our server and running our code</li>
<li><strong>Cors</strong>: middleware to manage and control any cross-origin requests</li>
<li><strong>Helmet</strong>: yet another middleware for securing our HTTP response headers</li>
<li><strong>Morgan</strong>: a logging tool we can use to track both success and error logs</li>
</ul>
<p>Lastly, install Nodemon. This is a tool that spins up your server whenever you save a file using <code>npm install --save-dev nodemon</code>.</p>
<p>Now, go to your package.js file and update the scripts section. It should look like this:</p>
<pre><code><span class="hljs-string">"scripts"</span>: {
 <span class="hljs-string">"start"</span>: <span class="hljs-string">"node index.js"</span>,
 <span class="hljs-string">"dev"</span>: <span class="hljs-string">"nodemon index.js"</span>,
 <span class="hljs-string">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>
},
</code></pre><p>To finally start testing things out, create a new file called index.js in that same api-gateway folder.  </p>
<p>If you get everything right, you should have the following files:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-from-2024-03-04-12-50-56.png" alt="Image" width="600" height="400" loading="lazy">
<em>An image showing the file structure of our code base</em></p>
<h3 id="heading-putting-it-all-together">Putting it All Together</h3>
<p>A good code practice is to break things down as much as possible into smaller components. </p>
<p>But for this guide, we’re going to break that rule and put all the code into that one <code>index.js</code> file we created from the steps above. We'll be doing it this way because having too many files and an overly complex set up here might be confusing, especially while you're learning how things work.</p>
<p>First thing first, open the index.js file you’ve created and paste the following code into it:</p>
<pre><code><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cors"</span>);
<span class="hljs-keyword">const</span> helmet = <span class="hljs-built_in">require</span>(<span class="hljs-string">"helmet"</span>);
<span class="hljs-keyword">const</span> morgan = <span class="hljs-built_in">require</span>(<span class="hljs-string">"morgan"</span>);
<span class="hljs-keyword">const</span> { createProxyMiddleware } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"http-proxy-middleware"</span>);
</code></pre><p>In the code above we're just importing packages. </p>
<p>Next up, initialize and set up the imported packages like this:</p>
<pre><code><span class="hljs-comment">// Create an instance of Express app</span>
<span class="hljs-keyword">const</span> app = express();


<span class="hljs-comment">// Middleware setup</span>
app.use(cors()); <span class="hljs-comment">// Enable CORS</span>
app.use(helmet()); <span class="hljs-comment">// Add security headers</span>
app.use(morgan(<span class="hljs-string">"combined"</span>)); <span class="hljs-comment">// Log HTTP requests</span>
app.disable(<span class="hljs-string">"x-powered-by"</span>); <span class="hljs-comment">// Hide Express server information</span>
</code></pre><p>Remember that an API gateway is a single source of truth for all your services or external URLs. This means you must have other services or URLs you want to forward the requests to. </p>
<p>Assuming you already have your other services running either locally or deployed, let’s move to the next section of the code.</p>
<pre><code><span class="hljs-comment">// Define routes and corresponding microservices</span>
<span class="hljs-keyword">const</span> services = [
 {
   <span class="hljs-attr">route</span>: <span class="hljs-string">"/auth"</span>,
   <span class="hljs-attr">target</span>: <span class="hljs-string">"https://your-deployed-service.herokuapp.com/auth"</span>,
 },
 {
   <span class="hljs-attr">route</span>: <span class="hljs-string">"/users"</span>,
   <span class="hljs-attr">target</span>: <span class="hljs-string">"https://your-deployed-service.herokuapp.com/users/"</span>,
 },
 {
   <span class="hljs-attr">route</span>: <span class="hljs-string">"/chats"</span>,
   <span class="hljs-attr">target</span>: <span class="hljs-string">"https://your-deployed-service.herokuapp.com/chats/"</span>,
 },
 {
   <span class="hljs-attr">route</span>: <span class="hljs-string">"/payment"</span>,
   <span class="hljs-attr">target</span>: <span class="hljs-string">"https://your-deployed-service.herokuapp.com/payment/"</span>,
 },
 <span class="hljs-comment">// Add more services as needed either deployed or locally.</span>
];
</code></pre><p>In the above code, we created a services array list and defined objects each containing routes (where we’ll make requests to) and targets (where the requests will be forwarded to).  </p>
<p>Make sure to update the routes and targets to suit your needs.</p>
<p>Can you guess what’s next…?</p>
<p>Well, it’s finally time to create the simple logic to forward the requests to our target URL, setting up a rate limit and timeouts. And do you know what’s coming next? A code sample, lol:</p>
<pre><code><span class="hljs-comment">// Define rate limit constants</span>
<span class="hljs-keyword">const</span> rateLimit = <span class="hljs-number">20</span>; <span class="hljs-comment">// Max requests per minute</span>
<span class="hljs-keyword">const</span> interval = <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>; <span class="hljs-comment">// Time window in milliseconds (1 minute)</span>

<span class="hljs-comment">// Object to store request counts for each IP address</span>
<span class="hljs-keyword">const</span> requestCounts = {};

<span class="hljs-comment">// Reset request count for each IP address every 'interval' milliseconds</span>
<span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">Object</span>.keys(requestCounts).forEach(<span class="hljs-function">(<span class="hljs-params">ip</span>) =&gt;</span> {
    requestCounts[ip] = <span class="hljs-number">0</span>; <span class="hljs-comment">// Reset request count for each IP address</span>
  });
}, interval);

<span class="hljs-comment">// Middleware function for rate limiting and timeout handling</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rateLimitAndTimeout</span>(<span class="hljs-params">req, res, next</span>) </span>{
  <span class="hljs-keyword">const</span> ip = req.ip; <span class="hljs-comment">// Get client IP address</span>

  <span class="hljs-comment">// Update request count for the current IP</span>
  requestCounts[ip] = (requestCounts[ip] || <span class="hljs-number">0</span>) + <span class="hljs-number">1</span>;

  <span class="hljs-comment">// Check if request count exceeds the rate limit</span>
  <span class="hljs-keyword">if</span> (requestCounts[ip] &gt; rateLimit) {
    <span class="hljs-comment">// Respond with a 429 Too Many Requests status code</span>
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">429</span>).json({
      <span class="hljs-attr">code</span>: <span class="hljs-number">429</span>,
      <span class="hljs-attr">status</span>: <span class="hljs-string">"Error"</span>,
      <span class="hljs-attr">message</span>: <span class="hljs-string">"Rate limit exceeded."</span>,
      <span class="hljs-attr">data</span>: <span class="hljs-literal">null</span>,
    });
  }

  <span class="hljs-comment">// Set timeout for each request (example: 10 seconds)</span>
  req.setTimeout(<span class="hljs-number">15000</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Handle timeout error</span>
    res.status(<span class="hljs-number">504</span>).json({
      <span class="hljs-attr">code</span>: <span class="hljs-number">504</span>,
      <span class="hljs-attr">status</span>: <span class="hljs-string">"Error"</span>,
      <span class="hljs-attr">message</span>: <span class="hljs-string">"Gateway timeout."</span>,
      <span class="hljs-attr">data</span>: <span class="hljs-literal">null</span>,
    });
    req.abort(); <span class="hljs-comment">// Abort the request</span>
  });

  next(); <span class="hljs-comment">// Continue to the next middleware</span>
}

<span class="hljs-comment">// Apply the rate limit and timeout middleware to the proxy</span>
app.use(rateLimitAndTimeout);

<span class="hljs-comment">// Set up proxy middleware for each microservice</span>
services.forEach(<span class="hljs-function">(<span class="hljs-params">{ route, target }</span>) =&gt;</span> {
  <span class="hljs-comment">// Proxy options</span>
  <span class="hljs-keyword">const</span> proxyOptions = {
    target,
    <span class="hljs-attr">changeOrigin</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">pathRewrite</span>: {
      [<span class="hljs-string">`^<span class="hljs-subst">${route}</span>`</span>]: <span class="hljs-string">""</span>,
    },
  };

  <span class="hljs-comment">// Apply rate limiting and timeout middleware before proxying</span>
  app.use(route, rateLimitAndTimeout, createProxyMiddleware(proxyOptions));
});
</code></pre><p>I added a bunch of good code comments to help you understand what's going on.</p>
<p>Congratulations if you know what’s happening above. If you don’t, you can read about the <a target="_blank" href="https://www.npmjs.com/package/http-proxy-middleware">http-proxy-middleware</a> package.</p>
<p>But let’s get serious, we’re not done yet. </p>
<p>The above code still won’t work, as we need one more thing: writing a function to start the server when called upon.</p>
<p>Add the following code sample to the bottom of the index.js after all of the code you’ve added above:</p>
<pre><code><span class="hljs-comment">// Define port for Express server</span>
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">5000</span>;


<span class="hljs-comment">// Start Express server</span>
app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Gateway is running on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre><p>With that, when you run <code>npm run dev</code>, it spins up your server and you should be able to test this out using tools like Postman or any other tool you use to test APIs.</p>
<p>Now, before we go, let’s try to make this a little bit spicy! </p>
<p>Let’s add a 404 function to track and return a nice 404 message to a user if they navigate or send a request to a URL that doesn’t exist. </p>
<p>So on our services array defined above, we don’t have any routes defined for <code>products</code>. This means that if a user sends a request to <code>/product</code>, they’d get a server error because the request can’t be handled. </p>
<p>To tell the user that the URL is not found, we can add the following code sample just before we define the port and listen to it:</p>
<pre><code><span class="hljs-comment">// Handler for route-not-found</span>
app.use(<span class="hljs-function">(<span class="hljs-params">_req, res</span>) =&gt;</span> {
 res.status(<span class="hljs-number">404</span>).json({
   <span class="hljs-attr">code</span>: <span class="hljs-number">404</span>,
   <span class="hljs-attr">status</span>: <span class="hljs-string">"Error"</span>,
   <span class="hljs-attr">message</span>: <span class="hljs-string">"Route not found."</span>,
   <span class="hljs-attr">data</span>: <span class="hljs-literal">null</span>,
 });
});


<span class="hljs-comment">// Define port for Express server</span>
</code></pre><h2 id="heading-conclusion">Conclusion</h2>
<p>Building a custom API gateway with Node.js offers developers a flexible and customizable solution for managing, routing, and securing API calls in a microservices architecture. </p>
<p>Throughout this tutorial, we've explored the fundamental concepts of API gateways, including their role in simplifying client-side code, improving scalability and performance, and enhancing security.</p>
<p>By leveraging the power of Node.js and the <code>http-proxy-middleware</code> package, we've demonstrated how to implement a basic API gateway that proxies requests to multiple backend services. We've also enhanced our gateway with essential features such as rate limiting and timeouts to ensure reliable and secure communication between clients and services.</p>
<p>As you continue to explore the world of microservices and distributed systems, remember that API gateways play a crucial role in orchestrating communication and enforcing security measures. Whether you choose to build a custom solution or utilize existing gateway platforms, understanding the principles and best practices outlined in this tutorial will empower you to architect robust and scalable systems.</p>
<p>I encourage you to experiment with the code samples provided and explore further customization options to suit your project's unique requirements. The complete source code for this tutorial can be found here: https://github.com/irorochad/api-gateway.</p>
<p>Thank you for joining me on this journey to explore the intricacies of API gateways with Node.js. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use OpenTelementry to Trace Node.js Applications ]]>
                </title>
                <description>
                    <![CDATA[ Observability refers to our ability to "see" and understand what's happening inside a system by looking at its external signals (like logs, metrics, and traces). Observability involves collecting and analyzing data from sources within a system to mon... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-opentelementry-to-trace-node-js-applications/</link>
                <guid isPermaLink="false">66d45d5ad7a4e35e38434924</guid>
                
                    <category>
                        <![CDATA[ data ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abraham Dahunsi ]]>
                </dc:creator>
                <pubDate>Sat, 03 Feb 2024 00:21:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/feature-image-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Observability refers to our ability to "see" and understand what's happening inside a system by looking at its external signals (like logs, metrics, and traces).</p>
<p>Observability involves collecting and analyzing data from sources within a system to monitor its performance and address problems effectively.</p>
<h2 id="heading-why-is-observability-useful">Why is Observability Useful?</h2>
<ol>
<li><p><strong>Detecting and Troubleshooting Problems:</strong> Observability plays a role in identifying and diagnosing issues within a system. When something goes wrong, having access to data helps pinpoint the cause and resolve problems more quickly.</p>
</li>
<li><p><strong>Optimizing Performance:</strong> Through monitoring metrics and performance indicators, observability helps in optimizing the performance of your system. This includes identifying bottlenecks, improving resource utilization, and ensuring operation.</p>
</li>
<li><p><strong>Planning for Future Capacity:</strong> Understanding how your system behaves over time is vital for planning capacity requirements. Observability data can reveal trends, peak usage periods, and resource needs, helping your decisions regarding scaling.</p>
</li>
<li><p><strong>Enhancing User Experience:</strong> By observing user interactions with your system through logs and metrics, you can improve the user experience. It assists in recognizing patterns, preferences, and potential areas that can be enhanced for user satisfaction.</p>
</li>
</ol>
<h2 id="heading-why-should-i-use-opentelementary">Why Should I Use OpenTelementary?</h2>
<p>Observability is essential for ensuring the reliability and availability of your Node.js applications. But manually instrumenting your code to collect and export telemetry data, such as traces, metrics, and logs, can become very stressful.</p>
<p>Manual instrumentation is very tedious, error-prone, and inconsistent. It can also introduce additional overhead and complexity to your application logic.</p>
<p>In this guide, you will learn how to use OpenTelemetry’s auto-instrumentation to help you achieve effortless Node.js monitoring.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you go through this guide, make sure you have the following:</p>
<ul>
<li><p>A Node.js application</p>
</li>
<li><p>A Datadog account and an API key. If you don't have one, you can <a target="_blank" href="https://us5.datadoghq.com/signup">sign up here to get one</a>.</p>
</li>
<li><p>A Backend service. You can use a backend service like Zepkin or Jaeger to store and analyze trace data. For this guide, we'll be using Jaeger.</p>
</li>
<li><p>Some basic knowledge of <a target="_blank" href="https://www.freecodecamp.org/news/helpful-linux-commands-you-should-know/">Linux commands</a>. You should be familiar with using the command line and editing configuration files.</p>
</li>
</ul>
<h2 id="heading-prepare-your-application">Prepare Your Application</h2>
<p>In this guide, you will be using a Node.js application that has two services that transfer data between themselves. You will use OpenTelemetry’s Node.js client library to send trace data to an OpenTelementay collector.</p>
<p>Firstly, clone the Repo Locally:</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">clone</span> https://github.com/&lt;github-account&gt;/nodejs-example.git
</code></pre>
<p>Then run the application:</p>
<pre><code class="lang-bash">npm install
</code></pre>
<p>Go to the directory of the first service using this command:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> &lt;ServiceA&gt;
</code></pre>
<p>And start the first service.</p>
<pre><code class="lang-bash">$ node index.js
</code></pre>
<p>Then go to the directory of the second service</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> &lt;ServiceB&gt;
</code></pre>
<p>And start the second service.</p>
<pre><code class="lang-bash">$ node index.js
</code></pre>
<p>Open Service A, in this case port <code>5555</code>, and input some information. Then repeat the same for Service B.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/ServiceASshot.png" alt="ServiceASshot" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-set-up-opentelementary">How to Set Up OpenTelementary</h2>
<p>After starting the services, it's time to install the OpenTelementary modules you'll need for auto-instrumentation.</p>
<p>Here are what we need to install:</p>
<pre><code class="lang-bash">$ npm install --save @opentelemetry/api

$ npm install --save @opentelemetry/instrumentation

$ npm install --save @opentelemetry/tracing

$ npm install --save @opentelemetry/exporter-trace-otlp-http

$ npm install --save @opentelemetry/resources

$ npm install --save @opentelemetry/semantic-conventions

$ npm install --save @opentelemetry/auto-instrumentations-node

$ npm install --save @opentelemetry/sdk-node

$ npm install --save @opentelemetry/exporter-jaeger
</code></pre>
<p>Here's break down of what each module does:</p>
<ul>
<li><p><code>@opentelemetry/api</code>: This module provides the OpenTelemetry API for Node.js.</p>
</li>
<li><p><code>@opentelemetry/instrumentation</code>: The instrumentation libraries provide automatic instrumentation for your Node.js application. They automatically capture telemetry data without requiring manual code modifications.</p>
</li>
<li><p><code>@opentelemetry/tracing</code>: This module contains the core tracing functionality for OpenTelemetry in your Node.js application. It includes the Tracer and Span interfaces, which are important for capturing and representing distributed traces within your applications.</p>
</li>
<li><p><code>@opentelemetry/exporter-trace-otlp-http</code>: This exporter module enables sending trace data to an OpenTelemetry Protocol (OTLP) compatible backend over HTTP.</p>
</li>
<li><p><code>@opentelemetry/resources</code>: This module provides a way to define and manage resources associated with traces.</p>
</li>
<li><p><code>@opentelemetry/semantic-conventions</code>: This module defines a set of semantic conventions for tracing. It establishes a common set of attribute keys and value formats to ensure consistency in how telemetry data is represented and interpreted.</p>
</li>
<li><p><code>@opentelemetry/auto-instrumentations-node</code>: This module simplifies the process of instrumenting your application by automatically applying instrumentation to supported libraries.</p>
</li>
<li><p><code>@opentelemetry/sdk-node</code>: The Software Development Kit (SDK) for Node.js provides the implementation of the OpenTelemetry API.</p>
</li>
<li><p><code>@opentelemetry/exporter-jaeger</code>: This exporter module allows exporting trace data to Jaeger. Jaeger provides a user-friendly interface for monitoring and analyzing trace data.</p>
</li>
</ul>
<h2 id="heading-configure-the-nodejs-application">Configure the Node.js Application</h2>
<p>Next, add a Node.js SDk tracer to handle the instantiation and shutdown of the tracing.</p>
<p>To add the tracer, create a file <code>tracer.js</code>:</p>
<pre><code class="lang-bash">$ nano tracer.js
</code></pre>
<p>Then add the following code to the file:</p>
<pre><code class="lang-javascript"><span class="hljs-meta">
"use strict"</span>;

<span class="hljs-keyword">const</span> {
    BasicTracerProvider,
    SimpleSpanProcessor,
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@opentelemetry/tracing"</span>);
<span class="hljs-comment">// Import the JaegerExporter</span>
<span class="hljs-keyword">const</span> { JaegerExporter } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@opentelemetry/exporter-jaeger"</span>);
<span class="hljs-keyword">const</span> { Resource } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@opentelemetry/resources"</span>);
<span class="hljs-keyword">const</span> {
    SemanticResourceAttributes,
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@opentelemetry/semantic-conventions"</span>);

<span class="hljs-keyword">const</span> opentelemetry = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@opentelemetry/sdk-node"</span>);
<span class="hljs-keyword">const</span> {
    getNodeAutoInstrumentations,
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@opentelemetry/auto-instrumentations-node"</span>);

<span class="hljs-comment">// Create a new instance of JaegerExporter with the options</span>
<span class="hljs-keyword">const</span> exporter = <span class="hljs-keyword">new</span> JaegerExporter({
    <span class="hljs-attr">serviceName</span>: <span class="hljs-string">"YOUR-SERVICE-NAME"</span>,
    <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>, <span class="hljs-comment">// optional, can be set by OTEL_EXPORTER_JAEGER_AGENT_HOST</span>
    <span class="hljs-attr">port</span>: <span class="hljs-number">16686</span> <span class="hljs-comment">// optional</span>
});

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> BasicTracerProvider({
    <span class="hljs-attr">resource</span>: <span class="hljs-keyword">new</span> Resource({
        [SemanticResourceAttributes.SERVICE_NAME]:
            <span class="hljs-string">"YOUR-SERVICE-NAME"</span>,
    }),
});
<span class="hljs-comment">// Add the JaegerExporter to the span processor</span>
provider.addSpanProcessor(<span class="hljs-keyword">new</span> SimpleSpanProcessor(exporter));

provider.register();
<span class="hljs-keyword">const</span> sdk = <span class="hljs-keyword">new</span> opentelemetry.NodeSDK({
    <span class="hljs-attr">traceExporter</span>: exporter,
    <span class="hljs-attr">instrumentations</span>: [getNodeAutoInstrumentations()],
});

sdk
    .start()
    .then(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Tracing initialized"</span>);
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error initializing tracing"</span>, error));

process.on(<span class="hljs-string">"SIGTERM"</span>, <span class="hljs-function">() =&gt;</span> {
    sdk
        .shutdown()
        .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Tracing terminated"</span>))
        .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error terminating tracing"</span>, error))
        .finally(<span class="hljs-function">() =&gt;</span> process.exit(<span class="hljs-number">0</span>));
</code></pre>
<p>Here is a simple breakdown of the code:</p>
<ul>
<li><p>The code starts by importing the modules <code>BasicTracerProvider</code> and <code>SimpleSpanProcessor</code> for setting up tracing from the OpenTelemetry library</p>
</li>
<li><p>It then imports the JaegerExporter module for exporting trace data to Jaeger.</p>
</li>
<li><p>The code creates a new instance of the JaegerExporter, specifying the service name, host, and port.</p>
</li>
<li><p>It then creates a <code>BasicTracerProvider</code> and adds the JaegerExporter to the span processor using <code>SimpleSpanProcessor</code>.</p>
</li>
<li><p>The provider is registered, setting it as the default provider for the application.</p>
</li>
<li><p>An OpenTelemetry SDK instance is created, configuring it with the JaegerExporter and enabling auto-instrumentations for Node.js.</p>
</li>
<li><p>The OpenTelemetry SDK is started, initializing tracing.</p>
</li>
<li><p>A handler for the SIGTERM signal is set up to shut down tracing when the application is terminated.</p>
</li>
<li><p>The code then configures the trace provider with a trace exporter. To verify the instrumentation, <code>ConsoleSpanExporter</code> is used to print some of the tracer output to the console.</p>
</li>
</ul>
<h2 id="heading-how-to-set-up-opentelemetry-to-export-the-traces">How to Set Up OpenTelemetry to Export the Traces</h2>
<p>Next, you'll need to write the configurations to collect and export data in the OpenTelemetry Collector.</p>
<p>Create a file <code>config.yaml</code>:</p>
<pre><code class="lang-yaml">
<span class="hljs-attr">receivers:</span>
  <span class="hljs-attr">otlp:</span>
    <span class="hljs-attr">protocols:</span>
      <span class="hljs-attr">grpc:</span>
      <span class="hljs-attr">http:</span>

<span class="hljs-attr">exporters:</span>
  <span class="hljs-attr">datadog:</span>
    <span class="hljs-attr">api:</span> <span class="hljs-comment"># Replace with your Datadog API key</span>
      <span class="hljs-attr">key:</span> <span class="hljs-string">"&lt;YOUR_DATADOG_API_KEY&gt;"</span>
    <span class="hljs-comment"># Optional:</span>
    <span class="hljs-comment">#   - endpoint: https://app.datadoghq.eu  # For EU region</span>

<span class="hljs-attr">processors:</span>
  <span class="hljs-attr">batch:</span>

<span class="hljs-attr">extensions:</span>
  <span class="hljs-attr">pprof:</span>
    <span class="hljs-attr">endpoint:</span> <span class="hljs-string">:1777</span>
  <span class="hljs-attr">zpages:</span>
    <span class="hljs-attr">endpoint:</span> <span class="hljs-string">:55679</span>
  <span class="hljs-attr">health_check:</span>

<span class="hljs-attr">service:</span>
  <span class="hljs-attr">extensions:</span> [<span class="hljs-string">health_check</span>, <span class="hljs-string">pprof</span>, <span class="hljs-string">zpages</span>]
  <span class="hljs-attr">pipelines:</span>
    <span class="hljs-attr">traces:</span>
      <span class="hljs-attr">receivers:</span> [<span class="hljs-string">otlp</span>]
      <span class="hljs-attr">processors:</span> [<span class="hljs-string">batch</span>]
      <span class="hljs-attr">exporters:</span> [<span class="hljs-string">datadog</span>]
</code></pre>
<p>The configuration sets up OpenTelemetry with the OTLP (OpenTelemetry Protocol) receiver and the Datadog exporter. Here’s a break down of the code:</p>
<ul>
<li><p><code>receivers</code>: Specifies the components that receive the telemetry data. In this case, it includes the OTLP receiver, which supports both gRPC and HTTP protocols.</p>
</li>
<li><p><code>exporters</code>: Defines the components responsible for exporting telemetry data. Here, it configures the Datadog exporter, providing the Datadog API key. Additionally, an optional <code>endpoint</code> is provided for using Datadog's EU region.</p>
</li>
<li><p><code>processors</code>: Specifies the data processing components. In this case, the <code>batch</code> processor is used to batch and send data in larger chunks for efficiency.</p>
</li>
<li><p><code>extensions</code>: Defines additional components that extend the functionality. Here, it includes extensions for pprof (profiling data), zpages (debugging pages), and a health check extension.</p>
</li>
<li><p><code>service</code>: Configures the overall service behavior, including the extensions and pipelines. The <code>extensions</code> section lists the extensions to be used, and the <code>pipelines</code> section configures the telemetry data pipeline. Here, the traces pipeline includes the OTLP receiver, the batch processor, and the Datadog exporter.</p>
</li>
</ul>
<p>This code is configured by the collector with the Datadog exporter to send the traces to Datadog Distributed Tracing services. However, there are other distributed tracing services that you can use like New Relic, Logzio, and Zipkin.</p>
<h2 id="heading-how-to-start-the-application">How to Start the Application</h2>
<p>After correctly setting up auto-instrumentation, start the application again to test and verify the tracing configuration.</p>
<p>Begin by starting the OpenTelemetry Collector:</p>
<pre><code class="lang-bash">./otelcontribcol_darwin_amd64 --config ./config.yaml
</code></pre>
<p>The collector will start on port 4317.</p>
<p>Next, go to the directory of the first service:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> &lt;ServiceA&gt;
</code></pre>
<p>Then start the first service with the “--require './tracer.js'” parameter to enable the application instrumentation.</p>
<pre><code class="lang-bash">$ node --require <span class="hljs-string">'./tracer.js'</span> index.js
</code></pre>
<p>Repeat this to start the second service.</p>
<p>Using a browser like Chrome, go to the endpoints of your two applications' services, add some data, and send some requests to test the tracing configuration.</p>
<p>Once the requests are made, these traces are picked up by the collector, which then dispatches them to the distributed tracing backend specified by the exporter configuration in the collector's configuration file.</p>
<p>It's worth noting that our tracer not only facilitates the transmission of traces to the designated backend, but also exports them to the console at the same time.</p>
<p>This dual functionality allows for real-time visibility into the traces being generated and sent, helping us in the monitoring and debugging processes.</p>
<p>Now, let’s use Jaeger UI to monitor the traces:</p>
<p>Start Jaeger with the following command:</p>
<pre><code class="lang-bash">docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14250:14250 \
  -p 14268:14268 \
  -p 14269:14269 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.32
</code></pre>
<p>Using a browser, start Jaeger UI at the http://localhost:16686/ endpoint.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image4-1024x508.png" alt="image4-1024x508" width="600" height="400" loading="lazy"></p>
<p>There you have it! The initiation of the trace starting from the inception point of one service, navigating through a sequence of operations.</p>
<p>This path is created as the service starts its operations, resulting in the set up of the other service to fulfill the original request you initiated earlier.</p>
<p>The trace provides a visual narrative of what happens between these services, offering insights into each step of the process.</p>
<h2 id="heading-how-can-you-use-observability-data">How Can You Use Observability Data?</h2>
<ol>
<li><p><strong>Monitoring Metrics:</strong> Keep an eye on key metrics such as response times, error rates, and resource usage. Sudden spikes or anomalies can indicate issues that require attention.</p>
</li>
<li><p><strong>Logging:</strong> Log data provides detailed information about events and actions within a system. Analyzing logs helps in understanding the sequence of activities and tracing the steps leading to an issue.</p>
</li>
<li><p><strong>Tracing:</strong> Tracing involves tracking the flow of requests or transactions across different components of a system. This helps in understanding the journey of a request and identifying any bottlenecks or delays.</p>
</li>
<li><p><strong>Alerting:</strong> Set up alerts based on specific conditions or thresholds. When certain metrics exceed predefined limits, alerts can notify you in real-time, allowing for immediate action.</p>
</li>
<li><p><strong>Visualization:</strong> Use graphical representations and dashboards to visualize complex data. This makes it easier to identify patterns, trends, and correlations in the observability data.</p>
</li>
</ol>
<p>Observability, when implemented effectively, empowers teams to proactively manage and improve the performance, reliability, and user experience of their systems. It's a crucial aspect of modern software development and operations.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this guide you learned how to auto-instrument Node.js applications with little code by:</p>
<ul>
<li><p>Installing and configuring the OpenTelemetry Node.js SDK and the auto-instrumentation package</p>
</li>
<li><p>Enabling automatic tracing and metrics collection for your Node.js applications and their dependencies</p>
</li>
<li><p>Exporting to visualize your telemetry data on a backend, Jaeger.</p>
</li>
</ul>
<p>Using OpenTelemetry’s auto-instrumentation can help you gain valuable insights into the performance and behavior of your Node.js applications without having to manually instrument each library or framework.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use pnpm – Installation and Common Commands ]]>
                </title>
                <description>
                    <![CDATA[ pnpm is like npm, but it's way faster and more efficient. After all, the starting p stands for _p_erformant. According to its creator, Zoltan Kochan, pnpm "allows you to save gigabytes of disk space." Many popular projects including Next.js, Vite, Sv... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-pnpm/</link>
                <guid isPermaLink="false">66c5f749bae1f0a10743aece</guid>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ npm ]]>
                    </category>
                
                    <category>
                        <![CDATA[ performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pnpm ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Biswas ]]>
                </dc:creator>
                <pubDate>Tue, 09 Jan 2024 15:31:52 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/cover-pnpm-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><em>pnpm</em> is like npm, but it's way faster and more efficient. After all, the starting <em>p</em> stands for _p_erformant.</p>
<p>According to its creator, Zoltan Kochan, pnpm "allows you to save gigabytes of disk space."</p>
<p>Many popular projects including Next.js, Vite, Svelte, and even freeCodeCamp use pnpm. So now is a great time try out this tool if you haven't yet. I'm sure your time will not be wasted.</p>
<p>In this article, I won't go into details of why pnpm is faster and more efficient than npm. You can check out the <a target="_blank" href="https://pnpm.io/motivation">official documentation</a> if you want to know more about that.</p>
<p>The goal of this article is to quickly get you started with pnpm so you can perform your day to day tasks that you previously did with npm or yarn. Grab your favorite cup of tea or coffee ☕️, and let's dive right in! 🚀</p>
<h2 id="heading-how-to-install-pnpm">How to Install pnpm</h2>
<p>I assume you already have a modern version of Node.js installed on your machine. These modern versions come with a command called <code>corepack</code>. It let's you manage your Node package managers. </p>
<p>Yes you read that right! It's an experimental feature of Node but it works pretty well. </p>
<p>So to start using it, you first need to enable it by entering the following command from your terminal, which has the effect of installing pnpm (and also yarn) on your system:</p>
<pre><code class="lang-zsh">corepack <span class="hljs-built_in">enable</span>
</code></pre>
<p>It's that simple. Now if you run <code>pnpm --version</code> you will see the version you have just installed. But this might not be the latest version of pnpm. If this is the case, you can install the latest version of pnpm using this command:</p>
<pre><code class="lang-zsh">corepack prepare pnpm@latest --activate
</code></pre>
<p>Keep in mind that there are many ways to install pnpm on your system, and you can read about all of them in the <a target="_blank" href="https://pnpm.io/installation">installation docs</a>. My favorite is the <code>corepack</code> formula I've shown above.</p>
<h2 id="heading-how-to-configure-your-shell-for-efficiency-optional">How to Configure your Shell for Efficiency (Optional)</h2>
<p>Well, you now have pnpm installed. But the default command line experience can be improved to save you some effort. </p>
<p>Note that this section is optional. If you want you can skip to the next section. But if you are serious about setting it up so that the CLI experience is pleasant, let's learn how to do it.</p>
<h3 id="heading-pnpm-is-hard-to-type-so-set-up-an-alias"><code>pnpm</code> is Hard to Type – So Set Up an Alias</h3>
<p>If you find <code>pnpm</code> hard to type like I do, you can set up an alias to to save you some effort. If you're on Linux or MacOS, just put the following in your shell config (<code>.bashrc</code>, <code>.zshrc</code>, or <code>config.fish</code>):</p>
<pre><code>alias pn=pnpm
</code></pre><p>If you want to set up your alias in Powershell (Windows) you can <a target="_blank" href="https://pnpm.io/installation#adding-a-permanent-alias-in-powershell-windows">see this doc</a>.</p>
<h3 id="heading-how-to-setup-tab-completion">How to Setup Tab-Completion</h3>
<p>There are two ways you can do this in pnpm. Both have their pros and cons.</p>
<p>First I will share with you my favorite method. It's a shell plugin called <code>pnpm-shell-completion</code> and is available for zsh, fish shell, and Powershell core. It only covers the most commonly used commands. If you are Arch Linux and zsh user, you can install it with any AUR helper. For example, if you use <code>yay</code>, run the following command to install it:</p>
<pre><code class="lang-zsh">yay -S pnpm-shell-completion
</code></pre>
<p>Then add the following line in your <code>.zshrc</code> file to load it:</p>
<pre><code class="lang-zsh"><span class="hljs-built_in">source</span> /usr/share/zsh/plugins/pnpm-shell-completion/pnpm-shell-completion.zsh
</code></pre>
<p>Now it should work. If you use any other supported shell, follow the plugin's <a target="_blank" href="https://github.com/g-plane/pnpm-shell-completion">doc</a> to learn how to install it.</p>
<p>The second method comes built-in with pnpm. To setup this style of auto-completion, run the following command:</p>
<pre><code class="lang-shell">pnpm install-completion
</code></pre>
<p>And then follow the steps it gives you. This method covers more commands than the first approach. But it has some limitations – for example it can't auto-complete your <code>package.json</code> scripts. It also, for example, can't auto complete any dependency name that you want to uninstall.</p>
<h2 id="heading-how-to-use-pnpm">How to Use <code>pnpm</code></h2>
<p>Now, you should have pnpm installed with an alias and tab-completion. No more delay – let's see how to use pnpm.</p>
<h3 id="heading-how-to-initialize-a-new-project-using-pnpm">How to Initialize a New Project using <code>pnpm</code></h3>
<p>To get the default <code>package.json</code> in the current directory, run the following command:</p>
<pre><code class="lang-zsh">pnpm init
</code></pre>
<p>Unlike npm, it will not create it interactively and you don't need to specify the <code>-y</code> flag for this.</p>
<h3 id="heading-how-to-install-a-package">How to Install a Package</h3>
<p>To install a package as a dependency, the syntax is:</p>
<pre><code>pnpm add &lt;pkg&gt;
</code></pre><p>To install a package as a dev dependency, you have pass the <code>-D</code> (or <code>--save-dev</code>) flag:</p>
<pre><code>pnpm add -D &lt;pkg&gt;
</code></pre><p>To install a package globally, use the <code>-g</code> flag:</p>
<pre><code>pnpm add -g &lt;pkg&gt;
</code></pre><h3 id="heading-how-to-install-all-dependencies">How to Install All Dependencies</h3>
<p>Suppose you cloned a project from GitHub. It does have a <code>package.json</code> file but no <code>node_modules</code> (you should not track <code>node_modules</code> with Git). Now to install all the dependencies in that <code>package.json</code>, the command is very similar to <code>npm</code>:</p>
<pre><code>pnpm install
</code></pre><p>or</p>
<pre><code>pnpm i
</code></pre><h3 id="heading-how-to-run-a-packagejson-script">How to Run a <code>package.json</code> Script</h3>
<p>This process is also very similar to <code>npm</code>. The explicit way to do it is to use the <code>run</code> command. If you have a script named <code>build</code>, you can execute it with this command:</p>
<pre><code>pnpm run build
</code></pre><p>You can also use <code>pnpm build</code> to do the same thing. This is a shorthand format that can do other things as well. We'll learn more about shorthand very soon in this article.</p>
<h3 id="heading-how-to-run-commands-that-come-with-dependencies">How to Run Commands that Come with Dependencies</h3>
<p>You can run commands that come with dependencies using <code>pnpm exec</code>.</p>
<p>When you install a package, if it has commands specified by the <code>bin</code> field in its <code>package.json</code>, you will get an executable of the same name in your <code>node_modules/.bin</code> directory. Its purpose to execute the corresponding file.</p>
<p><code>pnpm exec</code> prepends <code>./node_modules/.bin</code> to the <code>PATH</code> (that is, <code>PATH=./node_modules/.bin:$PATH</code>) and then executes the given command.</p>
<p>The following is an example that shows installing <code>typescript</code> as a dev dependency and then running the <code>tsc</code> command to create a <code>tsconfig.json</code> file:</p>
<pre><code>pnpm add -D typescript
pnpm exec tsc --init
</code></pre><p>Similar to the <code>pnpm run</code> command, you can also omit <code>exec</code> and just use <code>pnpm tsc</code> to do the same thing. This works when you don't have a conflicting <code>tsc</code> script in your <code>package.json</code>. In the next section we will take a close look at this shorthand syntax.</p>
<p>Note that since <code>pnpm exec</code> has access to all commands resolved by the paths specified in <code>PATH</code>, you may have access to many system commands for example <code>rm</code>, <code>ls</code>, and so on.</p>
<h3 id="heading-how-pnpm-works">How <code>pnpm &lt;command&gt;</code> Works</h3>
<p><code>pnpm &lt;command&gt;</code> works like this:</p>
<ul>
<li>If <code>&lt;command&gt;</code> is a pnpm command (that is <code>add</code>, <code>install</code> and so on), execute that command.</li>
<li>Else if <code>&lt;command&gt;</code> is a script found in <code>package.json</code>, execute <code>pnpm run &lt;command&gt;</code>.</li>
<li>Else execute <code>pnpm exec &lt;command&gt;</code>.</li>
</ul>
<p>So <code>pnpm &lt;command&gt;</code> serves as a convenient shortcut where <code>pnpm exec</code> and <code>pnpm run</code> are explicit commands without fallback.</p>
<h3 id="heading-how-to-update-packages">How to Update Packages</h3>
<p>To update packages to their latest versions based on the specified range in <code>package.json</code>, run this command:</p>
<pre><code>pnpm up
</code></pre><p>To update all dependencies to their latest versions, ignoring ranges specified in <code>package.json</code>, run this:</p>
<pre><code>pnpm up --latest
</code></pre><h3 id="heading-how-to-remove-a-package">How to Remove a Package</h3>
<p>To remove a package from both <code>node_modules</code> and your <code>package.json</code>, you can use <code>pnpm rm</code>. For example if you installed <code>express</code>, you can remove it using:</p>
<pre><code>pnpm rm express
</code></pre><p>To remove a globally installed package, use the <code>-g</code> flag. Below is an example of removing the globally installed package <code>nodemon</code>:</p>
<pre><code>pnpm rm -g nodemon
</code></pre><h2 id="heading-is-there-an-npx-alternative">Is There an <code>npx</code> Alternative?</h2>
<p>Yes – it's the <code>pnpm dlx</code> command. It's very similar to npx. It downloads the specified package from the registry without installing it as a dependency and then runs whatever default command binary it exposes.</p>
<p>For example, you can run the command that <code>cowsay</code> package exposes like below to print ASCII art of a cow saying a string that you pass:</p>
<pre><code>pnpm dlx cowsay hi freeCodeCamp
</code></pre><p>Now you might be wondering, if a package exposes multiple command binaries, what command <code>pnpm dlx</code> chooses as the default? Or how can you explicitly specify a command binary?</p>
<p>Let's see how the default command binary is determined first:</p>
<ul>
<li>If the <code>bin</code> field of <code>package.json</code> has only one entry, then that is used.</li>
<li>Else if there is a command name in the <code>bin</code> field of <code>package.json</code> that matches the package name, ignoring the scope part if any, then that command is used.</li>
<li>Else pnpm can't determine the default command and throws an error with a helpful error message that most likely will answer the second question.</li>
</ul>
<p>To explicitly specify a particular command, you will need to install the package first using the <code>--package</code> option and specify that command after <code>dlx</code>. </p>
<p>For example the package <code>typescript</code> exposes to command binaries <code>tsc</code> and <code>tsserver</code>. Now if you want to run <code>tsc --init</code> to create a <code>tsconfig.json</code> file without having <code>typescript</code> in your <code>node_modules</code> or <code>package.json</code>, you can use <code>pnpm dlx</code> like below:</p>
<pre><code>pnpm --package=typescript dlx tsc --init
</code></pre><h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you've learned what pnpm is and how to install it. We've also covered several common pnpm commands that you will most likely need on a daily basis. </p>
<p>I hope this article helped you get up and running with pnpm. Check out the <a target="_blank" href="https://pnpm.io/motivation">documentation of pnpm</a> to learn more about it.</p>
<p>If you want you can follow me on <a target="_blank" href="https://www.linkedin.com/in/ashutosh-biswas/">LinkedIn</a> and <a target="_blank" href="https://twitter.com/ashutoshbw">Twitter</a> where I share useful coding related things.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ MERN Stack Roadmap – How to Learn MERN and Become a Full-Stack Developer ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever wondered how modern web applications are built? How you can learn and master the technologies that you can use to build your own full stack projects from scratch? In this handbook, I'm going to introduce you to the MERN stack, a widely-... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/mern-stack-roadmap-what-you-need-to-know-to-build-full-stack-apps/</link>
                <guid isPermaLink="false">66c8c8f7fe21816c4cb75d21</guid>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chris Blakely ]]>
                </dc:creator>
                <pubDate>Thu, 04 Jan 2024 00:57:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/Copy-of-mern-stack-hotel-booking-website--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever wondered how modern web applications are built? How you can learn and master the technologies that you can use to build your own full stack projects from scratch?</p>
<p>In this handbook, I'm going to introduce you to the MERN stack, a widely-used technology stack embraced by many leading companies. I'll guide you through 7 essential steps to start learning these technologies on your own. </p>
<p>By the time you finish reading, you'll have a solid understanding of what the MERN stack entails, its component technologies, and various resources for learning. You'll also have 10 project ideas that you can develop and showcase in your portfolio.</p>
<h1 id="heading-table-of-contents">Table of Contents</h1>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-the-mern-stack">What is the MERN stack?</a></li>
<li><a class="post-section-overview" href="#heading-the-mern-stack-roadmap">The MERN Stack Roadmap</a><ul>
<li><a class="post-section-overview" href="#heading-step-1-learn-the-right-amount-of-html-javascript-and-css">STEP 1: Learn the right amount of HTML, JavaScript, and CSS</a></li>
<li><a class="post-section-overview" href="#heading-step-2-get-familiar-with-react">STEP 2: Get familiar with React</a></li>
<li><a class="post-section-overview" href="#heading-step-3-understand-rest-apis-and-how-a-backend-server-works-using-expressnode">STEP 3: Understand REST API's and how a backend server works using Express/Node</a></li>
<li><a class="post-section-overview" href="#heading-step-4-storing-data-with-mongodb-and-mongoose">STEP 4: Storing data with MongoDB and Mongoose</a></li>
<li><a class="post-section-overview" href="#heading-step-5-writing-tests">STEP 5: Writing tests</a></li>
<li><a class="post-section-overview" href="#heading-step-6-using-git">STEP 6: Using Git</a></li>
<li><a class="post-section-overview" href="#heading-step-7-deployments">STEP 7: Deployments</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-top-resources-to-learn-the-mern-stack">Top Resources to learn the MERN Stack</a></li>
<li><a class="post-section-overview" href="#heading-10-project-ideas-you-can-try-today">10 project ideas you can try today</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up-the-mern-stack-journey">Wrapping up the MERN stack journey</a></li>
</ol>
<h2 id="heading-what-is-the-mern-stack">What is the MERN stack?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/MERN-Stack-wallpaper-gigapixel-hq-scale-6_00x.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The MERN stack, comprising MongoDB, Express.js, React, and Node.js, is a cohesive set of technologies used for building efficient and scalable web applications. </p>
<p>Its popularity stems from the seamless integration of each component: MongoDB's flexible data handling, Express.js's efficient server-side networking, React's dynamic user interfaces, and Node.js's powerful back-end runtime environment. </p>
<p>For beginners, the MERN stack is a smart choice because it uses JavaScript across all layers, simplifying the learning curve. This uniformity, coupled with a strong community and ample learning resources, makes it an accessible and practical toolkit for anyone looking to dive into full-stack development.</p>
<p>The MERN stack is also heavily utilized in the industry, favored by startups and large enterprises alike for its efficiency and the robust, modern web applications it can produce. This industry adoption not only validates its effectiveness but also opens up numerous career opportunities for those skilled in these technologies.</p>
<p>Let's look at a brief overview of what each part of the MERN Stack looks like:</p>
<h3 id="heading-frontend-react">Frontend (React)</h3>
<p>The frontend of a website is like the dining area of a restaurant. It's everything you see and interact with directly on a website – the layout, design, buttons, and text.  </p>
<p><strong>Example</strong>: When you visit a website and see a beautiful homepage, interact with menus, or fill out forms, you're experiencing the frontend.</p>
<h3 id="heading-backend-nodejs">Backend (Node.js)</h3>
<p>The backend is like the kitchen in a restaurant. It's where all the behind-the-scenes work happens. It includes the server, applications, and databases that work together to process the information you see on the frontend.  </p>
<p><strong>Example</strong>: When you order food (submit a form on the website), the kitchen (backend) processes the order (the data) and prepares your meal (the information or service you requested).</p>
<h3 id="heading-database-mongodb">Database (MongoDB)</h3>
<p>A database in web development is similar to a restaurant’s pantry or storage where all the ingredients (data) are kept. It stores and manages all the information needed by the website, like user profiles, content, and other data.  </p>
<p><strong>Example</strong>: In an online store, the database stores product information, prices, user reviews, and customer details.</p>
<h3 id="heading-rest-apis-express">REST APIs (Express)</h3>
<p>REST APIs are like the waiters in a restaurant. They are the messengers or go-betweens for the frontend and backend. They take requests (like orders) from the frontend (customer), fetch or update data in the backend (kitchen), and then return responses (prepared orders). </p>
<p>The terms POST, PUT, DELETE, and GET are types of requests used in REST APIs:</p>
<ul>
<li><strong>POST</strong>: Used to create new data. Like placing a new order in the restaurant.</li>
<li><strong>PUT</strong>: Used to update existing data. Similar to changing an order you've already placed.</li>
<li><strong>DELETE</strong>: Used to remove data. Like cancelling an order.</li>
<li><strong>GET</strong>: Used to retrieve data. Comparable to asking about the menu or checking the status of your order.</li>
</ul>
<h2 id="heading-the-mern-stack-roadmap">The MERN Stack Roadmap</h2>
<h3 id="heading-step-1-learn-the-right-amount-of-html-javascript-and-css">STEP 1: Learn the right amount of HTML, JavaScript, and CSS</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/b59a78e2ed76c705f3c0dcb300f3f222aefdcd99-gigapixel-hq-scale-6_00x.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The MERN stack uses JavaScript heavily, so its a natural first step to learn. In this section you will look at the main things you will use day-to-day when creating full-stack MERN apps. </p>
<p>Understanding JavaScript is like knowing the right amount of ingredients needed for a recipe. You don't need to master everything at once, just the essential ingredients that make your particular dish (or your web project) come to life.</p>
<h3 id="heading-variables">Variables</h3>
<p><a target="_blank" href="https://www.freecodecamp.org/news/javascript-variables-beginners-guide/">Variables in JavaScript</a> are like labelled jars in your kitchen. You can store things in them (like numbers, text) and use these jars later in your cooking (or coding).</p>
<p><strong>Example</strong>: A variable storing the user's name, so you can use it later to say "Hello, [Name]!"</p>
<h3 id="heading-functions">Functions</h3>
<p><a target="_blank" href="https://www.freecodecamp.org/news/javascript-functions-and-scope/">Functions</a> are like recipes in a cookbook. They are sets of instructions that perform a specific task. You can reuse these recipes whenever you need to perform that task again.</p>
<p><strong>Example</strong>: A function that calculates the total price of items in a shopping cart.</p>
<h3 id="heading-objects-amp-arrays">Objects &amp; Arrays</h3>
<p><a target="_blank" href="https://www.freecodecamp.org/news/javascript-basics-strings-arrays-objects/">Objects</a> are like information cards holding details about something (like a contact card), and arrays are like lists.  </p>
<p><strong>Example of an Object</strong>: A card holding a user's information (name, age, email).<br><strong>Example of an Array</strong>: A list of all the user's favorite book titles.</p>
<h3 id="heading-ifelse-statements-switch-statements">If/else Statements, Switch Statements</h3>
<p>These are like decision-making processes. <a target="_blank" href="https://www.freecodecamp.org/news/javascript-if-else-and-if-then-js-conditional-statements/">If/else statements</a> are like choosing what to wear based on the weather, and switch statements are like a more complex decision, like choosing what to cook based on multiple ingredients you have.  </p>
<p><strong>Example</strong>: If it's raining (if), take an umbrella (else), take sunglasses.</p>
<h3 id="heading-callbackspromisesasync-await">Callbacks/Promises/Async Await</h3>
<p>These are ways to handle tasks that take some time, like ordering food and waiting for it. <a target="_blank" href="https://www.freecodecamp.org/news/what-is-a-callback-function-in-javascript-js-callbacks-example-tutorial/">Callbacks</a> are like calling a friend to do something when they’re free. <a target="_blank" href="https://www.freecodecamp.org/news/javascript-promises-async-await-and-promise-methods/">Promises</a> are like your friend promising to do it. <a target="_blank" href="https://www.freecodecamp.org/news/javascript-async-await/">Async-await</a> is like making a plan to do tasks one after another in an organized way.  </p>
<p><strong>Example</strong>: Ordering a coffee (a task) and waiting to get it before leaving the cafe (ensuring order of actions).</p>
<h3 id="heading-ecmascript-template-strings-destructuring-assignment-spread-operator-default-parameters-and-so-on">ECMAScript (Template Strings, Destructuring Assignment, Spread Operator, Default Parameters, and so on)</h3>
<p>These are advanced tools and shortcuts in JavaScript to make coding easier and cleaner. It's like having a food processor in your kitchen that makes chopping and mixing faster and more efficient.  </p>
<p><strong>Example</strong>: Automatically creating a welcome message like "Hello, [Name]!" without manually joining words and variables.</p>
<h3 id="heading-typescript">TypeScript</h3>
<p><a target="_blank" href="https://www.freecodecamp.org/news/typescript-tutorial-for-react-developers/">TypeScript</a> is like JavaScript but with more rules for organizing your code (like a more detailed recipe book). It helps in managing larger projects by adding types to your code, making sure you don’t mix incompatible ingredients. <a target="_blank" href="https://www.freecodecamp.org/news/learn-typescript-beginners-guide/">This guide</a> teaches you TypeScript basics.  </p>
<p><strong>Example</strong>: Specifying that a function should only take a number as an input, not text or anything else. </p>
<h2 id="heading-step-2-get-familiar-with-react">STEP 2: Get Familiar with React</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/communityIcon_4g1uo0kd87c61.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Once you've got a feel for JavaScript, its time to venture into the wonderful world of frontend development. </p>
<p>React.js is a popular JavaScript library used for building user interfaces, particularly known for its efficiency in rendering dynamic, interactive web pages. It enables developers to create large web applications that can change data, without reloading the page, making for a smoother user experience.</p>
<p>Below is a list of common things you want to know when working with React.</p>
<h3 id="heading-components">Components</h3>
<p>Think of <a target="_blank" href="https://www.freecodecamp.org/news/how-to-use-react-components/">components</a> as individual LEGO blocks in a large LEGO model. Each block is a small, reusable piece that you can use to build different parts of your web application.  </p>
<p><strong>Example</strong>: A 'button' component in a website that can be used in many places, like for submitting a form or closing a pop-up.</p>
<h3 id="heading-jsx-javascript-xml">JSX (JavaScript XML)</h3>
<p><a target="_blank" href="https://www.freecodecamp.org/news/jsx-in-react-introduction/">JSX</a> lets you write your website's design code (like HTML) inside your JavaScript code. It's like writing the recipe and the cooking instructions in one place for easier reference.  </p>
<p><strong>Example</strong>: Writing a piece of JSX code that includes both JavaScript and HTML-like tags to create a user login form.</p>
<h3 id="heading-props-properties">Props (Properties)</h3>
<p><a target="_blank" href="https://www.freecodecamp.org/news/props-in-react/">Props are like instructions</a> or settings you pass to your LEGO blocks (components) to tell them what they should look like or do.  </p>
<p><strong>Example</strong>: Passing a 'color' prop to a 'button' component to make it red or blue depending on the situation.</p>
<h3 id="heading-state">State</h3>
<p><a target="_blank" href="https://www.freecodecamp.org/news/usestate-vs-redux-state-management/">State</a> is like a personal notebook for each component, where it keeps track of its own information, like whether a button is clicked or not. Here's a course all about <a target="_blank" href="https://www.freecodecamp.org/news/how-to-manage-state-in-react/">state management in React</a>.</p>
<p><strong>Example</strong>: A 'like' button keeping track of whether it has been clicked (liked) or not.</p>
<h3 id="heading-hooks">Hooks</h3>
<p><a target="_blank" href="https://www.freecodecamp.org/news/react-hooks-useeffect-usestate-and-usecontext/">Hooks are special tools in React</a> that let you add features like state to your components without needing to use complex code structures.</p>
<p><strong>Example</strong>: Using the useState hook to keep track of a counter in a component.</p>
<h3 id="heading-event-handling">Event Handling</h3>
<p>This is how you tell a component to do something when a user interacts with it, like clicking a button or entering text in a form.  </p>
<p><strong>Example</strong>: Setting up an event handler so that when a user clicks a 'submit' button, it sends their information to the server.</p>
<h3 id="heading-conditional-rendering">Conditional Rendering</h3>
<p>This is like having a magic painting that can change its picture based on certain conditions. In React, you can <a target="_blank" href="https://www.freecodecamp.org/news/react-conditional-rendering/">show different components based on different conditions</a>.</p>
<p><strong>Example</strong>: Showing a 'login' button if a user is not logged in, and a 'logout' button if they are.</p>
<h3 id="heading-lists-and-keys">Lists and Keys</h3>
<p>Keys are like name tags for items in a list. They help React keep track of which items are new, changed, or removed.  </p>
<p><strong>Example</strong>: Displaying a list of messages in a chat app, where each message has a unique key.</p>
<h3 id="heading-context-api">Context API</h3>
<p><a target="_blank" href="https://www.freecodecamp.org/news/context-api-in-react/">The Context API</a> a way to share information (like a theme setting or user data) across many components without passing the information through each level manually.</p>
<p><strong>Example</strong>: Using Context API to share the current logged-in user's information across different components in a web app.</p>
<h3 id="heading-fragment">Fragment</h3>
<p>Fragments let you group several components or elements together without adding extra layers to the website. It's like putting multiple LEGO pieces on a baseplate without the baseplate being part of the final model.</p>
<p><strong>Example</strong>: Grouping a list of items together in a menu without adding extra wrappers or divs around them.</p>
<h2 id="heading-step-3-understand-rest-apis-and-how-a-backend-server-works-using-expressnode">STEP 3: Understand REST API's and how a backend server works using Express/Node</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/express-and-node-opengraph-v1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Every UI needs a way to store and retrieve the data it needs to make the frontend work. This is where our backend comes in. </p>
<p>In the MERN stack, the backend is composed of 3 main bits: Express, a Node.js server, and a database. We'll cover the database shortly, for now we'll focus on the Express/Node pieces of the MERN stack, as they're closely related.  </p>
<p>Express.js is a lightweight, flexible framework for Node.js, designed to build web applications and <a target="_blank" href="https://www.freecodecamp.org/news/build-consume-and-document-a-rest-api/">REST APIs</a> with ease and efficiency. Node.js is a powerful JavaScript runtime that allows for the development of scalable server-side applications, making the duo a popular choice for backend development.</p>
<h3 id="heading-nodejs-foundation-for-building-web-applications">Node.js: Foundation for Building Web Applications</h3>
<p>Think of Node.js as the foundation for constructing a modern building. It's a platform that lets you build web applications, similar to how you would use a set of basic tools and materials to start building a house. You might hear this being to referred to as the "backend".  </p>
<p><strong>Example</strong>: Building a chat application where multiple users can send messages in real-time.</p>
<h3 id="heading-express-streamlining-rest-api-development">Express: Streamlining REST API Development</h3>
<p>Express is a helper tool for Node.js. It's like having a pre-built kit that makes building certain parts of your house easier and faster, providing templates and shortcuts so you don't have to start from scratch. </p>
<p><strong>Example</strong>: Using Express to quickly set up routes for a website, like a route to a contact page or a product catalog.</p>
<h3 id="heading-modules-and-packages-ready-made-components">Modules and Packages: Ready-Made Components</h3>
<p>In Node.js, modules are like pre-made components or sections of a house (like a bathroom unit or a kitchen set) that you can simply choose and add to your building project.</p>
<p><strong>Example</strong>: Adding a 'date-time' module to display current times and dates on your web application.</p>
<h3 id="heading-node-package-manager-npm-the-tool-and-material-warehouse">Node Package Manager (NPM): The Tool and Material Warehouse</h3>
<p>NPM acts like a vast warehouse where you can find all sorts of tools and materials (modules) you might need. It's a central place to get additional resources for building your web applications.</p>
<p><strong>Example</strong>: Installing 'body-parser' from npm to handle JSON data in your web application.</p>
<h3 id="heading-routing-directing-web-traffic">Routing: Directing Web Traffic</h3>
<p>Routing in Express is like setting up roads and paths in a housing complex. It's about directing the flow of traffic (data and user requests) to different parts of your web application.</p>
<p><strong>Example</strong>: Creating routes in an online store, like <code>/products</code> for the product list and <code>/products/:id</code> for individual product details.</p>
<h3 id="heading-middleware-additional-functional-layers">Middleware: Additional Functional Layers</h3>
<p>Middleware in Express can be seen as extra layers or services in your building, like security, plumbing, or electrical systems. They add specific functionalities to your web application.</p>
<p><strong>Example</strong>: Adding 'cookie-parser' middleware to handle cookies in your web application.</p>
<h3 id="heading-request-and-response-communication-channels">Request and Response: Communication Channels</h3>
<p>Requests and responses in Express are like sending and receiving mail or messages. They are the way your web application communicates with users, sending them data or receiving their inputs.</p>
<p><strong>Example</strong>: Your application receiving a user's login request (request) and then sending back a confirmation message (response).</p>
<h3 id="heading-environment-variables-secure-storage-spaces">Environment Variables: Secure Storage Spaces</h3>
<p>Think of environment variables as secure storage spaces or safes in your building. They're used to store sensitive information like passwords or personal settings, keeping them secure and separate from the main construction.</p>
<p><strong>Example</strong>: Storing the database connection string in an environment variable to keep it secure.</p>
<h3 id="heading-security-building-safeguards">Security: Building Safeguards</h3>
<p>In the context of web applications, security is about building safeguards into your project. It's like installing locks, security systems, and fire safety measures in a building to protect it from various threats.</p>
<p><strong>Example</strong>: Implementing HTTPS to secure data transmission and using JWT (JSON Web Tokens) for user authentication to protect user data.</p>
<h2 id="heading-step-4-storing-data-with-mongodb-and-mongoose">STEP 4: Storing data with MongoDB and Mongoose</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/MongoDB_Logo.svg.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>MongoDB is a NoSQL database that offers high flexibility and scalability for storing and managing data, making it ideal for handling large volumes and diverse types of data. </p>
<p>Mongoose is an Object Data Modeling (ODM) library for MongoDB, providing a straightforward schema-based solution to model application data, enhancing database interaction with useful features and validation.</p>
<h3 id="heading-mongodb-a-nosql-database">MongoDB: A NoSQL Database</h3>
<p>MongoDB is a type of database that stores data in a flexible, JSON-like format. This makes it different from traditional databases, which use tables and rows. It's great for handling large volumes of data and is very scalable.</p>
<p><strong>Example</strong>: Using MongoDB to store user profiles where each profile can have different fields.</p>
<h3 id="heading-collections-and-documents">Collections and Documents</h3>
<p>In MongoDB, data is stored in 'collections', which are similar to tables in a relational database. Inside these collections, data is stored in 'documents'. Think of a document as a single record in your collection, like an entry in a diary or a contact in an address book.</p>
<p><strong>Example</strong>: A 'users' collection with documents each representing a user with details like name and email.</p>
<h3 id="heading-mongoose-a-mongodb-object-modeling-tool">Mongoose: A MongoDB Object Modeling Tool</h3>
<p>Mongoose is a library for Node.js that makes it easier to interact with MongoDB. It provides a straightforward, schema-based solution to model your application data. It's like having a personal assistant to help manage the communication between your application and MongoDB.</p>
<p><strong>Example</strong>: Using Mongoose to easily add, retrieve, and manage user data in a MongoDB database.</p>
<h3 id="heading-schemas">Schemas</h3>
<p>In Mongoose, a schema is a structure that defines the format of the data to be stored in MongoDB (like defining fields and data types). Think of it as a blueprint for how your data should look.</p>
<p><strong>Example</strong>: Creating a Mongoose schema for a blog post with fields like title, author, and content.</p>
<h3 id="heading-models">Models</h3>
<p>A model in Mongoose acts as a constructor, compiled from the Schema definitions. It represents documents in a MongoDB database. Models are responsible for creating and reading documents from the underlying MongoDB database.</p>
<p><strong>Example</strong>: Defining a 'User' model based on a user schema to interact with the 'users' collection in the database.</p>
<h3 id="heading-crud-operations">CRUD Operations</h3>
<p>CRUD stands for Create, Read, Update, Delete. These are the basic operations you can perform on the database. Mongoose provides easy methods to execute these operations on your data.</p>
<p><strong>Example</strong>: Using Mongoose methods to add new users, find users by name, update user information, or delete users.</p>
<h3 id="heading-connecting-to-mongodb">Connecting to MongoDB</h3>
<p>You can use Mongoose to connect your Node.js application to a MongoDB database. This is like setting up a phone line between your application and the database so they can talk to each other.</p>
<p><strong>Example</strong>: Writing a Mongoose connect function to link your Node.js application to a MongoDB database hosted on Atlas.</p>
<h3 id="heading-querying-data">Querying Data</h3>
<p>Mongoose allows you to query your MongoDB database. This means you can search for specific data, filter your data based on certain criteria, and more.</p>
<p><strong>Example</strong>: Using a Mongoose query to find all blog posts written by a specific author.</p>
<h3 id="heading-data-validation">Data Validation</h3>
<p>Mongoose provides built-in validation. This is a way to make sure the data being saved to your database is in the right format, like checking if an email address looks like an email address.</p>
<p><strong>Example</strong>: Defining a schema in Mongoose where the email field must match the format of an email address.</p>
<h3 id="heading-middleware-pre-and-post-hooks">Middleware (Pre and Post Hooks)</h3>
<p>Mongoose middleware are functions which can be executed automatically before or after certain operations, like saving a document. They're useful for complex logic like hashing passwords before saving them to the database.</p>
<p><strong>Example</strong>: Using a pre-save middleware in Mongoose to hash user passwords before saving them to the database.</p>
<h3 id="heading-indexes">Indexes</h3>
<p>Indexes in MongoDB are used to improve the performance of searches. They are similar to indexes in a book, helping the database find data faster.</p>
<p><strong>Example</strong>: Creating an index on the 'email' field in a user collection to speed up the search for users by email.</p>
<h3 id="heading-aggregation">Aggregation</h3>
<p>Aggregation in MongoDB is a powerful way to process data and get computed results. It's like having a sophisticated calculator to perform complex operations on your data, such as summing up values or averaging them.</p>
<p><strong>Example</strong>: Using MongoDB's aggregation framework to calculate the average number of comments on blog posts.</p>
<h2 id="heading-step-5-writing-tests">STEP 5: Writing Tests</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/opengraph.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Testing in software development is like a safety check to ensure everything in your application works as expected. It's a crucial step in the development process where you look for bugs or issues before your users do. Think of it like proofreading an essay or checking a car before a road trip – it helps catch and fix problems early.</p>
<p>There are different types of testing, each serving a unique purpose:</p>
<h3 id="heading-unit-testing">Unit Testing</h3>
<p>This is the most basic form of testing. Here, you test individual parts of your code (like functions or components) in isolation. It's like checking each light bulb in a string of Christmas lights. </p>
<p>In the MERN stack, tools like Jest or Mocha are commonly used for this. They let you write small tests to check if a specific part of your application behaves as expected.</p>
<h3 id="heading-integration-testing">Integration Testing</h3>
<p>This type of testing checks how different parts of your application work together. It's like making sure all the light bulbs light up when connected and the string is plugged in. </p>
<p>For the MERN stack, you might still use Jest or Mocha, combined with other tools like Chai for assertions, to ensure that different components or services in your application interact correctly.</p>
<h3 id="heading-end-to-end-e2e-testing">End-to-End (E2E) Testing</h3>
<p>Here, you test your application's workflow from start to finish. It's like checking if the entire Christmas tree lights up and twinkles as expected. </p>
<p>For a MERN stack application, Cypress or Selenium are popular choices. They simulate real user scenarios, ensuring the entire application, from the front end in React to the back end with Express and Node.js, functions smoothly together.</p>
<h3 id="heading-performance-testing">Performance Testing</h3>
<p>This checks if your application can handle stress, like heavy traffic or data processing. It's akin to ensuring the Christmas tree lights don't blow a fuse when they're all on. Tools like Loader.io or Apache JMeter can be used here.</p>
<p>Each type of testing serves to ensure a different aspect of your application is working correctly, and together, they contribute to building a robust, reliable, and user-friendly application. </p>
<p>By employing these tests in the MERN stack, you not only catch bugs early but also maintain a high standard of quality for your application.</p>
<h2 id="heading-step-6-using-git">STEP 6: Using Git</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/629b7adc7c5cd817694c3231.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Git is a version control system, a tool that tracks changes in your code over time. Think of it like a detailed diary for your coding project. Every time you make changes to your code, Git keeps a record of what was changed, when, and by whom. This becomes incredibly useful when you’re working on complex projects, like those involving the MERN stack.</p>
<p>Why is Git so important when building with the MERN stack, or any software for that matter? </p>
<h3 id="heading-collaboration">Collaboration</h3>
<p>Git is like a team playbook. It allows multiple developers to work on the same project without stepping on each other's toes. </p>
<p>Everyone can work on different features or parts of the application simultaneously (like MongoDB database schemas, React components, or Express.js routes). Git helps manage these contributions, ensuring changes can be merged smoothly into the main project.</p>
<h3 id="heading-tracking-changes">Tracking Changes</h3>
<p>Imagine you've made changes to your React component, and suddenly things aren't working as they used to. Git allows you to go back in time and see what changes were made and by whom. </p>
<p>This historical data is invaluable for understanding how your project evolved and for fixing issues without having to start from scratch.</p>
<h3 id="heading-branching-and-merging">Branching and Merging</h3>
<p>Git’s branching feature lets you diverge from the main line of development and experiment with new features or ideas in a controlled way. </p>
<p>You can create a branch, make your changes, and then merge those changes back into the main project when they're ready. This ensures the main project (often referred to as the 'master' or 'main' branch) remains stable.</p>
<h3 id="heading-backup-and-restore">Backup and Restore</h3>
<p>With Git, your project's entire history is stored in the repository. If anything goes wrong, you can roll back to a previous state. It’s like having a fail-safe backup system.</p>
<h3 id="heading-documentation">Documentation</h3>
<p>Commit messages in Git provide a narrative for your project. They allow you to document what changes were made and why, which is extremely helpful for both your future self and other developers who might work on the project.</p>
<p>When building applications with the MERN stack, Git offers a safety net and a collaborative workspace. It keeps your project organized, tracks every change, and allows multiple developers to work together more efficiently. </p>
<p>Using Git is essential for managing complex development projects in today's software development world.</p>
<h2 id="heading-step-7-deployments">STEP 7: Deployments</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/img-blog-cico.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Code deployment is the process of taking code written by developers and making it operational on a live environment where users can interact with it. </p>
<p>In the context of the MERN stack, which involves technologies like MongoDB, Express.js, React, and Node.js, deployment is the final step in the journey of bringing a full-stack application to life.</p>
<p>Imagine you've built a house (your web application). Deployment is like moving it from the construction site (development environment) to its actual location where people can live in it (production environment). This process involves several key steps to ensure that everything works as expected when users access your app.</p>
<h3 id="heading-preparing-for-deployment">Preparing for Deployment</h3>
<p>Before deploying, you need to prepare your application. This involves ensuring your code is complete and tested, dependencies are properly managed, and your app is configured for the production environment. </p>
<p>For MERN stack applications, this might mean setting up environment variables, configuring your database (MongoDB) connection for production, and optimizing your React front-end for performance.</p>
<h3 id="heading-hosting-and-servers">Hosting and Servers</h3>
<p>Choosing where to host your application is crucial. For MERN stack apps, you can use cloud-based hosting services like AWS, Heroku, or DigitalOcean. These platforms offer services to host both your Node.js backend and MongoDB database, and they often provide additional features like scaling, monitoring, and security.</p>
<h3 id="heading-continuous-integrationcontinuous-deployment-cicd">Continuous Integration/Continuous Deployment (CI/CD)</h3>
<p>CI/CD is a methodology that automates the deployment process. Whenever you make changes to your codebase (like fixing a bug or adding a new feature), CI/CD tools automatically test your code and deploy it if the tests pass. This ensures that your application is always up-to-date with the latest changes. </p>
<p>Tools like Jenkins, Travis CI, or GitHub Actions are commonly used for this purpose.</p>
<h3 id="heading-monitoring-and-maintenance">Monitoring and Maintenance</h3>
<p>After deployment, it’s important to monitor your application for any issues and perform regular maintenance. This could involve checking server logs, updating dependencies, or rolling out fixes for any bugs that might arise.</p>
<h3 id="heading-rollbacks">Rollbacks</h3>
<p>A good deployment strategy also includes plans for rollbacks. If something goes wrong after deployment, you need to be able to revert to the previous version quickly to minimize downtime.</p>
<p>In the MERN stack, each component (MongoDB, Express.js, React, and Node.js) might require specific considerations for deployment. For instance, you might use Docker containers to package your Node.js and Express.js backend, ensuring it runs consistently across different environments. React apps might be minified and bundled for optimal performance.</p>
<p>In essence, deployment in the MERN stack is about getting your application from your local machine to a server where it can serve users reliably and efficiently. It involves careful planning, choosing the right hosting solutions, automating the process as much as possible, and being prepared to address issues post-deployment.</p>
<h2 id="heading-top-resources-to-learn-the-mern-stack">Top Resources to Learn the MERN Stack</h2>
<p>Now that you have a pretty good idea of what you need to learn to master the MERN stack, lets look at a list of free resources you can start using today to begin your journey!</p>
<ul>
<li>The <a target="_blank" href="https://www.freecodecamp.org/learn/">freeCodeCamp curriculum</a> is one of the best places to learn how to code for free. The curriculum is super in depth and covers alot of the topics mentioned in this post.</li>
<li>The freeCodeCamp YouTube channel has a ton of free courses you can try as well. <a target="_blank" href="https://www.youtube.com/watch?v=-42K44A1oMA&amp;t=2950s">This MERN stack book project is an excellent one for beginners</a>.</li>
<li><a target="_blank" href="https://fullstackopen.com/">Full Stack open</a> is another good resource. It doesn't teach MongoDB but you learn about SQL instead which is equally as useful.</li>
<li>My <a target="_blank" href="https://www.youtube.com/watch?v=YdBy9-0pER4">MERN stack hotel booking app project on YouTube is a free 15 hour course</a> where you will learn everything talked about in this post.</li>
</ul>
<h2 id="heading-10-project-ideas-you-can-try-today">10 Project Ideas You Can Try Today</h2>
<p>One of my favourite ways to learn new technologies is to build projects. If you're struggling with coming up with ideas, here's 10 projects you can start building today. I'll be building some of these on my <a target="_blank" href="https://www.youtube.com/@ChrisBlakely">YouTube channel</a> so feel free to subscribe to stay up to date!</p>
<h3 id="heading-personal-blog-website">Personal Blog Website</h3>
<ul>
<li><strong>Functionality</strong>: Users can read posts, and the admin can create, edit, or delete posts.</li>
<li><strong>Learning Focus</strong>: Basic CRUD operations, user authentication, integrating React with Express API, and using MongoDB for data storage.</li>
</ul>
<h3 id="heading-task-manager-to-do-list">Task Manager (To-Do List)</h3>
<ul>
<li><strong>Functionality</strong>: Users can add, view, edit, and delete tasks. Tasks can have deadlines and priority levels.</li>
<li><strong>Learning Focus</strong>: React state management, Express route handling, MongoDB operations, and basic UI development.</li>
</ul>
<h3 id="heading-simple-e-commerce-site">Simple E-commerce Site</h3>
<ul>
<li><strong>Functionality</strong>: Display products, add to cart, and checkout functionality. Admin features for adding or removing products.</li>
<li><strong>Learning Focus</strong>: React components for product listing, cart management, Express.js for product APIs, MongoDB for product data, and handling user inputs.</li>
</ul>
<h3 id="heading-recipe-sharing-application">Recipe Sharing Application</h3>
<ul>
<li><strong>Functionality</strong>: Users can post, view, edit, and delete recipes. Implement a rating or comment system for interaction.</li>
<li><strong>Learning Focus</strong>: File upload for images, user-generated content management, and MongoDB schema design.</li>
</ul>
<h3 id="heading-budget-tracker">Budget Tracker</h3>
<ul>
<li><strong>Functionality</strong>: Users can input their expenses and income, categorize them, and view a summary of their finances.</li>
<li><strong>Learning Focus</strong>: Handling forms in React, creating RESTful services with Express, and effective data structuring in MongoDB.</li>
</ul>
<h3 id="heading-event-planning-application">Event Planning Application:</h3>
<ul>
<li><strong>Functionality</strong>: Users can create and manage events, send invitations, and track RSVPs.</li>
<li><strong>Learning Focus</strong>: Date handling in JavaScript, complex MongoDB documents, and Express middleware for authentication.</li>
</ul>
<h3 id="heading-fitness-tracker">Fitness Tracker:</h3>
<ul>
<li><strong>Functionality</strong>: Log workouts, track progress over time, set fitness goals.</li>
<li><strong>Learning Focus</strong>: Data visualization with React, creating API endpoints for varied data types, and MongoDB for storing time-series data.</li>
</ul>
<h3 id="heading-chat-application">Chat Application:</h3>
<ul>
<li><strong>Functionality</strong>: Real-time chat rooms, private messaging, and user profiles.</li>
<li><strong>Learning Focus</strong>: WebSockets with Node.js for real-time communication, MongoDB for message storage, and React for dynamic UI updates.</li>
</ul>
<h3 id="heading-book-review-platform">Book Review Platform:</h3>
<ul>
<li><strong>Functionality</strong>: Users can post book reviews, rate books, and browse reviews by other users.</li>
<li><strong>Learning Focus</strong>: Integrating external APIs for book data, user-generated content moderation, and complex querying in MongoDB.</li>
</ul>
<h3 id="heading-local-business-directory">Local Business Directory:</h3>
<ul>
<li><strong>Functionality</strong>: Listing of local businesses with categories, user reviews, and contact information.</li>
<li><strong>Learning Focus</strong>: Geolocation, advanced querying and indexing in MongoDB, and creating a responsive layout with React.</li>
</ul>
<h2 id="heading-wrapping-up-the-mern-stack-journey">Wrapping Up the MERN Stack Journey</h2>
<p>As we reach the end of our exploration of the MERN stack, I hope this guide has illuminated the path for your journey into the world of full-stack development. </p>
<p>We've covered the fundamental components – MongoDB, Express.js, React, and Node.js – and delved into the practical aspects of building, testing, and deploying applications using this versatile stack.</p>
<p>Remember, the road to mastering the MERN stack is both challenging and rewarding. Each project you undertake will add to your skills and confidence. Use the resources and project ideas provided as stepping stones to build your portfolio and deepen your understanding. </p>
<p>The beauty of the MERN stack lies in its community-driven nature, so don't hesitate to seek help, collaborate, and share your experiences.  </p>
<p>If you want to get in touch, you can reach me over at <a target="_blank" href="https://www.linkedin.com/in/chrisblakely01/">LinkedIn</a>, or drop a comment on my <a target="_blank" href="https://www.youtube.com/@ChrisBlakely">YouTube channel</a>. Good luck and happy coding! </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/undefined" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Scrape Amazon Product Reviews Behind a Login ]]>
                </title>
                <description>
                    <![CDATA[ By Satyam Tripathi Amazon is the most popular e-commerce website for web scrapers, with billions of product pages being scraped every month.  It is also home to a vast database of product reviews, which can be very useful for market research and comp... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-scrape-amazon-product-reviews-behind-a-login/</link>
                <guid isPermaLink="false">66d461744bc8f441cb6df837</guid>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ puppeteer ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web scraping ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 30 Oct 2023 16:46:40 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/pexels-pixabay-159751--1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Satyam Tripathi</p>
<p>Amazon is the most popular e-commerce website for web scrapers, with billions of product pages being scraped every month. </p>
<p>It is also home to a vast database of product reviews, which can be very useful for market research and competitor monitoring. </p>
<p>You can extract relevant data from the Amazon website and save it in a spreadsheet or JSON format. And you can even automate the process to update the data regularly.</p>
<p>Scraping Amazon product reviews is not always straightforward, especially when a login is required. In this guide, you'll learn how to scrape Amazon product reviews behind a login. You’ll learn the process of logging in, parsing review data, and exporting reviews to CSV.</p>
<p><strong>Important Disclaimer:</strong> This tutorial is for educational purposes only. Scraping data from behind logins on websites may violate their terms and conditions (T&amp;Cs).  It's crucial to always check the T&amp;Cs of any website before scraping data.</p>
<p>Without further ado, let's get started.</p>
<h2 id="heading-prerequisites-and-project-setup">Prerequisites and Project Setup</h2>
<p>We’ll use the Node.js Puppeteer library to scrape Amazon reviews. Make sure Node.js is installed on your system. If it is not, go to the official <a target="_blank" href="https://nodejs.org/en">Node.js website</a> and install it. </p>
<p>After Node.js is installed, install Puppeteer. <a target="_blank" href="https://github.com/puppeteer/puppeteer">Puppeteer</a> is a Node.js library that provides a high-level, user-friendly API for automating tasks and interacting with dynamic web pages. </p>
<p>Now, let's install and configure Puppeteer.</p>
<p>Open a terminal and create a new folder with any name. (In my case, it is _amazon<em>reviews</em>).</p>
<pre><code class="lang-bash">mkdir amazon_reviews
</code></pre>
<p>Change your current directory to the folder created above.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> amazon_reviews
</code></pre>
<p>Cool, you're now in the correct directory. Execute the following command to initialize the <em>package.json</em> file:</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<p>Finally, install Puppeteer using the following command:</p>
<pre><code class="lang-bash">npm install puppeteer
</code></pre>
<p>This is what the process looks like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-070530.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, open the folder in any code editor, and create a new JavaScript file (index.js). Make sure that the hierarchy looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-070823.png" alt="Image" width="600" height="400" loading="lazy">
_Hierarchy showing <code>node_modules</code>, <code>index.js</code>, <code>package-lock.json</code>, and <code>package.json</code>_</p>
<p>All set up successfully. We’re now ready to code the scraper.</p>
<p><strong>Note:</strong> Ensure that you have an account on Amazon so you can progress through the rest of this tutorial.</p>
<h2 id="heading-step-1-get-access-to-the-public-page">Step 1: Get Access to the Public Page</h2>
<p>You're going to scrape the reviews of the product shown below. You’ll extract the author's name, review title, and date.</p>
<p>Here's the product URL: <a target="_blank" href="https://www.amazon.com/ENHANCE-Headphone-Customizable-Lighting-Flexible/dp/B07DR59JLP/">https://www.amazon.com/ENHANCE-Headphone-Customizable-Lighting-Flexible/dp/B07DR59JLP/</a></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-072923.png" alt="Image" width="600" height="400" loading="lazy">
<em>The product we're using in the example - headphones</em></p>
<p>First, you’ll log in to Amazon, and then redirect to the product URL to scrape the reviews.</p>
<h2 id="heading-step-2-scrape-behind-the-login">Step 2: Scrape Behind the Login</h2>
<p>Amazon's multi-stage login process requires users to enter their username or email, click a Continue button to enter their password, and then finally submit it. Both the username and password fields are typically on different pages.</p>
<p>To enter the email ID, use the selector <code>input[name=email]</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-082325.png" alt="Image" width="600" height="400" loading="lazy">
<em>HTML of the sign-in field</em></p>
<p>Now, click on the Continue button using the selector <code>input[id=continue]</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-083136.png" alt="Image" width="600" height="400" loading="lazy">
<em>HTML of the continue button</em></p>
<p>Now you should be on the next page. To enter the password, use the selector <code>input[name=password]</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-083415.png" alt="Image" width="600" height="400" loading="lazy">
<em>HTML of the password field</em></p>
<p>Finally, click on the Sign In button using the selector <code>input[id=signInSubmit]</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-083833.png" alt="Image" width="600" height="400" loading="lazy">
<em>HTML of the sign-in button</em></p>
<p>Here’s the code for the login process:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> selectors = {
  <span class="hljs-attr">emailid</span>: <span class="hljs-string">'input[name=email]'</span>,
  <span class="hljs-attr">password</span>: <span class="hljs-string">'input[name=password]'</span>,
  <span class="hljs-attr">continue</span>: <span class="hljs-string">'input[id=continue]'</span>,
  <span class="hljs-attr">singin</span>: <span class="hljs-string">'input[id=signInSubmit]'</span>,
};


    <span class="hljs-keyword">await</span> page.goto(signinURL);
    <span class="hljs-keyword">await</span> page.waitForSelector(selectors.emailid);
    <span class="hljs-keyword">await</span> page.type(selectors.emailid, <span class="hljs-string">"satyam@gmail.com"</span>, { <span class="hljs-attr">delay</span>: <span class="hljs-number">100</span> });
    <span class="hljs-keyword">await</span> page.click(selectors.continue);
    <span class="hljs-keyword">await</span> page.waitForSelector(selectors.password);
    <span class="hljs-keyword">await</span> page.type(selectors.password, <span class="hljs-string">"mypassword"</span>, { <span class="hljs-attr">delay</span>: <span class="hljs-number">100</span> });
    <span class="hljs-keyword">await</span> page.click(selectors.singin);
    <span class="hljs-keyword">await</span> page.waitForNavigation();
</code></pre>
<p>We're following the same steps as discussed above. First, go to the sign-in URL, enter the email ID, and click on the Continue button. Then enter the password, click on the Sign In button, and wait for a moment for the sign-in process to complete.</p>
<p>After the sign-in process is completed, you’ll be redirected to the product page to scrape the reviews.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-072923-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Product page</em></p>
<h2 id="heading-step-3-parse-the-review-data">Step 3: Parse the Review Data</h2>
<p>You've successfully logged in and are now on the product page that you want to scrape. Let's now parse the review data.</p>
<p>On the page, you'll find various reviews. These reviews are contained within a parent <code>div</code> with the ID <code>cm-cr-dp-review-list</code>, which holds all the reviews on the current page. If you want to access more reviews, you'll need to navigate to the next page using the pagination process.</p>
<p>This parent div has multiple child divs, and each child div holds one review. To extract the reviews, you can use the selector <code>#cm-cr-dp-review-list div.review</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> selectors = {
  <span class="hljs-attr">allReviews</span>: <span class="hljs-string">'#cm-cr-dp-review-list div.review'</span>,
  <span class="hljs-attr">authorName</span>: <span class="hljs-string">'div[data-hook="genome-widget"] span.a-profile-name'</span>,
  <span class="hljs-attr">reviewTitle</span>: <span class="hljs-string">'[data-hook=review-title]&gt;span:not([class])'</span>,
  <span class="hljs-attr">reviewDate</span>: <span class="hljs-string">'span[data-hook=review-date]'</span>,
};
</code></pre>
<p>This selector shows that you first go to the element with the ID <code>cm-cr-dp-review-list</code>, then search for all <code>div</code> elements with the data-hook <code>review</code>. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/annotely_image.png" alt="Image" width="600" height="400" loading="lazy">
<em>Review data with Author name, Review Title, Description, etc.</em></p>
<p>The following code snippet shows that you should first go to the product URL, wait for the selector to load, and then scrape all the reviews and store them in the <code>reviewElements</code> variable.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> page.goto(productURL);
<span class="hljs-keyword">await</span> page.waitForSelector(selectors.allReviews);
<span class="hljs-keyword">const</span> reviewElements = <span class="hljs-keyword">await</span> page.$$(selectors.allReviews);
</code></pre>
<p>Now, let's extract the author's name, review title, and date.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-091701.png" alt="Image" width="600" height="400" loading="lazy">
<em>Targetting Author name, Review Title, and Date</em></p>
<p>To parse the author name, you can use the selector <code>div[data-hook="genome-widget"] span.a-profile-name</code>. This selector tells us to first search for the <code>div</code> element with the <code>data-hook</code> attribute set to <code>genome-widget</code>, because the names are inside this <code>div</code> element. Then, search for the <code>span</code> element with the class name <code>a-profile-name</code>. This is the element that contains the author's name.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> author = <span class="hljs-keyword">await</span> reviewElement.$eval(selectors.authorName, <span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> element.textContent);
</code></pre>
<p>To parse the review title, you can use the CSS selector <code>[data-hook="review-title"] &gt; span:not([class])</code>. This selector tells us to search for the <code>span</code> element that is a direct child of the <code>[data-hook="review-title"]</code> element and that does not have a class attribute.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> title = <span class="hljs-keyword">await</span> reviewElement.$eval(selectors.reviewTitle, <span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> element.textContent);
</code></pre>
<p>To parse the date, you can use the CSS selector <code>span[data-hook="review-date"]</code>. This selector tells us to search for the span element that has the <code>data-hook</code> attribute set to <code>review-date</code>. This is the element that contains the review date.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> rawReviewDate = <span class="hljs-keyword">await</span> reviewElement.$eval(selectors.reviewDate, <span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> element.textContent);
</code></pre>
<p>Note that you’ll get the entire text, including the location, instead of just the full date. Therefore, you must use a regular expression pattern to extract the date from the text. </p>
<p>After that, combine all of the data into the <code>reviewData</code> and then push it to the final list <code>reviewsData</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> datePattern = <span class="hljs-regexp">/(\w+\s\d{1,2},\s\d{4})/</span>;
      <span class="hljs-keyword">const</span> match = rawReviewDate.match(datePattern);
      <span class="hljs-keyword">const</span> reviewDate = match ? match[<span class="hljs-number">0</span>].replace(<span class="hljs-string">','</span>, <span class="hljs-string">''</span>) : <span class="hljs-string">"Date not found"</span>;

      <span class="hljs-keyword">const</span> reviewData = {
        author,
        title,
        reviewDate,
      };

      reviewsData.push(reviewData);
    }
</code></pre>
<p>The above process will run until it has parsed all of the reviews on the current page. Here’s the code snippet to parse the data:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> reviewElement <span class="hljs-keyword">of</span> reviewElements) {
      <span class="hljs-keyword">const</span> author = <span class="hljs-keyword">await</span> reviewElement.$eval(selectors.authorName, <span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> element.textContent);
      <span class="hljs-keyword">const</span> title = <span class="hljs-keyword">await</span> reviewElement.$eval(selectors.reviewTitle, <span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> element.textContent);
      <span class="hljs-keyword">const</span> rawReviewDate = <span class="hljs-keyword">await</span> reviewElement.$eval(selectors.reviewDate, <span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> element.textContent);

      <span class="hljs-keyword">const</span> datePattern = <span class="hljs-regexp">/(\w+\s\d{1,2},\s\d{4})/</span>;
      <span class="hljs-keyword">const</span> match = rawReviewDate.match(datePattern);
      <span class="hljs-keyword">const</span> reviewDate = match ? match[<span class="hljs-number">0</span>].replace(<span class="hljs-string">','</span>, <span class="hljs-string">''</span>) : <span class="hljs-string">"Date not found"</span>;

      <span class="hljs-keyword">const</span> reviewData = {
        author,
        title,
        reviewDate,
      };

      reviewsData.push(reviewData);
    }
</code></pre>
<p>Great! You’ve successfully parsed the relevant data, which is now in JSON format, as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-095917.png" alt="Image" width="600" height="400" loading="lazy">
<em>Scraped the data in JSON format</em></p>
<h2 id="heading-step-4-export-reviews-to-a-csv">Step 4: Export Reviews to a CSV</h2>
<p>You've parsed the reviews in JSON format, which is a bit human-readable. You can convert this data to CSV format to make it more readable and easier for other purposes. </p>
<p>There are many ways to convert JSON data to CSV, but we'll use a simple and effective approach. Here is a simple code snippet to convert JSON to CSV:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> csvContent = <span class="hljs-string">"Author,Title,Date\n
for (const review of reviewsData) {
      const { author, title, reviewDate } = review;
      csvContent += `${author},"</span>${title}<span class="hljs-string">",${reviewDate}\n`;
    }

const csvFileName = "</span>amazon_reviews.csv<span class="hljs-string">";
await fs.writeFileSync(csvFileName, csvContent, "</span>utf8<span class="hljs-string">");</span>
</code></pre>
<p>Here’s the output of the CSV file.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-27-102705.png" alt="Image" width="600" height="400" loading="lazy">
<em>Converted JSON data into CSV format</em></p>
<p>And there you have it!</p>
<p>You can find the full Code uploaded on GitHub <a target="_blank" href="https://gist.github.com/triposat/20706d61989a4031669c2e3d25f487d0">here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this guide, you learned how to scrape Amazon product reviews behind a login using Puppeteer. You learned how to log in, parse relevant data, and save it to a CSV file. </p>
<p>To practice more, you can extract all the reviews of all the pages using pagination.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Full Stack Project Tutorial – Create A Notes App Using React and Node.js ]]>
                </title>
                <description>
                    <![CDATA[ Hey there! Ready to build something cool? In this tutorial, we're going to create a full stack notes app using React, Node.js, and PostgreSQL.  We'll start from scratch and end up with a fully functioning app where you can create, edit, and delete no... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/full-stack-project-tutorial-create-a-notes-app-using-react-and-node-js/</link>
                <guid isPermaLink="false">66c8c8d7fe21816c4cb75d17</guid>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgres ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chris Blakely ]]>
                </dc:creator>
                <pubDate>Thu, 28 Sep 2023 14:10:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/09/react-node-notes-app-screenshot-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hey there! Ready to build something cool? In this tutorial, we're going to create a full stack notes app using React, Node.js, and PostgreSQL. </p>
<p>We'll start from scratch and end up with a fully functioning app where you can create, edit, and delete notes. Plus, we're adding validation on both the UI and the backend to keep things in check!</p>
<p>This guide is all about giving you the real-deal experience of building a web app. You'll get to learn how each piece of the puzzle fits together – from the front-end magic with React, to the server-side wonders with Node.js, and storing all the good stuff in a PostgreSQL database. And hey, we're making sure it looks good and works well on mobile screens too!</p>
<p>By the end of this, you’ll have a good grip on full stack development with React and Node, which you can carry with you into future projects. It’s all about learning by doing, and getting the skills to make your ideas come to life. So, grab a cup of coffee, roll up your sleeves, and let’s get coding!</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Since we will be focusing on how to build a project, there are a few prerequisites that will be needed to get the most out of this tutorial:</p>
<ul>
<li>Some knowledge about web development concepts (frontend, backend, databases, API's, REST).</li>
<li>Some knowledge of JavaScript (variables, functions, objects, arrays, and so on).</li>
<li>Basic understanding on React (how to create components, add styles, work with state).</li>
<li>Basic understanding on Node.js/Express (working with APIs).</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-well-build">What We'll Build</a></li>
<li><a class="post-section-overview" href="#heading-challenge-try-it-yourself-first">Challenge: Try it Yourself First!</a></li>
<li><a class="post-section-overview" href="#heading-video-tutorial">Video Tutorial</a></li>
<li><a class="post-section-overview" href="#heading-part-1-create-the-ui">PART 1 – Create the UI</a></li>
<li><a class="post-section-overview" href="#heading-part-2-create-the-backend">PART 2 - Create the Backend</a></li>
<li><a class="post-section-overview" href="#heading-part-3-connect-ui-to-backend">PART 3 - Connect UI to Backend</a></li>
<li><a class="post-section-overview" href="#heading-the-end-why-not-try-the-bonus-challenges">The End - Why not try the bonus challenges?</a></li>
</ul>
<h2 id="heading-what-well-build">What We'll Build</h2>
<p>In this tutorial, we'll build a full stack notes app from scratch, using React, Node.js and PostgreSQL, with the following features:</p>
<ul>
<li>Create/Edit/Delete Notes</li>
<li>Validation on the UI and Backend</li>
<li>Responsive on mobile screens</li>
</ul>
<h2 id="heading-challenge-try-it-yourself-first">Challenge: Try it Yourself First!</h2>
<p>If you would like to attempt this project yourself first without looking at the tutorial, here's a few hints:</p>
<ul>
<li>Tackle one little piece at a time. For example, you would focus on getting the UI working on the UI first, and tackle the APIs later.</li>
<li>Think about your data – What do you need to store? What data structure (for example, arrays) will you use to return the data via the API?  How will you render this data on the UI?</li>
<li>Don't forget about validation and error handling. What will happen if the user tries to save a note without a title field? How will you prevent this? (Hint: Forms and the <code>required</code> field will be your friend here)</li>
<li>Remember there is no perfect way to complete a project. The tutorial below is one way to tackle the problem. You can choose to go a different way, putting your own unique style on things. The main thing is that you start!</li>
</ul>
<p>If you need more help on getting started yourself, you can find more hints and tips, starter code, and completed code you can reference over at <a target="_blank" href="https://www.codecoyotes.com/projects/react-node-notes-app">codecoyotes.com</a>.</p>
<h2 id="heading-video-tutorial">Video Tutorial</h2>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/2MoSzSlAuNk" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-part-1-create-the-ui">PART 1 – Create the UI</h2>
<p>We'll start this tutorial by creating the UI using some mock data. This lets us focus on our styling, and how things to look, without having to worry about creating a backend right away.</p>
<h3 id="heading-create-a-new-react-app">Create a New React App</h3>
<p>Okay, first things first: let's set up our project structure. Open your terminal and navigate to your desktop. Our next step is to create a new folder that will hold both our UI and backend code. Let's name it <code>notes-app</code>:</p>
<pre><code class="lang-bash">mkdir notes-app
</code></pre>
<p>Once that's done, navigate into the newly created <code>notes-app</code> directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> notes-app
</code></pre>
<p>Next, we'll create a new React app using TypeScript as our template. We'll use the <code>npx create-react-app</code> command for this, specifying TypeScript as the template:</p>
<pre><code class="lang-bash">npx create-react-app notes-app --template typescript
</code></pre>
<p>After you hit Enter, the process may take a few minutes to install all necessary packages. Once it's completed, open the <code>notes-app</code> folder in Visual Studio Code or your preferred IDE.</p>
<p>In Visual Studio Code, you should see that the <code>notes-app</code> is at the top level of your directory. As the course progresses, we will add a <code>notes-app-server</code> directory as well to keep all the code together in one place.</p>
<p>Now open a new terminal within your IDE and navigate to your React app's directory (let's assume you named it <code>notes-app</code>):</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> notes-app
</code></pre>
<p>Then, run the following command to start the front-end development server:</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>If all goes well, your browser will automatically open and display your new React app. You should see a spinning React logo, among other default assets.</p>
<p>Finally, let's clear out the boilerplate code to have a clean starting point for our app. Open <code>src/App.tsx</code> in your IDE and delete its content. This will be our new starting point for building the app.</p>
<h3 id="heading-add-ui-elements">Add UI Elements</h3>
<p>Okay, the first thing we'll do is put some of our UI components in place. This will consist of the general markup and CSS, without involving any JavaScript. This gives us a glimpse of how we envision the layout, without having to concern ourselves with API calls or database interactions at this stage.</p>
<p>We'll navigate to <code>.App.tsx</code> and create a new component. Make sure to import our stylesheet from <code>App.css</code>. The first thing to add is a <code>div</code> with a class name of <code>AppContainer</code>. This will help position our form and the CSS grid for our notes.</p>
<p>Within this <code>div</code>, we'll include our form tags. Here, we'll add an input field for the title — this is where the user can enter the note title. We'll also include a textarea for the note content. Both of these fields will be set to <code>required</code>, enabling browser-native validation messages if the user tries to submit an incomplete form. </p>
<p>At the bottom of the form, we'll include a button of type <code>submit</code>, which will handle form submissions when clicked.</p>
<p>Off to the right, we'll add a <code>div</code> to contain our notes. This will be structured as a CSS grid. Initially, we'll populate this grid with a single note to see how it looks.</p>
<p>For our note, we'll have a header containing a delete button situated on the right-hand side. We'll display the user-entered title – for demonstration purposes, we're using a dummy title. We'll also include the content that the user entered.</p>
<p>Finally, we'll export our component at the very bottom.</p>
<h3 id="heading-completed-code-for-this-section">Completed code for this section</h3>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"app-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"note-form"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Title"</span> <span class="hljs-attr">required</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Content"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">{10}</span> <span class="hljs-attr">required</span> /&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Add Note<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"notes-grid"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"note-item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"notes-header"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>x<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Note Title<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Note content<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h3 id="heading-add-css">Add CSS</h3>
<h4 id="heading-start-the-app">Start the App</h4>
<p>First, let's open a terminal and type <code>npm start</code>. This will launch the app in the browser. As you can see on the right-hand side, the appearance isn't great yet. This is because we haven't applied any styles. To fix this, we'll navigate to <code>App.css</code> and style the classes we added earlier.</p>
<p>You can download the styles from the link in the description if you prefer to copy and paste. Alternatively, feel free to follow along with the video and pause as needed. Remember, these styles are just examples for learning – they don't have to be perfect.</p>
<h4 id="heading-style-the-body-and-app-container">Style the Body and App Container</h4>
<p>In <code>App.css</code>, the first thing we'll do is add some styles to the <code>body</code>. We'll give it a gray background and a margin to prevent the app from touching the browser window edges. Next, we'll style our <code>App Container</code>.</p>
<p>We're designing this mobile-first, meaning the default styles will target mobile screens. We'll use media queries for larger displays. This approach is optional, but often it's easier to start with mobile designs.</p>
<p>For mobile screens, we want our <code>App Container</code> to default to a single column layout, stacking our form and notes grid on top of each other.</p>
<h4 id="heading-use-media-queries">Use Media Queries</h4>
<p>We'll add a media query specifying that for screens larger than 600 pixels, we'll use a two-column layout. We'll define this using <code>grid-template-columns</code>. </p>
<p>The first column will be 200 pixels wide, accommodating the form. The second column will use <code>1fr</code>, filling the remaining space. A 20-pixel gap will separate the two columns.</p>
<h4 id="heading-style-the-notes-grid">Style the Notes Grid</h4>
<p>Next, let's style our notes grid. We'll use CSS grid and define <code>grid-template-columns</code>. </p>
<p>Each grid item will have a minimum width of 250 pixels and can expand to fill available space. Don't worry if this sounds confusing – it will become clear soon.</p>
<p>We'll also set <code>grid-auto-rows</code> to ensure each row is a minimum of 250 pixels tall, accommodating notes of different sizes while maintaining a consistent row height.</p>
<h4 id="heading-style-individual-notes">Style Individual Notes</h4>
<p>For each note, we'll use Flexbox and set <code>flex-direction</code> to column, stacking the header, title, and content vertically. We'll also add some basic styles like border, padding, and background color. A box shadow will provide a finishing touch.</p>
<h4 id="heading-style-the-header-and-delete-button">Style the Header and Delete Button</h4>
<p>The header will also use Flexbox, and we'll set <code>justify-content</code> to <code>flex-end</code> to align the delete button to the right. The button will receive custom styles for a polished look.</p>
<h4 id="heading-style-the-form">Style the Form</h4>
<p>Lastly, we'll style the form on the left column. Again, we'll use Flexbox with a column layout and a 20-pixel gap between elements. The text area and input fields will get borders, padding, and resized fonts. We'll also style the submit button and add hover effects.</p>
<h4 id="heading-completed-code-for-this-section-1">Completed code for this section</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">background-color</span>: lightgrey;
}

<span class="hljs-selector-class">.app-container</span> {
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">1</span>fr;
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">600px</span>) {
  <span class="hljs-selector-class">.app-container</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">200px</span> <span class="hljs-number">1</span>fr;
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
  }
}

<span class="hljs-selector-class">.notes-grid</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(auto-fill, minmax(<span class="hljs-number">250px</span>, <span class="hljs-number">1</span>fr));
  <span class="hljs-attribute">grid-auto-rows</span>: <span class="hljs-built_in">minmax</span>(<span class="hljs-number">250px</span>, auto);
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.note-item</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f9f9f9</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0px</span> <span class="hljs-number">0px</span> <span class="hljs-number">10px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-class">.notes-header</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: flex-end;
}

<span class="hljs-selector-class">.notes-header</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">background</span>: transparent;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">max-width</span>: fit-content;
}

<span class="hljs-selector-tag">h2</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-selector-class">.note-form</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-tag">textarea</span>,
<span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid black;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
}

<span class="hljs-selector-class">.note-form</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">64</span>, <span class="hljs-number">154</span>, <span class="hljs-number">184</span>);
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">color</span>: white;
}

<span class="hljs-selector-class">.note-form</span> <span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">106</span>, <span class="hljs-number">175</span>, <span class="hljs-number">198</span>);
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-class">.edit-buttons</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-evenly;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">5px</span>;
}

<span class="hljs-selector-class">.edit-buttons</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
}

<span class="hljs-selector-class">.edit-buttons</span> <span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:last-of-type</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">220</span>, <span class="hljs-number">89</span>, <span class="hljs-number">89</span>);
  <span class="hljs-attribute">color</span>: white;
}
</code></pre>
<h3 id="heading-add-dummy-notes">Add Dummy Notes</h3>
<h4 id="heading-add-dummy-notes-for-css-grid-testing">Add Dummy Notes for CSS Grid Testing</h4>
<p>Now that we have our CSS in place, the next step is to add dummy notes to our <code>App</code> component to test the responsiveness of our CSS grid. To achieve this, we'll navigate to <code>App.tsx</code> and import the <code>useState</code> hook from React.</p>
<p>Inside our <code>App</code> component, we'll store the notes within the <code>useState</code> hook. Whenever you have UI elements that can change, it's a good idea to manage them in the state. We'll initialize this with a dummy array of notes, where each note has an <code>id</code>, a <code>title</code>, and <code>content</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [notes, setNotes] = useState&lt;Note[]&gt;([
{
  <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">title</span>: <span class="hljs-string">"test note 1"</span>,
  <span class="hljs-attr">content</span>: <span class="hljs-string">"bla bla note1"</span>,
},
{
  <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>,
  <span class="hljs-attr">title</span>: <span class="hljs-string">"test note 2 "</span>,
  <span class="hljs-attr">content</span>: <span class="hljs-string">"bla bla note2"</span>,
},
{
  <span class="hljs-attr">id</span>: <span class="hljs-number">3</span>,
  <span class="hljs-attr">title</span>: <span class="hljs-string">"test note 3"</span>,
  <span class="hljs-attr">content</span>: <span class="hljs-string">"bla bla note3"</span>,
},
{
  <span class="hljs-attr">id</span>: <span class="hljs-number">4</span>,
  <span class="hljs-attr">title</span>: <span class="hljs-string">"test note 4 "</span>,
  <span class="hljs-attr">content</span>: <span class="hljs-string">"bla bla note4"</span>,
},
{
  <span class="hljs-attr">id</span>: <span class="hljs-number">5</span>,
  <span class="hljs-attr">title</span>: <span class="hljs-string">"test note 5"</span>,
  <span class="hljs-attr">content</span>: <span class="hljs-string">"bla bla note5"</span>,
},
{
  <span class="hljs-attr">id</span>: <span class="hljs-number">6</span>,
  <span class="hljs-attr">title</span>: <span class="hljs-string">"test note 6"</span>,
  <span class="hljs-attr">content</span>: <span class="hljs-string">"bla bla note6"</span>,
},
]);
</code></pre>
<p>Think of this as simulating an API call and storing the returned data in the state. The structure of this data will be similar to what we'll receive from our API requests when we eventually build out our backend.</p>
<h4 id="heading-map-notes-to-components">Map Notes to Components</h4>
<p>With our array of notes in state, we can now use the <code>map</code> function within our notes grid to display the markup for each note. The <code>map</code> function will run as many times as there are notes in the array. Instead of hardcoding the <code>title</code> and <code>content</code>, we'll pull these values from each <code>note</code> object:</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">"notes-grid"</span>&gt;
  {notes.map(<span class="hljs-function">(<span class="hljs-params">note</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"note-item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"notes-header"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>x<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{note.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{note.content}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  ))}
&lt;/div&gt;
</code></pre>
<h4 id="heading-verify-responsiveness">Verify Responsiveness</h4>
<p>After these steps, you should see four notes displayed in the browser, populated with the values from the objects in the array.</p>
<p>To verify that our layout is responsive, you can change the window size. You'll see that the notes adjust based on the window size. When the window is at its smallest—simulating a mobile screen—the form will stack vertically above the notes grid.</p>
<h3 id="heading-save-note-form">Save Note Form</h3>
<p>Now that we have our UI set up, let's focus on adding functionality to the form that allows us to create a new note. Initially, we'll implement this for the UI. Later, we'll make the data persistent by linking it to the backend, which we'll build separately.</p>
<h4 id="heading-use-state-for-form-inputs-in-react">Use State for Form Inputs in React</h4>
<p>In React, when working with forms, it's a best practice to maintain a state variable for each form input. This enables React to control those inputs, making it easier to capture their values and use them programmatically.</p>
<p>In our code, we have two form inputs: one for the title and another for the content. For these, we'll set up two state variables called <code>title</code> and <code>content</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);
<span class="hljs-keyword">const</span> [content, setContent] = useState(<span class="hljs-string">""</span>);
</code></pre>
<p>For the title input, we bind its value to the <code>title</code> state variable and update this state whenever the user types into the field:</p>
<pre><code class="lang-javascript">&lt;input
  value={title}
  onChange={<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> setTitle(event.target.value)}
  placeholder=<span class="hljs-string">"Title"</span>
  required
&gt;&lt;/input&gt;
</code></pre>
<p>Similarly, we'll handle the <code>textarea</code> for content:</p>
<pre><code class="lang-javascript">&lt;textarea
  value={content}
  onChange={<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> setContent(event.target.value)}
  placeholder=<span class="hljs-string">"Content"</span>
  rows={<span class="hljs-number">10</span>}
  required
&gt;&lt;/textarea&gt;
</code></pre>
<h4 id="heading-handle-form-submission">Handle Form Submission</h4>
<p>After binding our form inputs to state variables, the next step is to add a function that handles the form submission. We'll name this function <code>handleAddNote</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleAddNote = <span class="hljs-function">(<span class="hljs-params">event: React.FormEvent</span>) =&gt;</span> {
  event.preventDefault();
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"title: "</span>, title);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"content: "</span>, content);
};
</code></pre>
<p>In this function, we specify the parameter type as <code>React.FormEvent</code> to satisfy TypeScript's typing requirement. We also call <code>event.preventDefault()</code> to prevent the form from submitting and refreshing the page, which is its default behavior. Following that, we log the <code>title</code> and <code>content</code> state variables to the console.</p>
<p>Finally, we'll connect this function to the <code>onSubmit</code> event in our form:</p>
<pre><code class="lang-jsx">&lt;form onSubmit={handleAddNote}&gt;{<span class="hljs-comment">/* ...form inputs here... */</span>}&lt;/form&gt;
</code></pre>
<h4 id="heading-test-the-form">Test the Form</h4>
<p>To test this setup, open the browser console, input a title and some content, and click the "Add Note" button. You should see the title and content values logged in the console, confirming that our form is capturing input as expected.</p>
<h3 id="heading-handle-the-add-note-functionality">Handle the "Add Note" Functionality</h3>
<p>Now that we've set up our state variables for the title and content, we can proceed to implement the function that handles adding a new note. This function will create a new note object and add it to our <code>notes</code> array, thereby updating the UI.</p>
<h4 id="heading-create-a-new-note-object">Create a New Note Object</h4>
<p>First, let's create a new note object and specify its type as <code>Note</code>, taking advantage of TypeScript's type system:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> newNote: Note = {
  <span class="hljs-attr">id</span>: notes.length + <span class="hljs-number">1</span>,
  <span class="hljs-attr">title</span>: title,
  <span class="hljs-attr">content</span>: content,
};
</code></pre>
<p>Because we've explicitly typed our object, TypeScript's IntelliSense will assist us in populating the object, ensuring that we don't miss any required properties. For now, we'll set the <code>id</code> to the length of the current <code>notes</code> array plus one, although this <code>id</code> will eventually be generated by our backend database.</p>
<h4 id="heading-update-state-with-new-note">Update State with New Note</h4>
<p>Once we have our new note object, we need to update our <code>notes</code> state array. We'll use the <code>setNotes</code> function for this purpose:</p>
<pre><code class="lang-javascript">setNotes([newNote, ...notes]);
</code></pre>
<p>The new note object will be the first item in the new <code>notes</code> array, followed by the existing notes, which we'll spread into the new array using the spread operator. This effectively makes a copy of the old <code>notes</code> array and inserts it into the new one.</p>
<h4 id="heading-clear-the-form-inputs">Clear the Form Inputs</h4>
<p>Lastly, let's reset the <code>title</code> and <code>content</code> state variables to empty strings, improving the user experience by clearing the form once a note is added:</p>
<pre><code class="lang-javascript">setTitle(<span class="hljs-string">""</span>);
setContent(<span class="hljs-string">""</span>);
</code></pre>
<h4 id="heading-test-the-functionality">Test the Functionality</h4>
<p>And that's it! If you now go to the browser, input a title and some content, and then click "Add Note," you'll see your new note appear at the top of the list, and the form fields will be cleared, ready for a new entry.</p>
<h3 id="heading-handle-the-update-note-functionality">Handle the "Update Note" Functionality</h3>
<p>In this section, we'll focus on implementing the feature that allows users to update an existing note. When a user clicks on a note, we want to populate the <code>title</code> and <code>content</code> fields in our form with the note's existing values. We'll also add a "Save" and "Cancel" button.</p>
<h4 id="heading-cleanup-and-initial-setup">Cleanup and Initial Setup</h4>
<p>First, let's clean up our code by removing any <code>console.log</code> statements – they are no longer needed:</p>
<pre><code class="lang-tsx">const [selectedNote, setSelectedNote] = useState&lt;Note | null&gt;(null);
</code></pre>
<h4 id="heading-track-the-selected-note">Track the Selected Note</h4>
<p>To track which note the user has clicked on, we'll create a new state variable called <code>selectedNote</code>. This state variable will have a type of <code>Note</code> or <code>null</code> to account for the possibility that no note is selected. We'll initialize this state to <code>null</code>.</p>
<h4 id="heading-create-the-click-handler">Create the Click Handler</h4>
<p>Next, let's create a function named <code>handleNoteClick</code> to handle the user's click event on a note. This function will take a <code>note</code> object as its argument:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleNoteClick = <span class="hljs-function">(<span class="hljs-params">note: Note</span>) =&gt;</span> {
  setSelectedNote(note);
  setTitle(note.title);
  setContent(note.content);
};
</code></pre>
<p>Within this function, we'll use <code>setSelectedNote</code> to save the clicked note to our <code>selectedNote</code> state. Additionally, we'll populate the <code>title</code> and <code>content</code> state variables with the values from the clicked note.</p>
<h4 id="heading-update-the-ui">Update the UI</h4>
<p>In the JSX for rendering each note, add an <code>onClick</code> event to the top-level <code>div</code> element for each note. Call the <code>handleNoteClick</code> function and pass the <code>note</code> object to it:</p>
<pre><code class="lang-jsx">&lt;div key={note.id} className=<span class="hljs-string">"note-item"</span> onClick={<span class="hljs-function">() =&gt;</span> handleNoteClick(note)}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"notes-header"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>x<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{note.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{note.content}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
&lt;/div&gt;
</code></pre>
<p>Since we are iterating over notes using the <code>map</code> function, this <code>onClick</code> handler will be added to each note automatically.</p>
<h4 id="heading-save-user-changes">Save user changes</h4>
<p>Now that we have the capability for the user to edit a note, we'll implement the functionality to save the changes they make to both the <code>title</code> and <code>content</code> of a note into our state.</p>
<h4 id="heading-the-handleupdatenote-function">The <code>handleUpdateNote</code> Function</h4>
<p>Let's create a new function called <code>handleUpdateNote</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleUpdateNote = <span class="hljs-function">(<span class="hljs-params">event: React.FormEvent</span>) =&gt;</span> {
  event.preventDefault();

  <span class="hljs-keyword">if</span> (!selectedNote) {
    <span class="hljs-keyword">return</span>;
  }

  <span class="hljs-keyword">const</span> updatedNote: Note = {
    <span class="hljs-attr">id</span>: selectedNote.id,
    <span class="hljs-attr">title</span>: title,
    <span class="hljs-attr">content</span>: content,
  };

  <span class="hljs-keyword">const</span> updatedNotesList = notes.map(<span class="hljs-function">(<span class="hljs-params">note</span>) =&gt;</span> (note.id === selectedNote.id ? updatedNote : note));

  setNotes(updatedNotesList);
  setTitle(<span class="hljs-string">""</span>);
  setContent(<span class="hljs-string">""</span>);
  setSelectedNote(<span class="hljs-literal">null</span>);
};
</code></pre>
<p>Within this function, we use <code>event.preventDefault()</code> to prevent the form from automatically submitting when the "Save" button is clicked. We also validate if a note is selected. If not, we exit the function early to prevent potential errors.</p>
<p>Next, we form an updated note object based on the selected note's <code>id</code> and the updated <code>title</code> and <code>content</code>. After that, we utilize the <code>map</code> function to generate a new array of notes, replacing the selected note with our updated note where the <code>id</code> matches. The updated array is then set to our state using the <code>setNotes</code> function. Finally, we reset our <code>title</code>, <code>content</code>, and <code>selectedNote</code> state values to their initial states.</p>
<h4 id="heading-the-handlecancel-function">The <code>handleCancel</code> Function</h4>
<p>We'll also implement a simple <code>handleCancel</code> function to reset our form and selected note when the user decides not to proceed with an update:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleCancel = <span class="hljs-function">() =&gt;</span> {
  setTitle(<span class="hljs-string">""</span>);
  setContent(<span class="hljs-string">""</span>);
  setSelectedNote(<span class="hljs-literal">null</span>);
};
</code></pre>
<h4 id="heading-update-the-jsx">Update the JSX</h4>
<p>Let's introduce conditional rendering in our JSX to display the appropriate buttons based on whether a note is selected for editing or not:</p>
<pre><code class="lang-jsx">&lt;form
  className=<span class="hljs-string">"note-form"</span>
  onSubmit={<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> (selectedNote ? handleUpdateNote(event) : handleAddNote(event))}
&gt;
  {<span class="hljs-comment">/* ... other form elements ... */</span>}
  {selectedNote ? (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"edit-buttons"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Save<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleCancel}</span>&gt;</span>Cancel<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  ) : (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Add Note<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  )}
&lt;/form&gt;
</code></pre>
<p>Within our form's <code>onSubmit</code> event, we've added a conditional. If a note is selected, we'll trigger the <code>handleUpdateNote</code> function. Otherwise, the <code>handleAddNote</code> function will be executed.</p>
<h4 id="heading-test-the-implementation">Test the Implementation</h4>
<p>After incorporating these changes, run your application. When you select a note, make modifications, and click on "Save", you'll observe the note gets updated.</p>
<h3 id="heading-delete-notes-from-the-ui">Delete Notes from the UI</h3>
<p>The last piece of functionality we need on the frontend before moving to the backend development is the ability to delete notes. You'll recall that we added a small "X" button to each note for this purpose. Clicking this button should remove the note from the UI. Let's jump back into the <code>App.tsx</code> file and implement this.</p>
<h4 id="heading-the-deletenote-function">The <code>deleteNote</code> Function</h4>
<p>First, create a function named <code>deleteNote</code> as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> deleteNote = <span class="hljs-function">(<span class="hljs-params">event: React.MouseEvent, noteId: number</span>) =&gt;</span> {
  event.stopPropagation();

  <span class="hljs-keyword">const</span> updatedNotes = notes.filter(<span class="hljs-function">(<span class="hljs-params">note</span>) =&gt;</span> note.id !== noteId);

  setNotes(updatedNotes);
};
</code></pre>
<p>This function takes in two parameters: the <code>event</code> object and the <code>noteId</code>. The <code>event.stopPropagation()</code> line is crucial here because the delete button is nested within a clickable note. It prevents the <code>deleteNote</code> event from interfering with the click event on the note itself. This is especially important when dealing with nested <code>onClick</code> events.</p>
<h4 id="heading-the-filtering-logic">The Filtering Logic</h4>
<p>The core of the delete functionality lies in the <code>filter</code> method applied to the <code>notes</code> array. This method loops through the array and applies a function to each element, much like the <code>map</code> method. It will only return the notes whose IDs do not match the <code>noteId</code> provided, effectively removing the selected note.</p>
<p>We save this newly filtered array into a variable called <code>updatedNotes</code> and then update our state with it by calling <code>setNotes(updatedNotes)</code>.</p>
<h4 id="heading-add-the-onclick-event">Add the <code>onClick</code> Event</h4>
<p>After defining the <code>deleteNote</code> function, attach it to the delete button within the note. Pass in the event and the note ID, like so:</p>
<pre><code class="lang-jsx">&lt;button onClick={<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> deleteNote(event, note.id)}&gt;x&lt;/button&gt;
</code></pre>
<h4 id="heading-test-the-functionality-1">Test the Functionality</h4>
<p>Now, if you run your app and click the delete button on a given note, you will observe that the note disappears from the UI.</p>
<h2 id="heading-part-2-create-the-backend">PART 2 - Create the Backend</h2>
<p>After implementing UI functionalities, it's time to set up a backend that allows us to persist notes when the user adds, edits, or deletes them. For this, create a new folder in your project at the top level and name it <code>notes-app-server</code>. Even though it might seem like the server code is in the same directory as the UI, they are entirely separate and will run independently.</p>
<h3 id="heading-initial-setup">Initial Setup</h3>
<ol>
<li>Open your terminal and navigate to the <code>notes-app-server</code> folder you just created.</li>
<li>Run the following commands:</li>
</ol>
<pre><code class="lang-bash">npm init
npm i ts-node typescript nodemon @types/cors @types/express @types/node --save-dev
npm i @prisma/client cors express prisma
npx tsc --init
</code></pre>
<ul>
<li><code>npm init</code>: Initializes a new npm module and gives you access to npm packages.</li>
<li><code>npm i ... --save-dev</code>: Installs development dependencies like TypeScript and type definitions.</li>
<li><code>npm i ...</code>: Installs production dependencies like Express and Prisma.</li>
</ul>
<h3 id="heading-modify-packagejson">Modify <code>package.json</code></h3>
<p>After running the above commands, navigate to your <code>package.json</code> and update the <code>scripts</code> section with:</p>
<pre><code class="lang-json"><span class="hljs-string">"start"</span>: <span class="hljs-string">"npx nodemon"</span>
</code></pre>
<p>This script uses nodemon for hot-reloading.</p>
<h3 id="heading-implement-the-server">Implement the Server</h3>
<p>Now, within the <code>notes-app-server</code> directory, create a <code>src</code> folder and within it, an <code>index.ts</code> file. Insert the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;
<span class="hljs-keyword">import</span> cors <span class="hljs-keyword">from</span> <span class="hljs-string">"cors"</span>;

<span class="hljs-keyword">const</span> app = express();

app.use(express.json());
app.use(cors());

app.get(<span class="hljs-string">"/api/notes"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  res.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"success!"</span> });
});

app.listen(<span class="hljs-number">5000</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"server running on localhost:5000"</span>);
});
</code></pre>
<ol>
<li><code>import express and cors</code>: We import the required libraries for our server.</li>
<li><code>const app = express();</code>: Initializes a new Express application.</li>
<li><code>app.use(express.json());</code>: Parses the JSON body from incoming API requests.</li>
<li><code>app.use(cors());</code>: Adds CORS support.</li>
<li><code>app.listen(5000, ...)</code>: This starts the server listening on port 5000.</li>
</ol>
<h3 id="heading-test">Test</h3>
<p>Finally, you can test the server by navigating to the <code>notes-app-server</code> directory in your terminal and running:</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>You should see the console log: <code>server running on localhost:5000</code>. To further test, you can use a curl command to hit the <code>/api/notes</code> endpoint. If everything is set up correctly, you'll get a JSON object back.</p>
<h3 id="heading-create-a-postgres-database">Create a Postgres Database</h3>
<p>ElephantSQL is a PostgreSQL database hosting service that makes it easy to set up, maintain, and scale your PostgreSQL database. Here's how to get started with creating a database using ElephantSQL.</p>
<h4 id="heading-step-1-sign-up-log-in">Step 1: Sign Up / Log In</h4>
<ol>
<li>Navigate to the <a target="_blank" href="https://www.elephantsql.com/">ElephantSQL website</a>.</li>
<li>If you don't have an account, you can sign up for free. If you already have one, go ahead and log in.</li>
</ol>
<h4 id="heading-step-2-create-a-new-instance">Step 2: Create a New Instance</h4>
<ol>
<li>Once logged in, you'll find yourself on the "Dashboard" page.</li>
<li>Click on the "Create New Instance" button.</li>
<li>You'll be taken to a page where you can set the details for your new PostgreSQL database instance.</li>
</ol>
<h4 id="heading-step-3-choose-a-plan">Step 3: Choose a Plan</h4>
<ol>
<li>You can start with a free "Tiny Turtle" plan, which is perfect for small projects and testing.</li>
<li>Select the plan that best suits your needs and click "Select".</li>
</ol>
<h4 id="heading-step-4-configure-your-instance">Step 4: Configure Your Instance</h4>
<ol>
<li>You'll be asked to name your instance. Choose a name that you'll remember and that describes the purpose of the database.</li>
<li>You can also select the data center that is geographically closest to you or your users for better performance.</li>
<li>Click on "Review" and then "Create instance" to finalize the creation.</li>
</ol>
<h4 id="heading-step-5-access-your-database">Step 5: Access Your Database</h4>
<ol>
<li>Once the instance is created, click on it in the Dashboard.</li>
<li>Here, you'll see the "Details" tab which includes all the information you need to connect to your database: <code>URL</code>, <code>User &amp; Default database</code>, <code>Password</code>, and more.</li>
</ol>
<h3 id="heading-populate-the-db">Populate the DB</h3>
<h4 id="heading-step-1-login-to-elephantsql">Step 1: Login to ElephantSQL</h4>
<p>Open your web browser and navigate to the ElephantSQL website. Log<br>in to your account.</p>
<h4 id="heading-step-2-open-your-instance">Step 2: Open your Instance</h4>
<p>Once logged in, click on the name of the database instance you've set up.</p>
<h4 id="heading-step-3-navigate-to-the-sql-browser">Step 3: Navigate to the SQL Browser</h4>
<p>In the left sidebar, find and click on "SQL Browser" or something similar (it might say "Browser").</p>
<h4 id="heading-step-4-run-sql-query">Step 4: Run SQL Query</h4>
<p>In the SQL Query editor that appears, you can type or paste in your SQL command:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-string">"public"</span>.<span class="hljs-string">"Note"</span> (title, <span class="hljs-keyword">content</span>)
<span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'test title'</span>, <span class="hljs-string">'test content bla bla'</span>);
</code></pre>
<p>After entering the SQL, click on the "Execute" or "Run" button.</p>
<p>That should insert a new row into your <code>Note</code> table with the title 'test title' and content 'test content bla bla'.</p>
<h4 id="heading-optional-verify-the-insert">Optional: Verify the Insert</h4>
<p>You may also want to verify if the data has been inserted correctly. For that, you could use:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-string">"public"</span>.<span class="hljs-string">"Note"</span>;
</code></pre>
<p>Run this SQL query in the same SQL browser, and it should return all rows from the <code>Note</code> table, including the one you've just inserted.</p>
<p>And that's it! You've inserted a new row into your table through the ElephantSQL web console.</p>
<h3 id="heading-connect-to-db-from-nodejs-backend-using-prisma">Connect to DB from Node.js backend using Prisma</h3>
<h4 id="heading-step-1-copy-the-elephantsql-connection-url">Step 1: Copy the ElephantSQL Connection URL</h4>
<p>Once you've set up your ElephantSQL database, make sure to copy the connection URL that appears on your dashboard. This URL includes your username and password to the database, so keep it secure.</p>
<h4 id="heading-step-2-create-an-env-file">Step 2: Create an <code>.env</code> File</h4>
<p>Navigate to your <code>notes-app-server</code> directory and create a new <code>.env</code> file:</p>
<pre><code class="lang-bash">touch .env
</code></pre>
<p>Open this file and add the following line to specify the database connection URL:</p>
<pre><code class="lang-bash">DATABASE_URL=<span class="hljs-string">"your_connection_url_here"</span>
</code></pre>
<p>Make sure not to commit this <code>.env</code> file to your Git repository to keep your credentials secure.</p>
<h4 id="heading-step-3-initialize-prisma">Step 3: Initialize Prisma</h4>
<p>If you haven't installed Prisma yet, install it first:</p>
<pre><code class="lang-bash">npm install prisma --save-dev
</code></pre>
<p>Now, initialize Prisma in the <code>notes-app-server</code> directory:</p>
<pre><code class="lang-bash">npx prisma init
</code></pre>
<p>This command will create a new <code>prisma</code> folder containing a <code>schema.prisma</code> file.</p>
<h4 id="heading-step-4-configure-schemaprisma">Step 4: Configure <code>schema.prisma</code></h4>
<p>Open <code>schema.prisma</code> in your text editor. You'll see that Prisma has already generated some configurations for you. Update the <code>datasource</code> block to use the environment variable:</p>
<pre><code class="lang-javascript">datasource db {
  provider = <span class="hljs-string">"postgresql"</span>
  url      = env(<span class="hljs-string">"DATABASE_URL"</span>)
}
</code></pre>
<h4 id="heading-step-5-create-the-note-model">Step 5: Create the Note Model</h4>
<p>Below the <code>datasource</code> block, add a new <code>model</code> block to represent a <code>Note</code>:</p>
<pre><code class="lang-javascript">model Note {
  id      Int     @id @<span class="hljs-keyword">default</span>(autoincrement())
  title   <span class="hljs-built_in">String</span>
  content <span class="hljs-built_in">String</span>
}
</code></pre>
<h4 id="heading-step-6-generate-prisma-client-and-database-table">Step 6: Generate Prisma Client and Database Table</h4>
<p>Run the following command to generate your Prisma client and create the database tables:</p>
<pre><code class="lang-bash">npx prisma db push
</code></pre>
<h4 id="heading-step-7-add-prisma-to-your-application">Step 7: Add Prisma to Your Application</h4>
<p>First, import Prisma at the top of your <code>index.ts</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;
</code></pre>
<p>Then, initialize the Prisma client:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient();
</code></pre>
<h4 id="heading-step-8-query-your-database">Step 8: Query Your Database</h4>
<p>Now you can use Prisma in your application to query the database. For example, in a <code>GET</code> endpoint:</p>
<pre><code class="lang-typescript">app.get(<span class="hljs-string">"/notes"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> notes = <span class="hljs-keyword">await</span> prisma.note.findMany();
  res.json(notes);
});
</code></pre>
<h3 id="heading-optional-install-thunder-client-in-vs-code">Optional: Install Thunder Client in VS Code</h3>
<p>(Feel free to skip this step if you already have a preferred API client)</p>
<p>Using <code>curl</code> is useful for quickly testing APIs, but it becomes cumbersome when you need to build out more complex requests. For instance, handling POST requests with custom bodies and headers can be more complicated. </p>
<p>To make API requests more straightforward, we'll install a client designed for this purpose.</p>
<p>While there are several options like Postman, we're going to focus on installing Thunder Client within VS Code, which makes it simple to execute requests right from your IDE.</p>
<p>To install Thunder Client, navigate to the Extensions section in VS Code and type "Thunder Client" in the search bar. You'll find it in the list of available extensions, identifiable by its purple logo. Click "Install," and upon completion, you'll see a Thunder Client option appear on the left-hand taskbar of your IDE.</p>
<p>Once you've clicked on Thunder Client, a list of your past requests will display. To initiate a new request, click the "New Request" button at the top. This action opens a new tab within Visual Studio Code.</p>
<p>Before proceeding, ensure that your server is running. Open the terminal and verify this. We will use Thunder Client to test our GET endpoint and get familiar with the request-making process. In the URL bar, enter the address of your 'notes' endpoint and specify that it's a GET request.</p>
<p>Click "Send," and you'll see a small window displaying the response. If the status code is 200 and you see an array containing your note, you've successfully made a GET request. Thunder Client will be our tool of choice for testing subsequent create, update, and delete requests. Of course, feel free to use any other tool you're comfortable with for this purpose.</p>
<h3 id="heading-create-post-endpoint">Create POST Endpoint</h3>
<p>In this section, we'll add an endpoint to our Express application that allows us to create a new note. Locate the <code>index.ts</code> file and insert the following code below your existing GET endpoint:</p>
<pre><code class="lang-typescript">app.post(<span class="hljs-string">"/api/notes"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { title, content } = req.body;

  <span class="hljs-keyword">if</span> (!title || !content) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"title and content fields required"</span>);
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> note = <span class="hljs-keyword">await</span> prisma.note.create({
      data: { title, content },
    });
    res.json(note);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">"Oops, something went wrong"</span>);
  }
});
</code></pre>
<p>The structure is similar to the GET endpoint, but we're using <code>app.post</code> this time. We specify the URL for this POST endpoint and then define our function.</p>
<p>Inside the function, the first task is to extract <code>title</code> and <code>content</code> from the <code>req.body</code>. This is what the UI will send when a user submits the "Add Note" form.</p>
<p>After obtaining <code>title</code> and <code>content</code>, we utilize the Prisma client that we set up earlier to create a new note. We pass the <code>title</code> and <code>content</code> to the <code>prisma.note.create()</code> method, which returns a new note object complete with an ID. This object is then sent back as a JSON response.</p>
<p>To test the endpoint, go to the Thunder Client tab in VS Code. Switch the HTTP method from GET to POST while keeping the URL the same. Click the "Body" tab, which should default to JSON, and input some test values for <code>title</code> and <code>content</code>. After hitting "Send," you should receive a 200 OK status along with the created note, containing an ID, title, and content.</p>
<p>For robustness, we've added validation and error-handling. If either <code>title</code> or <code>content</code> is missing, the server returns a 400 Bad Request status with an appropriate error message. To test this, remove either <code>title</code> or <code>content</code> from the request body and resend it. You should now see a 400 status code along with your error message.</p>
<p>Additionally, we use a try-catch block to handle any errors thrown by the Prisma client. This helps in cases of database connection issues or other unforeseen errors, preventing the backend from crashing.</p>
<p>Finally, you can test the GET endpoint again. It should now return two notes: the first one manually added to the database, and the second one just created through Thunder Client. Switch the method back to GET in Thunder Client and hit "Send"; you should see two notes in the response.</p>
<h3 id="heading-create-put-endpoint">Create PUT Endpoint</h3>
<p>In this segment of the tutorial, we'll focus on adding the ability to update a note. Add the following code snippet below the code for your previous POST endpoint:</p>
<pre><code class="lang-javascript">app.put(<span class="hljs-string">"/api/notes/:id"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { title, content } = req.body;
  <span class="hljs-keyword">const</span> id = <span class="hljs-built_in">parseInt</span>(req.params.id);

  <span class="hljs-keyword">if</span> (!title || !content) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"title and content fields required"</span>);
  }

  <span class="hljs-keyword">if</span> (!id || <span class="hljs-built_in">isNaN</span>(id)) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"ID must be a valid number"</span>);
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> updatedNote = <span class="hljs-keyword">await</span> prisma.note.update({
      <span class="hljs-attr">where</span>: { id },
      <span class="hljs-attr">data</span>: { title, content },
    });
    res.json(updatedNote);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">"Oops, something went wrong"</span>);
  }
});
</code></pre>
<p>The structure of this <code>app.put</code> function is similar to the GET and POST endpoints you've already created. The major difference is the <code>:id</code> parameter in the URL. This acts as a placeholder, allowing you to specify the ID of the note you wish to update.</p>
<p>Inside the function, you'll notice we extract <code>title</code> and <code>content</code> from <code>req.body</code>, just like before. Additionally, we retrieve the ID from <code>req.params</code> and convert it to an integer using <code>parseInt()</code>, as our database stores IDs as integers.</p>
<p>We've added validation checks to ensure that the <code>id</code> exists and is a valid number. If either <code>id</code>, <code>title</code>, or <code>content</code> is missing or invalid, the API returns a 400 status code along with an error message.</p>
<p>Next, we use a try-catch block to attempt the update operation. Within the <code>try</code> section, we call the <code>prisma.note.update()</code> function. We specify the <code>id</code> in a <code>where</code> object and provide the new <code>title</code> and <code>content</code> via a <code>data</code> object. If the operation succeeds, the updated note is sent back in the response. In case of an error, the <code>catch</code> block will return a 500 status and an error message.</p>
<p>To test this, switch to your Thunder Client tab in VS Code. Update the method to PUT and set the URL to include the ID of the note you want to update, for example, <code>/api/notes/3</code>. In the request body, send JSON data with the new <code>title</code> and <code>content</code>. Upon hitting "Send", a 200 status should confirm the update. The returned note should reflect your changes.</p>
<p>To double-check, perform a GET request on the <code>/api/notes</code> endpoint. You should see the updated note in the list.</p>
<p>Lastly, test the validation by supplying an invalid ID, like a random string. The API should return an error message stating that the ID must be a valid number.</p>
<h3 id="heading-create-delete-endpoint">Create DELETE Endpoint</h3>
<p>In addition to our existing endpoints, it's crucial to add validation for empty <code>title</code> or <code>content</code> fields in our <code>app.put</code> function, since these fields are required by our database. Revisit your <code>app.put</code> function in <code>index.ts</code> and add similar validation to what we added for the POST request. Specifically, if either <code>title</code> or <code>content</code> is empty, return a 400 status code along with an error message.</p>
<p>With that in place, let's move on to the DELETE endpoint. Add the following code just after your PUT endpoint:</p>
<pre><code class="lang-javascript">app.delete(<span class="hljs-string">"/api/notes/:id"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> id = <span class="hljs-built_in">parseInt</span>(req.params.id);

  <span class="hljs-keyword">if</span> (!id || <span class="hljs-built_in">isNaN</span>(id)) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"ID field required"</span>);
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> prisma.note.delete({
      <span class="hljs-attr">where</span>: { id },
    });
    res.status(<span class="hljs-number">204</span>).send();
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">"Oops, something went wrong"</span>);
  }
});
</code></pre>
<p>This <code>app.delete</code> function works similarly to the update (<code>app.put</code>) endpoint. It also accepts an ID as part of the URL parameters (<code>query params</code> should be <code>URL parameters</code> or <code>route parameters</code>).</p>
<p>First, we validate that the provided ID is a valid number. If it isn't, we return a 400 status code and an accompanying error message.</p>
<p>Once the ID is validated, we proceed to delete the note using Prisma's <code>delete</code> method. In the <code>try</code> block, we specify which note to delete by its ID in the <code>where</code> object. Upon successful deletion, we return a 204 status code, which indicates 'No Content.' This is a standard way to signal to the frontend or API consumers that the deletion was successful.</p>
<p>If an error occurs during the deletion, the <code>catch</code> block returns a 500 status code along with a generic error message.</p>
<p>To test the new DELETE endpoint, switch your HTTP method to <code>DELETE</code> in your testing tool (like Thunder Client or Postman). Use the ID of the note you wish to delete, such as <code>/api/notes/3</code>, and hit 'Send'. You should receive a 204 status code, indicating the operation was successful. To confirm, perform a GET request on your <code>/api/notes</code> endpoint and observe that the note with the specified ID has indeed been removed.</p>
<h2 id="heading-part-3-connect-ui-to-backend">PART 3 - Connect UI to Backend</h2>
<p>Now that we have our backend and UI ready, it's time to connect them. We will do this by using the built in <code>fetch</code> function to call our backend from our UI.</p>
<h3 id="heading-get-and-display-notes">Get and Display Notes</h3>
<p>Let's dive back into our frontend code. Just below our state declarations at the top of our component, we're going to introduce a <code>useEffect</code> hook:</p>
<pre><code class="lang-jsx">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// ...</span>
}, []);
</code></pre>
<p>Inside this <code>useEffect</code>, we'll define an asynchronous function named <code>fetchNotes</code>. We need to put this in a separate function because React does not support making the <code>useEffect</code> hook asynchronous directly:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> fetchNotes = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-comment">// ...</span>
};
</code></pre>
<p>To handle any potential errors from the API, we'll wrap our API logic inside a <code>try-catch</code> block:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">try</span> {
  <span class="hljs-comment">// ...</span>
} <span class="hljs-keyword">catch</span> (e) {
  <span class="hljs-built_in">console</span>.log(e);
}
</code></pre>
<p>Inside the <code>try</code> block, we use the native <code>fetch</code> function to make an API call. Our API is running at <code>http://localhost:5000/api/notes</code>. By default, <code>fetch</code> performs a GET request, which is what we need:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:5000/api/notes"</span>);
</code></pre>
<p>After making the request, we'll process the response and convert it to JSON. The API returns an array of notes, which we'll capture in a variable named <code>notes</code> of type <code>Note[]</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> notes: Note[] = <span class="hljs-keyword">await</span> response.json();
</code></pre>
<p>If everything goes smoothly, the next step is to update our state with the notes fetched from the API:</p>
<pre><code class="lang-jsx">setNotes(notes);
</code></pre>
<p>In the <code>catch</code> block, we'll log any errors that may occur:</p>
<pre><code class="lang-jsx"><span class="hljs-built_in">console</span>.log(e);
</code></pre>
<p>We've defined <code>fetchNotes</code>, but haven't called it yet. To invoke this function, add a call to <code>fetchNotes()</code> at the end of the <code>useEffect</code> block:</p>
<pre><code class="lang-jsx">fetchNotes();
</code></pre>
<p>Lastly, add an empty dependency array to ensure that this code only runs once when the component is first mounted:</p>
<pre><code class="lang-jsx">}, []);
</code></pre>
<p>After saving your changes, you should see the notes from your database displayed in the browser. If you've added or deleted notes directly through the database, those changes should be reflected here.</p>
<p>To wrap things up, you can remove any hardcoded array that you initially added to your <code>notes</code> state variable. Instead, populate it with the data fetched from the API:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [notes, setNotes] = useState&lt;Note[]&gt;([]);
</code></pre>
<p>This ensures that the <code>notes</code> state is initially empty, then populated by the <code>useEffect</code> through the <code>fetchNotes</code> function.</p>
<h3 id="heading-completed-code-for-this-section-2">Completed Code for this Section</h3>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> [notes, setNotes] = useState&lt;Note[]&gt;([]);


  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchNotes = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
          <span class="hljs-string">"http://localhost:5000/api/notes"</span>
        );

        <span class="hljs-keyword">const</span> notes: Note[] =
          <span class="hljs-keyword">await</span> response.json();

        setNotes(notes);
      } <span class="hljs-keyword">catch</span> (e) {
        <span class="hljs-built_in">console</span>.log(e);
      }
    };

    fetchNotes();
  }, []);
</code></pre>
<h3 id="heading-save-new-note">Save New Note</h3>
<p>Next, let's explore how to save a note to our backend. We already have a function called <code>handleAddNote</code> that deals with adding a note to the UI:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> handleAddNote = <span class="hljs-keyword">async</span> (
  event: React.FormEvent
) =&gt; {
  <span class="hljs-comment">// ...</span>
};
</code></pre>
<p>To start, remove any code that manually creates a new note object on the frontend. This is because our backend will return this object with all its properties once the note has been saved to the database.</p>
<p>As in our previous example, we'll use a <code>try-catch</code> block to handle the API logic and error handling:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">try</span> {
  <span class="hljs-comment">// API logic here</span>
} <span class="hljs-keyword">catch</span> (e) {
  <span class="hljs-built_in">console</span>.log(e);
}
</code></pre>
<p>Place your existing state-changing function calls (<code>setNotes</code>, <code>setTitle</code>, and <code>setContent</code>) inside the <code>try</code> block. These will be executed after the API successfully saves the note:</p>
<pre><code class="lang-jsx">setNotes([newNote, ...notes]);
setTitle(<span class="hljs-string">""</span>);
setContent(<span class="hljs-string">""</span>);
</code></pre>
<p>To call the API, we'll use the <code>fetch</code> function, similar to how we fetched notes. The difference is that this time, we need to pass a second argument to <code>fetch</code> to specify the HTTP method and payload:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
  <span class="hljs-string">"http://localhost:5000/api/notes"</span>,
  {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
    },
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
      title,
      content,
    }),
  }
);
</code></pre>
<p>Don't forget to add the <code>async</code> keyword to the <code>handleAddNote</code> function signature if you haven't already, as we are using the <code>await</code> keyword inside the function.</p>
<p>The server will respond with the newly created note object, which we can then add to our UI. Convert the response to JSON and store it in a variable named <code>newNote</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> newNote = <span class="hljs-keyword">await</span> response.json();
</code></pre>
<p>Finally, in the <code>catch</code> block, we log any errors that might occur:</p>
<pre><code class="lang-jsx"><span class="hljs-built_in">console</span>.log(e);
</code></pre>
<p>Also, make sure to add headers to specify the content type of the data we are sending:</p>
<pre><code class="lang-jsx">headers: {
  <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
}
</code></pre>
<p>Save your changes and test the functionality in the browser. Use the form to add a new note and click "Add Note." If everything is set up correctly, your new note should appear in the list.</p>
<h3 id="heading-completed-code-for-this-section-3">Completed Code for this Section</h3>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> handleAddNote = <span class="hljs-keyword">async</span> (
    event: React.FormEvent
  ) =&gt; {
    event.preventDefault();
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
        <span class="hljs-string">"http://localhost:5000/api/notes"</span>,
        {
          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
          <span class="hljs-attr">headers</span>: {
            <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
          },
          <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
            title,
            content,
          }),
        }
      );

      <span class="hljs-keyword">const</span> newNote = <span class="hljs-keyword">await</span> response.json();

      setNotes([newNote, ...notes]);
      setTitle(<span class="hljs-string">""</span>);
      setContent(<span class="hljs-string">""</span>);
    } <span class="hljs-keyword">catch</span> (e) {
      <span class="hljs-built_in">console</span>.log(e);
    }
  };
</code></pre>
<h3 id="heading-save-updated-note">Save Updated Note</h3>
<p>Next, let's explore how to save a note to our backend. We already have a function called <code>handleAddNote</code> that deals with adding a note to the UI:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> handleAddNote = <span class="hljs-keyword">async</span> (
  event: React.FormEvent
) =&gt; {
  <span class="hljs-comment">// ...</span>
};
</code></pre>
<p>To start, remove any code that manually creates a new note object on the frontend. This is because our backend will return this object with all its properties once the note has been saved to the database.</p>
<p>As in our previous example, we'll use a <code>try-catch</code> block to handle the API logic and error handling:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">try</span> {
  <span class="hljs-comment">// API logic here</span>
} <span class="hljs-keyword">catch</span> (e) {
  <span class="hljs-built_in">console</span>.log(e);
}
</code></pre>
<p>Place your existing state-changing function calls (<code>setNotes</code>, <code>setTitle</code>, and <code>setContent</code>) inside the <code>try</code> block. These will be executed after the API successfully saves the note:</p>
<pre><code class="lang-jsx">setNotes([newNote, ...notes]);
setTitle(<span class="hljs-string">""</span>);
setContent(<span class="hljs-string">""</span>);
</code></pre>
<p>To call the API, we'll use the <code>fetch</code> function, similar to how we fetched notes. The difference is that this time, we need to pass a second argument to <code>fetch</code> to specify the HTTP method and payload:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
  <span class="hljs-string">"http://localhost:5000/api/notes"</span>,
  {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
    },
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
      title,
      content,
    }),
  }
);
</code></pre>
<p>Don't forget to add the <code>async</code> keyword to the <code>handleAddNote</code> function signature if you haven't already, as we are using the <code>await</code> keyword inside the function.</p>
<p>The server will respond with the newly created note object, which we can then add to our UI. Convert the response to JSON and store it in a variable named <code>newNote</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> newNote = <span class="hljs-keyword">await</span> response.json();
</code></pre>
<p>Finally, in the <code>catch</code> block, we log any errors that might occur:</p>
<pre><code class="lang-jsx"><span class="hljs-built_in">console</span>.log(e);
</code></pre>
<p>Also, make sure to add headers to specify the content type of the data we are sending:</p>
<pre><code class="lang-jsx">headers: {
  <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
}
</code></pre>
<p>Save your changes and test the functionality in the browser. Use the form to add a new note and click "Add Note." If everything is set up correctly, your new note should appear in the list.</p>
<h3 id="heading-completed-code-for-this-section-4">Completed Code for this Section</h3>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> handleAddNote = <span class="hljs-keyword">async</span> (
    event: React.FormEvent
  ) =&gt; {
    event.preventDefault();
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
        <span class="hljs-string">"http://localhost:5000/api/notes"</span>,
        {
          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
          <span class="hljs-attr">headers</span>: {
            <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
          },
          <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
            title,
            content,
          }),
        }
      );

      <span class="hljs-keyword">const</span> newNote = <span class="hljs-keyword">await</span> response.json();

      setNotes([newNote, ...notes]);
      setTitle(<span class="hljs-string">""</span>);
      setContent(<span class="hljs-string">""</span>);
    } <span class="hljs-keyword">catch</span> (e) {
      <span class="hljs-built_in">console</span>.log(e);
    }
  };
</code></pre>
<h3 id="heading-save-deleted-note">Save Deleted Note</h3>
<p>In this section, we'll discuss how to delete a note by invoking an API endpoint. We'll focus on the <code>deleteNote</code> function for this functionality:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> deleteNote = <span class="hljs-keyword">async</span> (
  event: React.MouseEvent,
  <span class="hljs-attr">noteId</span>: number
) =&gt; {
  <span class="hljs-comment">// ...</span>
};
</code></pre>
<p>First, we need to make our function asynchronous to handle API calls. So, add the <code>async</code> keyword to the function declaration like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> deleteNote = <span class="hljs-keyword">async</span> (
  event: React.MouseEvent,
  <span class="hljs-attr">noteId</span>: number
) =&gt; {
  <span class="hljs-comment">// ...</span>
};
</code></pre>
<p>Next, let's add a <code>try-catch</code> block to manage the API call. The <code>catch</code> block is essential for logging errors, which prevents the application from crashing unexpectedly:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">try</span> {
  <span class="hljs-comment">// API logic here</span>
} <span class="hljs-keyword">catch</span> (e) {
  <span class="hljs-built_in">console</span>.log(e);
}
</code></pre>
<p>Copy the existing UI-update logic you have and paste it into the <code>try</code> block, right after the API call. This ensures that the UI only updates if the API call is successful.</p>
<p>Now, let's get to the main part—making the API call to delete the note. To do so, we'll use the <code>fetch</code> API:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">await</span> fetch(
  <span class="hljs-string">`http://localhost:5000/api/notes/<span class="hljs-subst">${noteId}</span>`</span>,
  {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"DELETE"</span>,
  }
);
</code></pre>
<p>Note that the URL is a template string. It allows us to inject the ID of the note (<code>noteId</code>) that we want to delete. This <code>noteId</code> is passed into our <code>deleteNote</code> function when the user clicks the delete button corresponding to a specific note.</p>
<p>We specify the HTTP method as "DELETE" to indicate that we're requesting to delete a note:</p>
<pre><code class="lang-jsx">method: <span class="hljs-string">"DELETE"</span>,
</code></pre>
<p>Unlike the 'add' or 'update' operations, there's no need to assign the API response to a variable, as we're not expecting any data to be returned:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">await</span> fetch(
  <span class="hljs-string">`http://localhost:5000/api/notes/<span class="hljs-subst">${noteId}</span>`</span>,
  {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"DELETE"</span>,
  }
);
</code></pre>
<p>After successfully deleting the note, we filter out the deleted note from our local notes state:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> updatedNotes = notes.filter(
  <span class="hljs-function">(<span class="hljs-params">note</span>) =&gt;</span> note.id !== noteId
);
setNotes(updatedNotes);
</code></pre>
<p>Finally, if everything goes smoothly and you save your changes, try running the application in the browser. Click the delete button for a specific note, and then refresh the page. You'll see that the note has been removed successfully.</p>
<h3 id="heading-completed-code-for-this-section-5">Completed Code for this Section</h3>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> deleteNote = <span class="hljs-keyword">async</span> (
    event: React.MouseEvent,
    <span class="hljs-attr">noteId</span>: number
  ) =&gt; {
    event.stopPropagation();

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> fetch(
        <span class="hljs-string">`http://localhost:5000/api/notes/<span class="hljs-subst">${noteId}</span>`</span>,
        {
          <span class="hljs-attr">method</span>: <span class="hljs-string">"DELETE"</span>,
        }
      );
      <span class="hljs-keyword">const</span> updatedNotes = notes.filter(
        <span class="hljs-function">(<span class="hljs-params">note</span>) =&gt;</span> note.id !== noteId
      );

      setNotes(updatedNotes);
    } <span class="hljs-keyword">catch</span> (e) {
      <span class="hljs-built_in">console</span>.log(e);
    }
  };
</code></pre>
<h2 id="heading-the-end-why-not-try-the-bonus-challenges">The End - Why not try the bonus challenges?</h2>
<p>Congratulations on making it to the end! If you enjoyed this project, I have created <a target="_blank" href="https://www.codecoyotes.com/projects/react-node-notes-app">a list of additional challenges to try over at codecoyotes.com</a>. </p>
<p>If you have any questions or suggestions feel free to <a target="_blank" href="https://www.codecoyotes.com/contact">drop me a message here.</a> See you in the next one!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ JavaScript Concepts to Know Before Learning Node.js ]]>
                </title>
                <description>
                    <![CDATA[ Before Node.js came into existence, JavaScript could only be run on the browser. It could only be used as a scripting language for frontend web development. Then, Node.js came to free JavaScript from this confinement. It made JavaScript ubiquitous (m... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/javascript-concepts-to-know-before-learning-node-js/</link>
                <guid isPermaLink="false">66d460443bc3ab877dae2224</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Musab Habeeb ]]>
                </dc:creator>
                <pubDate>Tue, 19 Sep 2023 15:12:57 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/09/JavaScript-Concepts-to-master-before-Node.js.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Before Node.js came into existence, JavaScript could only be run on the browser. It could only be used as a scripting language for frontend web development.</p>
<p>Then, Node.js came to free JavaScript from this confinement. It made JavaScript ubiquitous (meaning it could now be run everywhere).</p>
<p>Node.js is a JavaScript runtime environment that allows JavaScript developers to write command line tools and server side scripts outside of a browser.</p>
<p>Learning Node.js enables JavaScript developers to write server side code and code for embedded systems. This opens up opportunities in backend development and hardware programming.</p>
<p>But, before diving into Node.js, a JavaScript developer has to learn and understand some JavaScript concepts.</p>
<p>In this article, you are going to learn the JavaScript concepts you need to understand before learning Node.js.</p>
<p>Before you continue with the article, check the prerequisites.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this article, you should have some basic knowledge of:</p>
<ul>
<li><p>JavaScript</p>
</li>
<li><p>The browser console (this is where you will run your code).</p>
</li>
</ul>
<p>Now that we have those out of our way, let's dive into the article, starting with expressions.</p>
<h2 id="heading-expressions">Expressions</h2>
<p>An expression is a unit or block of code that evaluates to a value.</p>
<p>There are five basic categories of expressions in JavaScript: primary expressions, arithmetic expressions, string expressions, logical expressions, and left-hand side expressions.</p>
<h3 id="heading-primary-expressions">Primary expressions</h3>
<p>Primary expressions consist of basic keywords in JavaScript. A common example is the <code>this</code> keyword:</p>
<pre><code class="lang-js"><span class="hljs-built_in">this</span>[<span class="hljs-string">'item'</span>];

<span class="hljs-built_in">this</span>.item;
</code></pre>
<p>Later on in this article you will learn more about the <code>this</code> keyword.</p>
<h3 id="heading-arithmetic-expressions">Arithmetic expressions</h3>
<p>An arithmetic operator takes numerical values as its operands and returns a numerical value. The operands and the operator make up the arithmetic expression:</p>
<pre><code class="lang-js"><span class="hljs-number">2</span> + <span class="hljs-number">3</span>;

<span class="hljs-number">2</span> * <span class="hljs-number">3</span>;

<span class="hljs-number">2</span> ** <span class="hljs-number">3</span>;
</code></pre>
<h3 id="heading-string-expressions">String expressions</h3>
<p>When strings are concatenated they form string expressions:</p>
<pre><code class="lang-js"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">'My name is'</span> + <span class="hljs-string">'Peter'</span>);
</code></pre>
<h3 id="heading-logical-expressions">Logical expressions</h3>
<p>Logical expressions are expressions in which various values are compared:</p>
<pre><code class="lang-js"><span class="hljs-number">10</span> &gt; <span class="hljs-number">2</span>;
<span class="hljs-number">2</span> &lt; <span class="hljs-number">10</span>;
c === <span class="hljs-number">2</span> || d === <span class="hljs-number">10</span>;
</code></pre>
<h3 id="heading-left-hand-side-expressions">Left-hand side expressions</h3>
<p>Left-hand side expressions are expressions where values are assigned to a variable:</p>
<pre><code class="lang-js"><span class="hljs-comment">// variables</span>
a = <span class="hljs-number">2</span>;

<span class="hljs-comment">// object properties</span>
obj = {};
obj.name = <span class="hljs-string">'Paul'</span>;
</code></pre>
<h2 id="heading-data-types">Data Types</h2>
<p>There are 8 data types in JavaScript: String, Number, Boolean, Object, Null, Undefined, Symbol, and BigInt.</p>
<h3 id="heading-string">String</h3>
<p>The string type represents textual data. A string is surrounded by a single quote or a double quote.</p>
<p>Each element in a string occupies a certain position in the string. The first element is at index 0, and the second and third are at index 1 and 2 respectively.</p>
<p>Here is an example of a string:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> name = <span class="hljs-string">'Yusuf'</span>;
<span class="hljs-keyword">let</span> newName = <span class="hljs-string">"Joseph"</span>;
</code></pre>
<h3 id="heading-number">Number</h3>
<p>The number types are stored in 64-bit format, also known as double-precision floating point numbers.</p>
<p>They consist of numbers that are within the range of -(2<sup>53</sup> - 1) and (2<sup>53</sup> – 1), with both of these numbers inclusive. These two numbers are known as the <code>MIN_SAFE_INTEGER</code> and the <code>MAX_SAFE_INTEGER</code> respectively.</p>
<p>Numbers that exceed this range, belong to another data type called BigInt.</p>
<p>Here is an example of a positive integer, a float and a negative integer:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> number = <span class="hljs-number">15</span>;
<span class="hljs-keyword">let</span> anotherNumber = <span class="hljs-number">1.5</span>;
<span class="hljs-keyword">let</span> lastNumber = <span class="hljs-number">-3</span>;
</code></pre>
<h3 id="heading-boolean">Boolean</h3>
<p>The boolean type is logical, and it has only two values: true or false. It is commonly used in loops and conditional statements.</p>
<p>In the example below, I declared variables and assigned them a value of true and false respectively.</p>
<p>Then, I created a conditional statement that returns 1 if the <code>bool</code> variable is true or -1 if it is false. It returns zero if it is neither true nor false.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> positive = <span class="hljs-literal">true</span>;
<span class="hljs-keyword">let</span> negative = <span class="hljs-literal">false</span>;
<span class="hljs-keyword">let</span> bool = <span class="hljs-literal">false</span>;

<span class="hljs-comment">// conditional statement</span>
<span class="hljs-keyword">if</span> (bool) {
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (bool) {
    <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<h3 id="heading-object">Object</h3>
<p>An object type allows you to store collections of data. The data are stored in a pair of curly braces and a key-value pair format. Object keys must be textual (for example a string).</p>
<p>An object can store any of the other data types, like string, number, arrays, booleans, and so on.</p>
<p>In the example below I created an object named <code>myObject</code>, and gave it three keys with their corresponding values:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> myObject = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">"Gabriel"</span>,
    <span class="hljs-attr">number</span>: <span class="hljs-number">15</span>,
    <span class="hljs-attr">developer</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">"Daniel"</span>, <span class="hljs-number">1</span>]
}
</code></pre>
<h3 id="heading-null">Null</h3>
<p>Null data types are special data types. They have the value null which means that the value is unknown or empty:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> unknown = <span class="hljs-literal">null</span>;
</code></pre>
<h3 id="heading-undefined">Undefined</h3>
<p>Unlike null, undefined means that a variable is declared and not assigned a value. A variable can also be assigned undefined specifically:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> name = <span class="hljs-literal">undefined</span>;

<span class="hljs-keyword">let</span> newName;
<span class="hljs-built_in">console</span>.log(newName);
</code></pre>
<h3 id="heading-symbol">Symbol</h3>
<p>Symbols are used to create unique values. They are created by calling the <code>Symbol()</code> function. Every time the <code>Symbol()</code> function is invoked it creates a new unique value.</p>
<p>Symbols are kept hidden or private and they can only be used internally. For instance, they can be used as keys in an object. When you try to get the list of keys in an object where a symbol is part of its keys the symbol key will not be displayed.</p>
<p>You can pass a parameter to the symbol function to serve as a description for the symbol when debugging it in the console:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> firstSymbol = <span class="hljs-built_in">Symbol</span>();

<span class="hljs-keyword">let</span> anotherSymbol = <span class="hljs-built_in">Symbol</span>(anotherSymbol);
</code></pre>
<h3 id="heading-bigint">BigInt</h3>
<p>BigInt is a special type of number that provides support for numbers with a length that a normal number type can not hold (such as numbers that exceed the safe integer limit).</p>
<p>It can be created by appending n to the end of an integer or passing a number into the <code>BigInt</code> function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> bigNumber = <span class="hljs-number">175337823472347884278247898427427427642n</span>;
<span class="hljs-keyword">let</span> newBigNumber = BigInt(<span class="hljs-number">1624743724724724898718247248744774227422n</span>);

<span class="hljs-keyword">let</span> anotherBigNumber = BigInt(<span class="hljs-number">14</span>);
</code></pre>
<h2 id="heading-classes">Classes</h2>
<p>A JavaScript class is a template for creating objects. It contains data and functions that manipulate data.</p>
<p>Classes were introduced to JavaScript in the ECMAScript 2015 (ES6) version of JavaScript.</p>
<p>The functions used in classes are called methods.</p>
<p>There is a basic syntax for declaring classes looks something similar to the following:</p>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TemplateClass</span> </span>{
    <span class="hljs-keyword">constructor</span>() {...};
    method() {...};
    method() {...};
}
</code></pre>
<p>From the syntax you can create a class named <code>Visitor</code>:</p>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Visitor</span> </span>{
    <span class="hljs-keyword">constructor</span>(name) {
        <span class="hljs-built_in">this</span>.name = name;
    }
    introduce() {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`My name is <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> and I am a visitor`</span>)
    }
}
</code></pre>
<p>You can create a new class from this class by using the new class syntax. The newly created class can access any method from its parent class:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> visitor = <span class="hljs-keyword">new</span> Visitor(<span class="hljs-string">"Jeff"</span>);

<span class="hljs-comment">// visitor can call the introduce method in its parent class.</span>
visitor.introduce();
</code></pre>
<h2 id="heading-variables">Variables</h2>
<p>A variable is a named storage for JavaScript data. JavaScript variables can be declared in three ways:</p>
<ul>
<li><p>Using the <code>var</code> keyword</p>
</li>
<li><p>Using the <code>let</code> keyword</p>
</li>
<li><p>Using the <code>const</code> keyword</p>
</li>
</ul>
<h3 id="heading-how-to-declare-variables-using-the-var-keyword">How to declare variables using the <code>var</code> keyword</h3>
<p>Variables declared with the <code>var</code> keyword are function scoped and they can be redeclared:</p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> num = <span class="hljs-number">1</span>;

<span class="hljs-comment">// num can be redeclared</span>
<span class="hljs-keyword">var</span> num = <span class="hljs-number">2</span>;
</code></pre>
<h3 id="heading-how-to-declare-variables-using-the-let-keyword">How to declare variables using the <code>let</code> keyword</h3>
<p>Variables declared with the <code>let</code> keyword are block scoped and they cannot be redeclared – they can only be reassigned:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> fruit = <span class="hljs-string">"banana"</span>;

<span class="hljs-comment">// fruit can only be reassigned</span>
fruit = <span class="hljs-string">"orange"</span>;
</code></pre>
<h3 id="heading-how-to-declare-variables-using-the-const-keyword">How to declare variables using the <code>const</code> keyword</h3>
<p>Variables declared with the const keyword are block scoped and they cannot not be redeclared or reassigned (meaning they are constant):</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> bestStudent = <span class="hljs-string">"Daniel"</span>;
</code></pre>
<h2 id="heading-functions">Functions</h2>
<p>A function is a block of code that performs a specific task. It can be declared using the <code>function</code> keyword:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomething</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Does Something"</span>;
}
</code></pre>
<p>A function takes inputs called arguments and outputs results.</p>
<p>To execute a function you will invoke the function by calling the function name with enclosed brackets:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addNumbers</span>(<span class="hljs-params">a, b</span>) </span>{
    <span class="hljs-keyword">return</span> a + b;
}

addNumbers();
</code></pre>
<p>You can assign a function to a variable and call the variable when you want to invoke the function:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addNumbers</span>(<span class="hljs-params">a, b</span>) </span>{
    <span class="hljs-keyword">return</span> a + b;
}

<span class="hljs-keyword">let</span> numberAddition = addNumbers(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>)
numberAddition();
</code></pre>
<h2 id="heading-arrow-functions">Arrow Functions</h2>
<p>Arrow functions are a concise and compact way to write a function. They have some deliberate limitations in their usage:</p>
<ul>
<li><p>They cannot be used as a method.</p>
</li>
<li><p>They cannot be used as a constructor.</p>
</li>
<li><p>Arrow functions cannot use yield within their own bodies.</p>
</li>
</ul>
<p>Below is the syntax for an arrow function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> doSomething = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Do something"</span>;
}
</code></pre>
<p>An arrow function can also take an argument.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> multiplyNumbers = <span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> a * b;
}
</code></pre>
<h2 id="heading-this-keyword"><code>this</code> keyword</h2>
<p>The <code>this</code> keyword in JavaScript refers to an object that is executing a function or a code.</p>
<p>The <code>this</code> keyword can be used in different contexts – the context in which the <code>this</code> keyword is used determines what it refers to.</p>
<p>The <code>this</code> keyword can be used:</p>
<ul>
<li><p>In an object method.</p>
</li>
<li><p>Alone.</p>
</li>
<li><p>In object method bindings.</p>
</li>
</ul>
<h3 id="heading-how-to-use-the-this-keyword-in-an-object-method">How to use the <code>this</code> keyword in an object method</h3>
<p>The <code>this</code> keyword refers to the object whenever it is used as an object method:</p>
<pre><code class="lang-js">intro : <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"My name is"</span> + <span class="hljs-built_in">this</span>.name <span class="hljs-string">"and, I am a"</span> + <span class="hljs-built_in">this</span>.occupation;
}
</code></pre>
<h3 id="heading-how-to-use-the-this-keyword-alone">How to use the <code>this</code> keyword alone</h3>
<p>When <code>this</code> is used alone it refers to the global object:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> wes = <span class="hljs-built_in">this</span>;
</code></pre>
<h3 id="heading-how-to-use-the-this-keyword-in-object-method-bindings">How to use the <code>this</code> keyword in object method bindings</h3>
<p>When <code>this</code> is used in an object method, it refers to the object:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> student = {
  <span class="hljs-attr">firstName</span>  : <span class="hljs-string">"Juliana"</span>,
  <span class="hljs-attr">lastName</span>   : <span class="hljs-string">"Carpe"</span>,
  <span class="hljs-attr">myFunction</span> : <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }
};
</code></pre>
<h2 id="heading-loops">Loops</h2>
<p>Loops are useful for executing a block of code for a specified number of times based on some specified conditions. There are different types of loops in JavaScript:</p>
<ul>
<li><p><code>for</code> loops</p>
</li>
<li><p><code>for ... in</code> loops</p>
</li>
<li><p><code>for ... of</code> loops</p>
</li>
<li><p><code>while</code> loops</p>
</li>
<li><p><code>do ... while</code> loops</p>
</li>
</ul>
<h3 id="heading-how-to-use-for-loops">How to use <code>for</code> loops</h3>
<p><code>for</code> loops are used to execute a block of code a number of times:</p>
<pre><code class="lang-js"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</span>; i++) {
    <span class="hljs-keyword">return</span> i;
}
</code></pre>
<h3 id="heading-how-to-use-for-in-loops">How to use <code>for ... in</code> loops</h3>
<p><code>for ... in</code> loops are used to loop through the properties of an object:</p>
<pre><code class="lang-js"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> prop <span class="hljs-keyword">in</span> obj) {
    <span class="hljs-keyword">return</span> obj.prop;
}
</code></pre>
<h3 id="heading-how-to-use-for-of-loops">How to use <code>for ... of</code> loops</h3>
<p><code>for ... of</code> loops are used to loop through the values of iterable objects like arrays, strings, maps, and so on:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> numArr = [<span class="hljs-number">2</span>, <span class="hljs-number">4</span>, <span class="hljs-number">6</span>, <span class="hljs-number">8</span>]
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> val <span class="hljs-keyword">of</span> numArr) {
    <span class="hljs-keyword">return</span> val ** <span class="hljs-number">2</span>
}
</code></pre>
<h3 id="heading-how-to-use-while-loops">How to use <code>while</code> loops</h3>
<p><code>while</code> loops are used to execute a block of code while a certain condition still holds true:</p>
<pre><code class="lang-js"><span class="hljs-keyword">while</span> (i &lt; <span class="hljs-number">20</span>) {
    <span class="hljs-keyword">return</span> i;
    i++;
}
</code></pre>
<h3 id="heading-how-to-use-do-while-loops">How to use <code>do ... while</code> loops</h3>
<p><code>do ... while</code> loops execute a block of code first without any conditions. For as long as a certain condition still holds true it continues to execute the block of code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> i = <span class="hljs-number">3</span>;
<span class="hljs-keyword">do</span> {
    <span class="hljs-keyword">return</span> i;
    i++;
} 
<span class="hljs-keyword">while</span> (i &lt; <span class="hljs-number">4</span>)
</code></pre>
<h2 id="heading-scopes">Scopes</h2>
<p>The scope is the current context of execution. It is where variables and expressions can be accessed.</p>
<p>There is an hierarchical arrangement of scope in JavaScript. This makes it possible for lower scopes to access higher scopes.</p>
<p>The scopes in JavaScript are:</p>
<ul>
<li><p>Global scope</p>
</li>
<li><p>Module scope</p>
</li>
<li><p>Function scope</p>
</li>
<li><p>Block scope</p>
</li>
</ul>
<p>The global scope is the default scope for all codes running in script mode while the module scope is the default scope for all codes running in module mode.</p>
<p>The function scope is created by functions while the block scope is created by variables.</p>
<p>Here is an example of function and block scope:</p>
<pre><code class="lang-js"><span class="hljs-comment">// function scope</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">introduce</span>(<span class="hljs-params">name</span>) </span>{
    <span class="hljs-keyword">let</span> age = <span class="hljs-number">12</span>;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`My name is <span class="hljs-subst">${name}</span>`</span>);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`I am <span class="hljs-subst">${age}</span> years old`</span>);
}

<span class="hljs-keyword">let</span> firstAge = <span class="hljs-number">13</span>

<span class="hljs-comment">// block scope</span>
<span class="hljs-keyword">if</span> (firstAge === <span class="hljs-number">13</span>) {
    <span class="hljs-keyword">let</span> secondAge = <span class="hljs-number">20</span>;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`I am <span class="hljs-subst">${secondAge}</span> years old`</span>);
}
</code></pre>
<h2 id="heading-arrays">Arrays</h2>
<p>An array is a special type of an object that stores data in an ordered form.</p>
<p>Arrays can be declared in two ways:</p>
<ul>
<li><p>Using square brackets.</p>
</li>
<li><p>Using the the <code>Array()</code> constructor.</p>
</li>
</ul>
<h3 id="heading-how-to-declare-arrays-using-square-brackets">How to declare arrays using square brackets</h3>
<p>This is the common way of creating an array. It is done by wrapping the array's items in a pair of square brackets:</p>
<pre><code class="lang-js">  <span class="hljs-keyword">let</span> array = [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-string">"a"</span>, <span class="hljs-string">"c"</span>];
</code></pre>
<h3 id="heading-how-to-declare-arrays-using-the-the-array-constructor">How to declare arrays using the the <code>Array()</code> constructor</h3>
<p>The <code>Array()</code> constructor does the same thing as the bracket notation. It can be called with or without the <code>new</code> keyword:</p>
<pre><code class="lang-js">  <span class="hljs-keyword">let</span> anotherArray = <span class="hljs-built_in">Array</span>(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-string">"go"</span>);
</code></pre>
<h3 id="heading-how-to-access-array-elements">How to access array elements</h3>
<p>Array elements can be accessed in three ways:</p>
<ul>
<li><p>using their index.</p>
</li>
<li><p>using the array's <code>length</code> property.</p>
</li>
<li><p>using a loop</p>
</li>
</ul>
<h4 id="heading-how-to-access-an-array-element-using-its-index">How to access an array element using its index</h4>
<p>You call the name of the array with a square bracket containing the index you want to access:</p>
<pre><code class="lang-js"> <span class="hljs-keyword">let</span> newArray = [<span class="hljs-string">"Idris"</span>, <span class="hljs-string">"Daniel"</span>, <span class="hljs-string">"Joseph"</span>];

  <span class="hljs-comment">// To access first element</span>
  <span class="hljs-keyword">let</span> firstElement = newArray[<span class="hljs-number">0</span>]; 
  <span class="hljs-built_in">console</span>.log(firstElement);  <span class="hljs-comment">// Idris</span>

  <span class="hljs-comment">// To access second element </span>
  <span class="hljs-keyword">let</span> secondElement = newArray[<span class="hljs-number">1</span>];  
  <span class="hljs-built_in">console</span>.log(secondElement);  <span class="hljs-comment">// Joseph</span>
</code></pre>
<h3 id="heading-how-to-access-an-array-element-using-the-arrays-length-property">How to access an array element using the array's <code>length</code> property</h3>
<p>You can get the length of the array using the <code>length</code> property. Then, you will subtract any number from it to get the index of the element you want to access:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> newArray = [<span class="hljs-string">"Idris"</span>, <span class="hljs-string">"Daniel"</span>, <span class="hljs-string">"Joseph"</span>];

  <span class="hljs-keyword">let</span> length = newArray.length;

  <span class="hljs-keyword">let</span> firstElement = newArray[length - <span class="hljs-number">3</span>]; 
  <span class="hljs-built_in">console</span>.log(firstElement);  <span class="hljs-comment">// Idris</span>

  <span class="hljs-keyword">let</span> secondElement = newArray[length - <span class="hljs-number">2</span>];
  <span class="hljs-built_in">console</span>.log(secondElement);  <span class="hljs-comment">// Joseph</span>
</code></pre>
<h4 id="heading-how-to-access-an-array-element-using-a-loop">How to access an array element using a loop</h4>
<p>Array elements can be accessed using loops. You can make use of a <code>for</code> loop, <code>while</code> loop, or a <code>for ... of</code> loop:</p>
<pre><code class="lang-js">  <span class="hljs-keyword">let</span> newArray = [<span class="hljs-string">"Idris"</span>, <span class="hljs-string">"Daniel"</span>, <span class="hljs-string">"Joseph"</span>];
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; newArray.length; i++) {
      <span class="hljs-keyword">return</span> newArray[i]
  }
</code></pre>
<h3 id="heading-important-array-methods">Important Array methods</h3>
<p>There are over fifteen array methods in JavaScript. In this article, you will learn the ones that are most useful in Node.js:</p>
<ul>
<li><p><code>push()</code> and <code>pop()</code></p>
</li>
<li><p><code>shift()</code> and <code>unshift()</code></p>
</li>
<li><p><code>map()</code></p>
</li>
<li><p><code>sort()</code></p>
</li>
<li><p><code>forEach()</code></p>
</li>
</ul>
<h4 id="heading-how-to-use-the-push-and-pop-methods">How to use the <code>push()</code> and <code>pop()</code> methods</h4>
<p>The <code>push()</code> method is used to add an item to the end of an array, while the <code>pop()</code> method is used to remove an item from the end of an array:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> arr = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">9</span>]

arr.push(<span class="hljs-number">21</span>);

<span class="hljs-built_in">console</span>.log(arr)    <span class="hljs-comment">// [1, 2, 3, 9, 21]</span>

arr.pop()

<span class="hljs-built_in">console</span>.log(arr)    <span class="hljs-comment">// [1, 2, 3, 9]</span>
</code></pre>
<h4 id="heading-how-to-use-the-unshift-and-shift-methods">How to use the <code>unshift()</code> and <code>shift()</code> methods</h4>
<p>The <code>unshift()</code> method is used to add an item to the beginning of an array, while the <code>shift()</code> method is used to remove an item from the beginning of an array:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> arr = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];

arr.unshift(<span class="hljs-number">0</span>);

<span class="hljs-built_in">console</span>.log(arr);    <span class="hljs-comment">// [0, 1, 2, 3]</span>

arr.shift();

connsole.log(arr);    <span class="hljs-comment">// [1, 2, 3]</span>
</code></pre>
<h4 id="heading-how-to-use-the-map-method">How to use the <code>map()</code> method</h4>
<p>The <code>map()</code> method iterates through the elements of an array and calls a function on each element of the array. It returns a new array that contains the result of each function call:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> fruits = [<span class="hljs-string">"Apple"</span>, <span class="hljs-string">"Grape"</span>, <span class="hljs-string">"Cashew"</span>];

<span class="hljs-keyword">let</span> mappedFruits = fruits.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item + <span class="hljs-string">"s"</span>);
<span class="hljs-built_in">console</span>.log(mappedFruits); <span class="hljs-comment">// ["Apples", "Grapes", "Cashews"]</span>
</code></pre>
<h4 id="heading-how-to-use-the-sort-method">How to use the <code>sort()</code> method</h4>
<p>The <code>sort()</code> method sorts an array in place and returns the same array in a sorted form.</p>
<p>The default order of the <code>sort()</code> method is ascending order. Strings are sorted in alphabetical order:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> numbers = [<span class="hljs-number">8</span>, <span class="hljs-number">7</span>, <span class="hljs-number">5</span>];
<span class="hljs-keyword">let</span> fruits = [<span class="hljs-string">"Apple"</span>, <span class="hljs-string">"Grape"</span>, <span class="hljs-string">"Cashew"</span>];

<span class="hljs-keyword">let</span> sortedNumbers = numbers.sort();
<span class="hljs-keyword">let</span> sortedFruits = fruits.sort()

<span class="hljs-built_in">console</span>.log(sortedNumbers);  <span class="hljs-comment">// [5, 7, 8]</span>
<span class="hljs-built_in">console</span>.log(sortedFruits);  <span class="hljs-comment">// ["Apple", "Cashew", "Grape"]</span>
</code></pre>
<h4 id="heading-how-to-use-the-foreach-method">How to use the forEach() method</h4>
<p>The <code>forEach()</code> method loops through the array and calls a function for every element of the array:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> fruits = [<span class="hljs-string">"Apple"</span>, <span class="hljs-string">"Grape"</span>, <span class="hljs-string">"Cashew"</span>];

fruits.forEach(<span class="hljs-function"><span class="hljs-params">fruit</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(fruit));
<span class="hljs-comment">//  "Apple"</span>
<span class="hljs-comment">//  "Grape"</span>
<span class="hljs-comment">//  "Cashew"</span>
</code></pre>
<h2 id="heading-template-literals">Template Literals</h2>
<p>Template literals are enclosed in backticks, just like strings are enclosed in quotes. They allow you to store multiline strings and also interpolate strings with embedded expressions.</p>
<p>The example below shows a basic template literal:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> basic = <span class="hljs-string">`I write codes`</span>
</code></pre>
<p>You can write a template literal that stores multiline strings like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> multiLine = <span class="hljs-string">`I write codes                     
        I debug codes`</span>;
</code></pre>
<p>You can use the dollar sign and curly braces to embed expressions in template literals.</p>
<p>In the example below, the function <code>myName</code> is embedded in the display variable with a template literal:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myName</span>(<span class="hljs-params">Musab, Habeeb</span>) </span>{        
    alert(<span class="hljs-string">"Musab Habeeb"</span>);    
}    

<span class="hljs-keyword">let</span> display = <span class="hljs-string">`This displays my name <span class="hljs-subst">${myName()}</span>`</span>
</code></pre>
<h2 id="heading-strict-mode">Strict mode</h2>
<p>JavaScript is a sloppy language in the sense that it allows you to write code that is not allowed in other languages. Some of the code you write in JavaScript has errors but, JavaScript does not throw an error.</p>
<p>Strict mode does the following:</p>
<ul>
<li><p>It throws errors for JavaScript silent errors.</p>
</li>
<li><p>It fixes mistakes that makes it difficult for JavaScript engines to perform optimizations.</p>
</li>
<li><p>It prohibits some syntax likely to be defined in future versions of the ECMAScript.</p>
</li>
</ul>
<p>Strict mode works in an entire script file and functions, but it does not work in block scopes.</p>
<p>To invoke script mode you will add the <code>"use strict";</code> syntax to the top of the code you want to apply it to. You can apply strict mode to a script like this:</p>
<pre><code class="lang-js"><span class="hljs-meta">"use strict"</span>;

<span class="hljs-keyword">let</span> name = <span class="hljs-string">"Musab"</span>;

<span class="hljs-built_in">console</span>.log(name);
</code></pre>
<p>Also, you can apply strict mode to a function like this:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sayHi</span>(<span class="hljs-params">name</span>) </span>{
<span class="hljs-meta">    "use strict"</span>;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hi <span class="hljs-subst">${name}</span>`</span>);
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Finally, you are done with learning the JavaScript concepts you need to understand before learning Node.js.</p>
<p>All these concepts are important concepts that a JavaScript Developer aspiring to learn Node.js should understand. Understanding these concepts will make learning Node.js easier.</p>
<p>But, to understand these concepts in depth, you can do more research on each of them and read other articles. Keep learning, keep building.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A Quick Look at Bun 1.0 – The Node.js Alternative ]]>
                </title>
                <description>
                    <![CDATA[ By Nishant Kumar A wise man once told me, "When you start eating Bun, Node.js will feel bland". But why is that relevant? JavaScript got way faster with a new JavaScript runtime called Bun, which is now production-ready with its version 1.0 release. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-quick-look-at-bun-js/</link>
                <guid isPermaLink="false">66d4603fa326133d12440a35</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 15 Sep 2023 07:58:01 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/09/But-why-is-that-relevant--2-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nishant Kumar</p>
<p>A wise man once told me, "When you start eating Bun, Node.js will feel bland".</p>
<p>But why is that relevant? JavaScript got way faster with a new JavaScript runtime called Bun, which is now production-ready with its version 1.0 release.</p>
<p>But how and why is it faster than Node.js? A lot of questions come to mind.</p>
<p>I'll answer some of those questions in this article. And I'll do that quickly as I am now faster just like my pal, JavaScript, cooking in the oven with Bun 1.0.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/But-why-is-that-relevant--3-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Bun is a fast, all-in-one toolkit for running, building, testing, and debugging JavaScript and TypeScript, from a single file to a full-stack application.</p>
<p>Here are some things we can do with Bun.</p>
<h2 id="heading-run-your-code-faster-with-bun">Run your Code Faster with Bun</h2>
<p>Now, we don’t need tools like <code>npm</code>, <code>pnpm</code>, or <code>yarn</code> because Bun is 17 times faster. Take a look at the data below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Bun takes only 0.36 seconds to compile your code, whereas it takes about 6.44 seconds in the case of pnpm, 10.58 seconds with npm, and 12.08 seconds with yarn.</p>
<h2 id="heading-bun-supports-hot-reloading">Bun Supports Hot Reloading</h2>
<p>Bun supports hot reloading out of the box so you don’t need tools like Nodemon. It will automatically refresh the server when running JavaScript or TypeScript Code.</p>
<p>You can replace <code>npm run</code> with <code>bun run</code> to save over 150ms milliseconds every time you run a command.</p>
<p>Here is the full chart:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/Screenshot-2023-09-14-at-7.17.45-PM-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>From the chart above, using <code>npm</code> takes about 176ms to run, <code>yarn</code> takes about 131ms. In the case of <code>pnpm</code>, it takes 259ms. However, it takes about 7ms in the case of <code>Bun</code>. That's fast, isn't it?</p>
<h2 id="heading-bun-as-a-javascript-bundler">Bun as a JavaScript Bundler</h2>
<p>Bun is also a JavaScript bundler with best-in-class performance and an ESBuild-compatible plugin API, so we don’t need things like:</p>
<ul>
<li>ESBuild</li>
<li>Webpack</li>
<li>Parcel, .parcelrc</li>
<li>Rollup, rollup.config.js</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/But-why-is-that-relevant--2-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Bun now supports Next.js, Remix, Nuxt, Astro, SvelteKit, Nest, SolidStart, and Vite.</p>
<h3 id="heading-bun-has-both-esm-and-commonjs-compatibility">Bun has both ESM and CommonJS Compatibility</h3>
<p>Another great feature about Bun is that we can use ES Modules and CommonJs together in the same file, which was not possible in Node.js.</p>
<p>You can use <code>import</code> and <code>require()</code> in the same file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> lodash <span class="hljs-keyword">from</span> <span class="hljs-string">"lodash"</span>;
<span class="hljs-keyword">const</span> _ = <span class="hljs-built_in">require</span>(<span class="hljs-string">"underscore"</span>);
</code></pre>
<p>Apart from that, Bun has built-in support for the Web standard APIs that are available in browsers, such as <code>fetch</code>, along with extra Bun APIs like <code>Bun.file()</code> to lazy read a file and <code>Bun.Write()</code> to write a file to the local file system which is a lot simpler than Node.js.</p>
<h4 id="heading-bunfile-example"><code>Bun.file()</code> Example</h4>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> file = Bun.file(<span class="hljs-string">"package.json"</span>);
<span class="hljs-keyword">const</span> contents = <span class="hljs-keyword">await</span> file.text();
</code></pre>
<p>The code above will read the contents of a <code>package.json</code> file and transfer its content to a new variable called <code>contents</code>. </p>
<h4 id="heading-bunwrite-example"><code>Bun.write()</code> Example</h4>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> Bun.write(<span class="hljs-string">"index.html"</span>, <span class="hljs-string">"&lt;html/&gt;"</span>);
<span class="hljs-keyword">await</span> Bun.write(<span class="hljs-string">"index.html"</span>, Buffer.from(<span class="hljs-string">"&lt;html/&gt;"</span>));
<span class="hljs-keyword">await</span> Bun.write(<span class="hljs-string">"index.html"</span>, Bun.file(<span class="hljs-string">"home.html"</span>));
<span class="hljs-keyword">await</span> Bun.write(<span class="hljs-string">"index.html"</span>, 
<span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://example.com/"</span>));
</code></pre>
<p>In the code above, <code>Bun.write()</code> will write the string <code>"&lt;html/&gt;"</code>, or copy the contents of <code>home.html</code> file into the <code>index.html</code> file. If we have to fetch data, it will fetch the results from an external web API and write the contents to a <code>index.html</code> file.</p>
<h2 id="heading-why-is-bun-so-fast">Why is Bun so fast?</h2>
<p>Bun is fast because it uses the JavaScriptCore engine, while Node.js uses the JavaScript V8 engine. The former has been optimized for faster startup time.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/But-why-is-that-relevant.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you want to get things done faster, you should consider replacing Node.js with Bun.</p>
<h2 id="heading-how-to-get-started-with-bun">How to Get Started With Bun</h2>
<p>You cam install Bun on MacOS and Linux systems using npm:</p>
<pre><code class="lang-javascript">npm install -g bun
</code></pre>
<p>Now you are all set. To install a npm package, do this:</p>
<pre><code class="lang-javascrpt">bun install &lt;package-name&gt;
</code></pre>
<p>To start a Next.js app, do this:</p>
<pre><code class="lang-javascript">bun run dev
</code></pre>
<p>All you need to do is replace <code>npm</code> with <code>bun</code>.</p>
<p>However, Bun is only ready for production in MacOS and Linux operating systems. The Windows version is still experimental. At the moment, only the JavaScript runtime is supported for Windows, and not the package manager, the bundler, or the test runner. You can read more about that <a target="_blank" href="https://bun.sh/docs/installation#windows">here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This article shows how you can use Bun as a Node.js alternative and speed up your development time.</p>
<p>You can also check out my video on <strong><a target="_blank" href="https://youtu.be/q5UKY_dCmh4?si=satm6TAv6Zmh5OCn">The Node.js killer is here — Bun 1.0 First Look</a></strong>.</p>
<p>Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Task Manager CLI Tool with Node.js ]]>
                </title>
                <description>
                    <![CDATA[ By Krish Jaiswal Hello everyone 👋 In this tutorial, you'll learn how to make a simple Task Manager CLI (Command Line Interface) tool. This means you can use commands to Create, View, Update, or Delete your todos.  We will be building this CLI tool u... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/nodejs-tutorial-build-a-task-manager-cli-tool/</link>
                <guid isPermaLink="false">66d4601633b83c4378a517f0</guid>
                
                    <category>
                        <![CDATA[ cli ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 29 Aug 2023 14:19:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/Add-a-heading--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Krish Jaiswal</p>
<p>Hello everyone 👋 In this tutorial, you'll learn how to make a simple Task Manager CLI (Command Line Interface) tool. This means you can use commands to Create, View, Update, or Delete your todos. </p>
<p>We will be building this CLI tool using NodeJS. We'll also use MongoDB as the database to store all our to-dos. Finally, we'll use a few helpful packages from npm:</p>
<ul>
<li><strong><a target="_blank" href="https://www.npmjs.com/package/commander">commander</a></strong>: This helps us to build the CLI tool.</li>
<li><strong><a target="_blank" href="https://www.npmjs.com/package/chalk">chalk</a></strong>: This makes messages in the terminal colorful and easy to read.</li>
<li><strong><a target="_blank" href="https://www.npmjs.com/package/inquirer">inquirer</a></strong>: This lets us ask the user for input.</li>
<li><strong><a target="_blank" href="https://www.npmjs.com/package/ora">ora</a></strong>: This makes the terminal show nice spinning animations.</li>
</ul>
<p>Before we dive in, I want you to know that you can find the complete code for this project on GitHub. If you're ever unsure about something in the code, you can always refer to the final version there. </p>
<p>Here is the link to the Repository: <a target="_blank" href="https://github.com/KrishJ4856/task-manager-cli-fcc">Task Manager CLI Tool Repo</a>.</p>
<h2 id="heading-table-of-contents">Table Of Contents:</h2>
<ul>
<li><a class="post-section-overview" href="#heading-project-setup">Project Setup</a>  </li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-packagejson-file">How to create the <code>package.json</code> file</a>  </li>
<li><a class="post-section-overview" href="#heading-how-to-install-dependencies">How to install dependencies</a>  </li>
<li><a class="post-section-overview" href="#heading-how-to-convert-commonjs-modules-to-es-modules">How to convert CommonJS modules to ES modules</a>  </li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-folder-structure">How to create the folder structure</a></li>
<li><a class="post-section-overview" href="#heading-how-to-connect-to-the-database">How to Connect to the Database</a>  </li>
<li><a class="post-section-overview" href="#heading-how-to-obtain-a-mongodb-connection-string">How to obtain a MongoDB connection string</a>  </li>
<li><a class="post-section-overview" href="#heading-code-for-connecting-to-the-database">Code for connecting to the database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-mongoose-model">How to Create a Mongoose Model</a></li>
<li><a class="post-section-overview" href="#working-on-crud-operations">Working on CRUD Operations</a>  </li>
<li><a class="post-section-overview" href="#heading-how-to-create-todos">How to create Todos</a>  </li>
<li><a class="post-section-overview" href="#heading-how-to-read-todos">How to reading Todos</a>  </li>
<li><a class="post-section-overview" href="#heading-how-to-delete-todos">How to deleting Todos</a>  </li>
<li><a class="post-section-overview" href="#heading-how-to-update-todos">How to update Todos</a></li>
<li><a class="post-section-overview" href="#heading-how-to-write-the-cli-entry-point-using-commander">How to Write the CLI Entry Point using Commander</a></li>
<li><a class="post-section-overview" href="#heading-how-to-test-the-cli-tool">How to Test the CLI tool</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h1 id="heading-project-setup">Project Setup</h1>
<p>Welcome to the first section of this handbook! Here, we will be setting up our project. </p>
<p>This involves a few simple steps: creating a new directory, setting up the <code>package.json</code> file, and installing necessary npm packages like chalk, inquirer, commander, and others we'll talk about soon. We'll also organize the project by creating folders.</p>
<p>Before we dive in, let's ensure you have NodeJS installed on your system. You can get the latest LTS version from this website: <a target="_blank" href="https://nodejs.org/en">https://nodejs.org/en</a>. </p>
<p>To check if Node is properly installed, type this command: <code>node --version</code>. If you see a version number, you're all set! If not, you need to troubleshoot the errors.</p>
<p>Once NodeJS is up and running, create a new folder named "todo." You can use your favorite code editor (I prefer Visual Studio Code) or follow these steps in your terminal:</p>
<ol>
<li>Make a new folder: <code>mkdir todo</code></li>
<li>Go inside the folder: <code>cd todo</code></li>
<li>Open it in your code editor: <code>code .</code></li>
</ol>
<h2 id="heading-how-to-create-the-packagejson-file">How to Create the <code>package.json</code> File</h2>
<p>The first and foremost step is setting up the <code>package.json</code> file. But don't worry about doing it manually. You can save time by using this command:</p>
<pre><code class="lang-bash">npm init --yes
</code></pre>
<p>Once this step is done, let's move on to the next step and get all the necessary things for our project.</p>
<h2 id="heading-how-to-install-dependencies">How to Install Dependencies</h2>
<p>To build this project, we'll need some packages. Just run this simple command to get them all:</p>
<pre><code class="lang-bash">npm i commander inquirer chalk ora mongoose nanoid dotenv
</code></pre>
<h2 id="heading-how-to-convert-commonjs-modules-to-es-modules">How to Convert CommonJS Modules to ES Modules</h2>
<p>Before you continue, let's make a little change in the <code>package.json</code> file. Remove this line: <code>"main": "index.js"</code>, and add these two lines instead:</p>
<pre><code class="lang-json"><span class="hljs-string">"exports"</span>: <span class="hljs-string">"./index.js"</span>,
 <span class="hljs-string">"type"</span>: <span class="hljs-string">"module"</span>,
</code></pre>
<p>With these changes, we're converting our project from CommonJS Modules to ES Modules. This means we'll use <code>import</code> instead of <code>require()</code> to bring in modules, and <code>export</code> instead of <code>module.exports</code> to share things between files.</p>
<p>If you want to dive deeper into different types of modules in JavaScript and how they work, check out this tutorial on FreeCodeCamp: <a target="_blank" href="https://www.freecodecamp.org/news/modules-in-javascript/">Modules in JavaScript - CommonJS and ESmodules Explained.</a></p>
<h2 id="heading-how-to-create-the-folder-structure">How to Create the Folder Structure</h2>
<p>Now, let's organize our project by setting up a smart folder structure. This means we'll make folders to neatly hold our JavaScript files. This step's really important. It makes things easy to manage and develops smoothly.</p>
<p>We're creating 3 folders and 2 files in the main folder:</p>
<p><strong>First folder:</strong> <code>commands</code>. Inside this folder, you'll create 4 files. The names of the files and the description of the code they will contain is mentioned below:</p>
<ul>
<li><code>addTask.js</code>: Code for Creating a new todo.</li>
<li><code>deleteTask.js</code>: Code for Deleting a todo.</li>
<li><code>readTask.js</code>: Code for Displaying all the todos.</li>
<li><code>updateTask.js</code>: Code for Updating a todo.</li>
</ul>
<p><strong>Second folder:</strong> <code>db</code>. Inside this folder, add a file named <code>connectDB.js</code>. This file will contain the code for connecting to the MongoDB database and disconnecting when needed.</p>
<p><strong>Third folder:</strong> <code>schema</code>. Inside it, make a file named <code>TodoSchema.js</code>. This file stores the Mongoose Schema and Model. Basically, a blue print for our tasks, that is how our tasks will look.</p>
<p><strong>First file:</strong> <code>.env</code>. Create this file inside the root directory / main folder of the project. This is where you'll put your MongoDB Connection string.</p>
<p><strong>Second file:</strong> Create the <code>index.js</code> file in the root directory itself which will serve as the entry point of our project. It's like the project's front – where everything starts.</p>
<p>Once we are done, your project's folders should look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/image-141.png" alt="Image showing the folder structure for the project" width="600" height="400" loading="lazy">
<em>Project folder structure</em></p>
<h1 id="heading-how-to-connect-to-the-database">How to Connect to the Database</h1>
<p>Now that you've successfully set up the project, it's time to dive into the exciting part.</p>
<h2 id="heading-how-to-obtain-a-mongodb-connection-string">How to Obtain a MongoDB Connection String</h2>
<p>To keep track of all our todos, we need a place to store them. That's where MongoDB Atlas comes in. It's like a special service that handles databases for us. The best part? You can start using it for free (no credit card needed). </p>
<p>To connect to it, all you need is something called a connection string. If MongoDB Atlas is new to you, don't worry. Check out this easy-to-follow article: <a target="_blank" href="https://www.freecodecamp.org/news/get-started-with-mongodb-atlas/">MongoDB Atlas Tutorial - How to Get Started</a>. It gives you just enough info to start using Atlas. By the time you're done, you'll know how to get what you need, including the connection string.</p>
<p>Once you have that connection string, create a new thing called an "environment variable." It's like a secret code your project uses. Open the <code>.env</code> file and make a line like this: <code>MONGO_URI=</code>. After the <code>=</code>, put in your connection string.</p>
<p>Remember: Replace <code>&lt;password&gt;</code> with your actual password and <code>&lt;username&gt;</code> with the username of your database admin in the connection string. Also, add <code>todos</code> between <code>/?</code> in the string. When you're done, your <code>.env</code> file should look something like this:</p>
<pre><code class="lang-text">MONGO_URI=mongodb+srv://&lt;username&gt;:&lt;password&gt;@cluster0.k5tmsld.mongodb.net/todos?retryWrites=true&amp;w=majority
</code></pre>
<h2 id="heading-code-for-connecting-to-the-database">Code for Connecting to the Database</h2>
<p>Now, let's dive into the code that connects our tool to the MongoDB database. Open up the <code>./db/connectDB.js</code> file and let's write some code to make this connection happen.</p>
<p>First things first, we need to bring in the <code>dotenv</code> package that we grabbed earlier when we were setting up the project and invoke the <code>config()</code> method on <code>dotenv</code>. This helps us load environment variables from the <code>.env</code> file. Here's how you do it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> dotenv <span class="hljs-keyword">from</span> <span class="hljs-string">'dotenv'</span>
dotenv.config()
</code></pre>
<p>Next up, we want to import a few more packages that we'll use here. These are <code>mongoose</code>, <code>ora</code>, and <code>chalk</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>
<span class="hljs-keyword">import</span> ora <span class="hljs-keyword">from</span> <span class="hljs-string">'ora'</span>
<span class="hljs-keyword">import</span> chalk <span class="hljs-keyword">from</span> <span class="hljs-string">'chalk'</span>
</code></pre>
<p><strong>Note:</strong> <code>mongoose</code> is an Object Data Modeling (ODM) library for MongoDB. It provides a higher-level abstraction making it easier to do things like adding, reading, updating, and deleting stuff from the MongoDB database.</p>
<p>Now, let's get into the real action. We'll define two functions here: <code>connectDB()</code> and <code>disconnectDB()</code>.</p>
<p>The <code>connectDB()</code> function will contain the code to help connect our NodeJS Application to the M0ngoDB Database using <code>mongoose</code>. It's like a phone call connecting them. If we don't establish a connection first, our app won't be able to interact with the database and perform the various CRUD operations.</p>
<p>The <code>disconnectDB()</code> function does the opposite. It's like hanging up the phone after our app is done talking to the database. If we don't disconnect, it's like keeping the call going even after we're done. </p>
<p>Failing to disconnect from the database after we are done interacting with it could cause resource leaks. These may cause your app to slow down or potentially crash over time.</p>
<p>Let me show you the code for both the functions:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">connectDB</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> spinner = ora(<span class="hljs-string">'Connecting to the database...'</span>).start()
        <span class="hljs-keyword">await</span> mongoose.connect(process.env.MONGO_URI)
        spinner.stop()
        <span class="hljs-built_in">console</span>.log(chalk.greenBright(<span class="hljs-string">'Successfully connected to database!!!'</span>))   
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(chalk.redBright(<span class="hljs-string">'Error: '</span>), error);
        process.exit(<span class="hljs-number">1</span>) 
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">disconnectDB</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">await</span> mongoose.disconnect()
        <span class="hljs-built_in">console</span>.log(chalk.greenBright(<span class="hljs-string">'Disconnected from the database.'</span>))
    } <span class="hljs-keyword">catch</span>(err) {
        <span class="hljs-built_in">console</span>.log(chalk.redBright(<span class="hljs-string">'Error: '</span>), error);
        process.exit(<span class="hljs-number">1</span>) 
    }
}
</code></pre>
<p>This is a lot of code to digest at one time, so let me explain this for you:</p>
<p>In the <code>connectDB()</code> function, the line <code>mongoose.connect(process.env.MONGO_URI)</code> helps us actually connect to the database using the connection string. </p>
<p>Remember the <code>.env</code> file? We're using its info here. To load the <code>MONGO_URI</code> variable, we use the <code>dotenv</code> package and call the <code>config()</code> function and then we can access it using <code>process.env.MONGO_URI</code>. </p>
<p>Since <code>mongoose.connect()</code> returns a promise, we use the <code>await</code> keyword before it to make sure we proceed only when this returned promise gets resolved.</p>
<p>It is possible to encounter some errors while running this code, so we have wrapped the entire code in a <code>try...catch()</code> block to make sure any errors which pop up are handled properly in the <code>catch()</code> block.</p>
<p>The <code>ora</code> package helps us show a spinner while we connect to the database. Once successfully connected, we stop the spinner and show a happy message in green using <code>chalk</code>.</p>
<p>If you notice, we are doing the same thing in the <code>disconnectDB()</code> function. But, instead of connecting, we disconnect from the database using <code>mongoose.disconnect()</code>. We wrap it in a similar try-catch block, and again we show colorful messages using <code>chalk</code>.</p>
<p>We use <code>export</code> before these functions to let other parts of the project use them. Don't forget to add these two temporary lines at the end of the file for now:</p>
<pre><code class="lang-javascript">connectDB()
disconnectDB()
</code></pre>
<p>Now, you can run the <code>connectDB.js</code> file using the command: <code>node ./db/connectDB.js</code> and expect to see this in the console:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/rec1.gif" alt="GIF showing the output messages shown in the terminal when the connectDB.js file is executed" width="600" height="400" loading="lazy">
<em>Output seen on the terminal when <code>connectDB.js</code> file is executed. It shows how our code successfully connects to the database and disconnects from it showing appropriate console messages when we invoke the <code>connectDB()</code> and <code>disconnectDB()</code> methods.</em></p>
<p>Connecting to the database is a big step, but you're making great progress! Before moving ahead, make sure you remove those 2 lines you added at the end because they were added just to check if our connection and disconnection functions are working as expected.</p>
<h1 id="heading-how-to-create-a-mongoose-model">How to Create a Mongoose Model</h1>
<p>A Mongoose model is like a tool that helps us talk to the database. With it, we can easily do things like add, read, update, and delete tasks. It's like a helpful assistant that understands how to communicate with the database.</p>
<p>To make this model, we need something called a Schema. It basically defines what each task should look like. Think of it as a blueprint or a set of instructions that guides how each task is created, what information it should have, and how that information is organized. It's like setting rules for how our tasks are stored in the database.</p>
<p>We're going to build this Schema in the <code>./schema/TodoSchema.js</code> file. Open it up, and let's dive in. First, we need two special tools: <code>mongoose</code> and <code>nanoid</code>. We'll use <code>nanoid</code> to make short and unique IDs for each task.</p>
<p>Type these lines to import the tools:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>
<span class="hljs-keyword">import</span> {nanoid} <span class="hljs-keyword">from</span> <span class="hljs-string">'nanoid'</span>
</code></pre>
<p>Now, we use the <code>mongoose.Schema()</code> method to create our Schema. Here's the code for it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> TodoSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
    <span class="hljs-attr">name</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">detail</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">status</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">enum</span>: [<span class="hljs-string">'completed'</span>, <span class="hljs-string">'pending'</span>],
        <span class="hljs-attr">default</span>: <span class="hljs-string">'pending'</span>,
        <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">code</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">default</span>: <span class="hljs-string">'code'</span>,
        <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>
    }
}, {<span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span>})
</code></pre>
<p>Any task created using this Schema will have the following properties:</p>
<ul>
<li><code>name</code>: This is a short title for the task. The <code>type: String</code> emphasizes that it can only be text (a String). The <code>required: true</code> specifies that we have to provide this when creating a task and the <code>trim: true</code> specifies that any extra spaces at the beginning or at the end of the task's name will be removed before saving it in the database.</li>
<li><code>detail</code>: This is a description of the task. It has exactly the same properties as <code>name</code>.</li>
<li><code>status</code>: This shows if the task is done or not. The <code>enum: ['completed', 'pending']</code> property specifies that it can only be <code>completed</code> or <code>pending</code>. The <code>default: 'pending'</code> property specifies that if you do not set the <code>status</code> property while creating the task, it is assumed to be <code>pending</code>.</li>
<li><code>code</code>: This is a short and unique ID for the task. We are giving it a default value of <code>code</code>. This value is just a placeholder and doesn't have any real significance in terms of identifying the task. Don't worry, we'll change it soon.</li>
<li>The <code>{timestamps: true}</code> is a configuration option that automatically adds timestamp fields like <code>createdAt</code> and <code>updatedAt</code> to the tasks when they are created or modified.</li>
</ul>
<p>We have successfully defined our Schema – but you may wonder if the <code>code</code> property was supposed to be unique for every task. Currently it stores the same value, that is "<strong>code</strong>", for every single task. Don't worry, we'll fix that. Add this code at the end:</p>
<pre><code class="lang-javascript">TodoSchema.pre(<span class="hljs-string">'save'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">next</span>)</span>{
    <span class="hljs-built_in">this</span>.code = nanoid(<span class="hljs-number">10</span>)
    next()
})
</code></pre>
<p>Here, <code>TodoSchema.pre('save', function(){....})</code> helps us defining a pre-save hook/function which runs every time before a task gets saved in the database. </p>
<p>Inside the function, we use <code>nanoid(10)</code> to create a unique, 10 character long ID for the task and put this generated id in the <code>code</code> field of the task (we can actually access any property/field of the task using the <code>this</code> keyword). </p>
<p>The last line of code: <code>next()</code> basically tells the computer that we are done and it can finally save the document now. With this, we generate a unique ID for every single task created using the <code>nanoid</code> package.</p>
<p>Lastly, we'll make a <code>Todos</code> model using this <code>TodoSchema</code> blueprint and export it. This is how:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Todos = mongoose.model(<span class="hljs-string">'Todos'</span>, TodoSchema)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Todos
</code></pre>
<p>And there you go! We've built our Schema and Model. Now let's proceed to the next section of this tutorial.</p>
<h1 id="heading-how-to-work-on-crud-operations">How to Work on CRUD Operations</h1>
<p>Congrats for having successfully followed up till here. So far, we have done 3 things:</p>
<ol>
<li>We've set up the project</li>
<li>We've connected to the MongoDB database, and</li>
<li>We've created the Mongoose Model</li>
</ol>
<p>Up next, we will be working on the various CRUD operations like Creating, Reading, Updating, and Deleting the tasks from our database.</p>
<h2 id="heading-how-to-create-todos">How to Create Todos</h2>
<p>Now, let's start with creating tasks in our project. At first, I planned for a simple process where you add one task to the database at a time. This means when you tell the tool to create a task, it asks you once for the task's details—like the name and description—and then it saves the task.</p>
<p>But then I realized, what if someone wants to add many tasks quickly? Doing it one by one isn't cool. There are two issues:</p>
<ol>
<li>If you have, say, 5 tasks in your mind, you'd have to type the create command 5 times—one for each task.</li>
<li>After entering task details, you wait a bit because saving stuff to the database can take time, especially if the internet is slow.</li>
</ol>
<p>These problems aren't fun at all! To fix this, we need a way to add multiple tasks in one go. Here's how we'll do it:</p>
<p>After you put in the task's name and description, we'll ask if you want to add more tasks. If you enter yes, we continue the process from the start (asking you to again enter the name and description of the next task). But if you enter no, the question prompting process will stop and all the entered tasks get saved to the database together. This way, you can create many tasks without the hassle of doing it one by one. It's all about making things smooth for you.</p>
<p>We'll be writing some code in the <code>./commands/addTask.js</code> file. This is where the magic happens. Let's break it down step by step:</p>
<p>First, we import the necessary packages and functions we've created earlier. You can add these lines of code to do that:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> inquirer <span class="hljs-keyword">from</span> <span class="hljs-string">"inquirer"</span>;
<span class="hljs-keyword">import</span> { connectDB, disconnectDB } <span class="hljs-keyword">from</span> <span class="hljs-string">'../db/connectDB.js'</span>
<span class="hljs-keyword">import</span> Todos <span class="hljs-keyword">from</span> <span class="hljs-string">"../schema/TodoSchema.js"</span>;
<span class="hljs-keyword">import</span> ora <span class="hljs-keyword">from</span> <span class="hljs-string">"ora"</span>;
<span class="hljs-keyword">import</span> chalk <span class="hljs-keyword">from</span> <span class="hljs-string">"chalk"</span>;
</code></pre>
<p>Now, we create an asynchronous function called <code>input()</code> to gather the task's name and details from the user. Here's how it goes:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">input</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">const</span> answers = <span class="hljs-keyword">await</span> inquirer.prompt([
        { <span class="hljs-attr">name</span>: <span class="hljs-string">'name'</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Enter name of the task:'</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'input'</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">'detail'</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Enter the details of the task:'</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'input'</span> },
    ])

    <span class="hljs-keyword">return</span> answers
}
</code></pre>
<p>In simple terms, <code>input()</code> uses <code>inquirer</code> to ask the user for the task's name and details. The answers are then returned as an object.</p>
<p>But wait, you might wonder what <code>inquirer.prompt()</code> is doing. It's a method in the <code>inquirer</code> package that asks questions and waits for responses. You provide an array of question objects, each containing details like the message to display to the user and the type of question. The function returns a Promise, so we use <code>await</code> to wait for the user's answers which get's returned as an object.</p>
<p>Here, <code>{ name: 'name', message: 'Enter name of the task:', type: 'input' }</code> is the first question that will be asked to the user. The <code>message</code> property contains the question that will be displayed to the user. In our case, it is: <code>Enter the name of the task</code>. The user will be prompted to input some text (a String), since this question is of <code>type: 'input'</code>. The <code>name: 'name'</code> signifies that the user's answer to this question will be assigned to a property named – <code>name</code> in the answer's object.</p>
<p>The next object is the second question that will be asked to the user. In this case, a message will be displayed in the terminal: <code>Enter the details of the task</code> and the user's response will be assigned to a property called <code>detail</code> in the answer's object.</p>
<p>To see how the above code works, you can add these 2 lines of code at the end of the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> output = <span class="hljs-keyword">await</span> input()
<span class="hljs-built_in">console</span>.log(output)
</code></pre>
<p>Now, save the file and run the code using the command: <code>node ./commands/addTask.js</code>. This is what you will see when you run the code:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/image-166.png" alt="Image of the terminal showing what `inquirer.prompt()` function returns as output." width="600" height="400" loading="lazy">
<em>Output seen on terminal when we just invoke the <code>input()</code> method and execute the code. It shows how <code>inquirer.js</code> returns user's answers after the question prompting process.</em></p>
<p>We can now proceed with the rest of the code and you can remove the last 2 lines which you just added.</p>
<p>Now, let's create a function named <code>askQuestions()</code> to gather multiple tasks. This is how it looks:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> askQuestions = <span class="hljs-keyword">async</span>() =&gt; {

    <span class="hljs-keyword">const</span> todoArray = []
    <span class="hljs-keyword">let</span> loop = <span class="hljs-literal">false</span>

    <span class="hljs-keyword">do</span>{
        <span class="hljs-keyword">const</span> userRes = <span class="hljs-keyword">await</span> input()
        todoArray.push(userRes)
        <span class="hljs-keyword">const</span> confirmQ = <span class="hljs-keyword">await</span> inquirer.prompt([{ <span class="hljs-attr">name</span>: <span class="hljs-string">'confirm'</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Do you want to add more tasks?'</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'confirm'</span> }])
        <span class="hljs-keyword">if</span>(confirmQ.confirm){
            loop = <span class="hljs-literal">true</span>
        } <span class="hljs-keyword">else</span> {
            loop = <span class="hljs-literal">false</span>
        }
    } <span class="hljs-keyword">while</span>(loop)

    <span class="hljs-keyword">return</span> todoArray
}
</code></pre>
<p>In <code>askQuestions()</code>, we set up a loop that keeps asking for tasks until the user decides to stop. We gather each task from the user by calling the <code>input()</code> function, and the returned user's response gets pushed to the <code>todoArray</code>. </p>
<p>Then, we ask if the user wants to add more tasks using a confirmation question. If they say yes, we set <code>loop</code> to <code>true</code> and the loop continues – otherwise, <code>loop</code> becomes <code>false</code>, and the loop ends. Finally, we return the array of tasks, that is <code>todoArray</code>.</p>
<p>You can test this by adding these lines of code at the end of the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> output = <span class="hljs-keyword">await</span> askQuestions()
<span class="hljs-built_in">console</span>.log(output)
</code></pre>
<p>When you run the file using <code>node ./commands/addTask.js</code>, you'll see a similar result to what you see here:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/image-167.png" alt="Image of the terminal showing the array of tasks/todos returned by `askQuestions()` function" width="600" height="400" loading="lazy">
<em>Output seen on terminal when we invoke the <code>askQuestions()</code> method and execute the code. It shows the array of tasks returned by the method when the user does not want to continue adding more tasks.</em></p>
<p>We are almost there! Before proceeding, do not forget to remove the last 2 lines you added just now. After you've done that, let's move ahead.</p>
<p>Up to this point, we have successfully managed to collect all the tasks the user wants to create. </p>
<p>Now, let's define the last piece of the puzzle: the <code>addTask()</code> function. This function brings everything together and completes the task creation process. Here's the full code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addTask</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// calling askQuestions() to get array of todo's</span>
        <span class="hljs-keyword">const</span> userResponse = <span class="hljs-keyword">await</span> askQuestions()

        <span class="hljs-comment">// connecting to the database</span>
        <span class="hljs-keyword">await</span> connectDB()

        <span class="hljs-comment">// Displaying a spinner with the following text message using ora </span>
        <span class="hljs-keyword">let</span> spinner = ora(<span class="hljs-string">'Creating the todos...'</span>).start()

        <span class="hljs-comment">// looping over every todo in the userResponse array</span>
        <span class="hljs-comment">// and saving each todo in the database</span>
        <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i&lt;userResponse.length; i++){
            <span class="hljs-keyword">const</span> response = userResponse[i]
            <span class="hljs-keyword">await</span> Todos.create(response)
        }

        <span class="hljs-comment">// Stopping the spinner and displaying the success message</span>
        spinner.stop()
        <span class="hljs-built_in">console</span>.log(
            chalk.greenBright(<span class="hljs-string">'Created the todos!'</span>)
        )

        <span class="hljs-comment">// disconnecting the database</span>
        <span class="hljs-keyword">await</span> disconnectDB()
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-comment">// Error Handling</span>
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Something went wrong, Error: '</span>, error)
        process.exit(<span class="hljs-number">1</span>)
    }
}
</code></pre>
<p>The <code>addTask()</code> function starts by calling the <code>askQuestions()</code> function to gather the array of tasks and assigning it to the <code>userResponse</code> variable. Then, it connects to the database using <code>connectDB()</code>, displays a spinner using <code>ora</code> to show the task creation process, loops through each task in the array, and saves it to the database using <code>Todos.create(response)</code>. </p>
<p>Once all tasks are saved, the spinner stops, a success message is shown, and then it disconnects from the database using <code>disconnectDB()</code>.</p>
<p>The entire code is wrapped in a <code>try...catch</code> block to handle any potential errors gracefully.</p>
<p>With this code, you've completed the task creation process. Nice work! This was probably the most complex piece of code in the entire project. Future operations such as reading, deleting and updating tasks are going to be fairly simple and easy by comparison. With that said, let's move to performing the Read operation.</p>
<h2 id="heading-how-to-read-todos">How to Read Todos</h2>
<p>Now we'll explore how to read tasks from the MongoDB database. The process is straightforward, and I'll guide you through the entire code in the <code>./commands/readTask.js</code> file:</p>
<p>First, let's import the necessary packages and functions at the beginning of the file:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Importing packages and functions</span>
<span class="hljs-keyword">import</span> { connectDB, disconnectDB } <span class="hljs-keyword">from</span> <span class="hljs-string">'../db/connectDB.js'</span>
<span class="hljs-keyword">import</span> Todos <span class="hljs-keyword">from</span> <span class="hljs-string">'../schema/TodoSchema.js'</span>
<span class="hljs-keyword">import</span> chalk <span class="hljs-keyword">from</span> <span class="hljs-string">'chalk'</span>
<span class="hljs-keyword">import</span> ora <span class="hljs-keyword">from</span> <span class="hljs-string">'ora'</span>
</code></pre>
<p>Now, let's define an asynchronous function named <code>readTask()</code> which encapsulates the logic for reading tasks. The whole function is wrapped in a try...catch block for handling any potential errors:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readTask</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// connecting to the database</span>
        <span class="hljs-keyword">await</span> connectDB()

        <span class="hljs-comment">// starting the spinner</span>
        <span class="hljs-keyword">const</span> spinner = ora(<span class="hljs-string">'Fetching all todos...'</span>).start()

        <span class="hljs-comment">// fetching all the todos from the database </span>
        <span class="hljs-keyword">const</span> todos = <span class="hljs-keyword">await</span> Todos.find({})

        <span class="hljs-comment">// stopping the spinner</span>
        spinner.stop()

        <span class="hljs-comment">// check if todos exist or not</span>
        <span class="hljs-keyword">if</span>(todos.length === <span class="hljs-number">0</span>){
            <span class="hljs-built_in">console</span>.log(chalk.blueBright(<span class="hljs-string">'You do not have any tasks yet!'</span>))
        } <span class="hljs-keyword">else</span> {
            todos.forEach(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> {
                <span class="hljs-built_in">console</span>.log(
                    chalk.cyanBright(<span class="hljs-string">'Todo Code: '</span>) + todo.code + <span class="hljs-string">'\n'</span> + 
                    chalk.blueBright(<span class="hljs-string">'Name: '</span>) + todo.name + <span class="hljs-string">'\n'</span> + 
                    chalk.yellowBright(<span class="hljs-string">'Description: '</span>) + todo.detail + <span class="hljs-string">'\n'</span>
                )
            })
        }

        <span class="hljs-comment">// disconnect from the database</span>
        <span class="hljs-keyword">await</span> disconnectDB()
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-comment">// Error Handling</span>
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Something went wrong, Error: '</span>, error)
        process.exit(<span class="hljs-number">1</span>)
    }
}

readTask()
</code></pre>
<p>Now, let's break down the code step by step:</p>
<ol>
<li>We establish a connection to the MongoDB database using <code>await connectDB()</code>.</li>
<li>We start a spinner using <code>ora</code> to indicate that we are fetching all the todos.</li>
<li>We fetch all the todos from the database using <code>Todos.find({})</code>. Once the process is complete, the <code>todos</code> variable will contain either an empty array (if no tasks exists in the database) or an array of tasks.</li>
<li>After fetching is complete, we stop the spinner using <code>spinner.stop()</code>.</li>
<li>We check whether there are any todos by checking if <code>todos.length</code> is equal to 0. If it is, we display a message in blue saying "You do not have any tasks yet!". If there are todos in the array (which means that the length of the array is not equal to 0), we loop through each todo in the array and print its code, name, and description using <code>chalk</code> for color formatting.</li>
<li>Finally, we disconnect from the database using <code>await disconnectDB()</code>.</li>
</ol>
<p>In the last line of code, we call the <code>readTask()</code> function. This is only for testing purposes, and you can remove this line as instructed.</p>
<p>To run the code, use the command: <code>node ./commands/readTask.js</code>. When you execute this, you'll see something similar to the output shown here:</p>
<p>Note: I had created some random tasks before, so when I run the <code>readTask.js</code> file, I get to see this in my terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Untitled-video---Made-with-Clipchamp--1-.gif" alt="GIF showing the output which is displayed in the terminal as a result of running the `readTask.js` file" width="600" height="400" loading="lazy">
<em>Output seen on terminal when <code>readTask.js</code> file is executed. It shows how the code successfully reads all the tasks from the database and prints it out in the terminal.</em></p>
<p>Before we proceed, don't forget to remove the last line of code in the <code>readTask.js</code> file because we won't be needing it in the future. </p>
<p>With this code, you've successfully implemented the read functionality for your task manager CLI tool. Great job! In the upcoming sections, we'll explore how to delete and update tasks.</p>
<h2 id="heading-how-to-delete-todos">How to Delete Todos</h2>
<p>This section of the tutorial covers the simple process of deleting todos from the database. The logic is straightforward: users enter the Todo code of the todo they want to delete, and we remove that todo from the database. </p>
<p>Let's delve into the code to make this happen in the <code>./commands/deleteTask.js</code> file.</p>
<p>The first step is to import necessary packages and functions at the beginning of the file, including inquirer, <code>Todos</code> model, connectDB(), disconnectDB(), ora, and chalk.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Importing packages and functions</span>
<span class="hljs-keyword">import</span> inquirer <span class="hljs-keyword">from</span> <span class="hljs-string">"inquirer"</span>;
<span class="hljs-keyword">import</span> Todos <span class="hljs-keyword">from</span> <span class="hljs-string">'../schema/TodoSchema.js'</span>
<span class="hljs-keyword">import</span> {connectDB, disconnectDB} <span class="hljs-keyword">from</span> <span class="hljs-string">'../db/connectDB.js'</span>
<span class="hljs-keyword">import</span> ora <span class="hljs-keyword">from</span> <span class="hljs-string">"ora"</span>;
<span class="hljs-keyword">import</span> chalk <span class="hljs-keyword">from</span> <span class="hljs-string">"chalk"</span>;
</code></pre>
<p>Up next, we will define an asynchronous function called <code>getTaskCode()</code>. The role of this function is to prompt the user to enter the code of the todo they want to delete using <code>inquirer</code>. The function then trims the code entered by the user using the <code>trim()</code> method and returns the trimmed code. The trimming process is necessary to remove the leading or trailing whitespace which the code might contain.</p>
<p>Here is the code for the <code>getTaskCode()</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTaskCode</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Prompting the user to enter the todo code</span>
        <span class="hljs-keyword">const</span> answers = <span class="hljs-keyword">await</span> inquirer.prompt([
            {<span class="hljs-attr">name</span>: <span class="hljs-string">'code'</span>, <span class="hljs-string">'message'</span>: <span class="hljs-string">'Enter the code of the todo: '</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'input'</span>},
        ])

        <span class="hljs-comment">// Trimming user's response so that the todo code does not contain any starting or trailing white spaces</span>
        answers.code = answers.code.trim()

        <span class="hljs-keyword">return</span> answers
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Something went wrong...\n'</span>, error)
    }
}
</code></pre>
<p>Now we will define the main function named <code>deleteTask()</code>. The entire code is below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteTask</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Obtaining the todo code provided by user</span>
        <span class="hljs-keyword">const</span> userCode = <span class="hljs-keyword">await</span> getTaskCode()

        <span class="hljs-comment">// Connecting to the database</span>
        <span class="hljs-keyword">await</span> connectDB()

        <span class="hljs-comment">// Starting the spinner</span>
        <span class="hljs-keyword">const</span> spinner = ora(<span class="hljs-string">'Finding and Deleting the todo...'</span>).start()

        <span class="hljs-comment">// Deleting the task</span>
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> Todos.deleteOne({<span class="hljs-attr">code</span>: userCode.code})

        <span class="hljs-comment">// Stopping the spinner</span>
        spinner.stop()

        <span class="hljs-comment">// Checking the delete operation</span>
        <span class="hljs-keyword">if</span>(response.deletedCount === <span class="hljs-number">0</span>){
            <span class="hljs-built_in">console</span>.log(chalk.redBright(<span class="hljs-string">'Could not find any todo matching the provided name. Deletion failed.'</span>))
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">console</span>.log(chalk.greenBright(<span class="hljs-string">'Deleted Task Successfully'</span>))
        }

        <span class="hljs-comment">// Disconnecting from the database</span>
        <span class="hljs-keyword">await</span> disconnectDB()
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-comment">// Error Handling</span>
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Something went wrong, Error: '</span>, error)
        process.exit(<span class="hljs-number">1</span>)
    }
}
</code></pre>
<p>Let's break down this code step-by-step:</p>
<ol>
<li>We obtain the response object which includes the todo code entered by the user by calling the <code>getTaskCode()</code> function defined above. We then assign this object to the <code>userCode</code> variable.</li>
<li>We connect to the database using <code>await connectDB()</code>.</li>
<li>We start a spinner using <code>ora</code> to indicate that we're finding and deleting the todo.</li>
<li>We use <code>Todos.deleteOne({ code: userCode.code })</code> to search for and delete the todo with a matching code. The response will indicate if any document was deleted or not.</li>
<li>After the operation is complete, we stop the spinner using <code>spinner.stop()</code>.</li>
<li>We use an if...else condition to check the <code>deletedCount</code> property in the response. If it's 0, we print a message indicating that the task with the provided code wasn't found and deletion failed. If <code>deletedCount</code> is greater than 0, we print a success message.</li>
<li>We disconnect from the database using <code>await disconnectDB()</code>.</li>
</ol>
<p>If I call the function: <code>deleteTask()</code> and then proceed to run the code using <code>node /commands/deleteTask.js</code> command, I get to see this in my console:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Untitled-video---Made-with-Clipchamp--1---1-.gif" alt="GIF showing the output which is displayed in the terminal as a result of running the `deleteTask.js` file" width="600" height="400" loading="lazy">
<em>Output seen on terminal when<code>deleteTask.js</code> file is executed. It shows how the code successfully deletes a single task from the database.</em></p>
<p>As you can see in the above GIF, the code will prompt you to enter a Todo code for the task you want to delete. Upon deletion, you'll receive a confirmation message in the console. When we read all our tasks after the deletion process, we don't get to see the deleted task. This implies that our code is successful in doing what it is supposed to do!</p>
<h2 id="heading-how-to-update-todos">How to Update Todos</h2>
<p>In this section, we will be looking at the code to update a specific todo. Updating a todo is a bit more involved compared to the previous operations. The process unfolds as follows:</p>
<ol>
<li>Prompt the user to input the code of the todo to be updated.</li>
<li>Connect to the database.</li>
<li>Find the task whose code property matches the user's input.</li>
<li>If the task doesn't exist, display a message indicating the failure to find a matching todo.</li>
<li>If the task exists, prompt the user to update the <code>name</code>, <code>description</code> and <code>status</code> of the task. </li>
<li>If the user sets the status property of a task to "completed," then that task is deleted. If set to "pending," the task's name and description are updated in the database.</li>
<li>Display a success message in the console after the update operation.</li>
</ol>
<p>Let's start coding! The first thing you need to do is to import all the packages and functions we will need to perform this job.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Importing packages and functions</span>
<span class="hljs-keyword">import</span> {connectDB, disconnectDB} <span class="hljs-keyword">from</span> <span class="hljs-string">'../db/connectDB.js'</span>
<span class="hljs-keyword">import</span> { getTaskCode } <span class="hljs-keyword">from</span> <span class="hljs-string">'./deleteTask.js'</span>
<span class="hljs-keyword">import</span> inquirer <span class="hljs-keyword">from</span> <span class="hljs-string">'inquirer'</span>
<span class="hljs-keyword">import</span> Todos <span class="hljs-keyword">from</span> <span class="hljs-string">'../schema/TodoSchema.js'</span>
<span class="hljs-keyword">import</span> ora <span class="hljs-keyword">from</span> <span class="hljs-string">'ora'</span>
<span class="hljs-keyword">import</span> chalk <span class="hljs-keyword">from</span> <span class="hljs-string">'chalk'</span>
</code></pre>
<p>Before we start working on our <code>updateTask()</code> function, we will create a small function in the same file named <code>askUpdateQ()</code>. The role of this function is to prompt the user to enter the updated values of the task like the task name, description, and status. At the end, this function will return the response object. </p>
<p>Here is the code for it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">askUpdateQ</span>(<span class="hljs-params">todo</span>)</span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Prompting the user to update the todo data</span>
        <span class="hljs-keyword">const</span> update = <span class="hljs-keyword">await</span> inquirer.prompt([
            {<span class="hljs-attr">name</span>: <span class="hljs-string">'name'</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Update the name?'</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'input'</span>, <span class="hljs-attr">default</span>: todo.name},
            {<span class="hljs-attr">name</span>: <span class="hljs-string">'detail'</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Update the Description?'</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'input'</span>, <span class="hljs-attr">default</span>: todo.detail},
            {<span class="hljs-attr">name</span>: <span class="hljs-string">'status'</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Update the status'</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'list'</span>, <span class="hljs-attr">choices</span>: [<span class="hljs-string">'pending'</span>, <span class="hljs-string">'completed'</span>], <span class="hljs-attr">default</span>: todo.status}
        ])

        <span class="hljs-keyword">return</span> update
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Something went wrong... \n'</span>, error)
    }
}
</code></pre>
<p>Two things are to be noted here:</p>
<ol>
<li><code>todo</code> is the original task object (the task which the user wants to update). This will be passed to the <code>askUpdateQ()</code> function by the <code>updateTask()</code> function.</li>
<li>Each question object within the array passed to <code>inquirer.prompt()</code> contains a default property set to the original values of the task. This ensures that if the user skips a question, the default value remains unchanged.</li>
</ol>
<p>With that said, now let's look at the code for the <code>updateTask()</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateTask</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Obtaining the task code entered by user by calling getTaskCode() method</span>
        <span class="hljs-keyword">const</span> userCode = <span class="hljs-keyword">await</span> getTaskCode()

        <span class="hljs-comment">// Connecting to the database</span>
        <span class="hljs-keyword">await</span> connectDB()

        <span class="hljs-comment">// Starting the spinner</span>
        <span class="hljs-keyword">const</span> spinner = ora(<span class="hljs-string">'Finding the todo...'</span>).start()

        <span class="hljs-comment">// Finding the todo which the user wants to update</span>
        <span class="hljs-keyword">const</span> todo = <span class="hljs-keyword">await</span> Todos.findOne({<span class="hljs-attr">code</span>: userCode.code})

        <span class="hljs-comment">// Stopping the spinner</span>
        spinner.stop()

        <span class="hljs-comment">// Checking if the todo exists or not</span>
        <span class="hljs-keyword">if</span>(!todo){
            <span class="hljs-built_in">console</span>.log(chalk.redBright(<span class="hljs-string">'Could not find a Todo with the code you provided.'</span>))
        } <span class="hljs-keyword">else</span>{
            <span class="hljs-built_in">console</span>.log(chalk.blueBright(<span class="hljs-string">'Type the updated properties. Press Enter if you don\'t want to update the data.'</span>))

            <span class="hljs-comment">// Get the user's response of the updated data by calling askUpdateQ() method</span>
            <span class="hljs-keyword">const</span> update = <span class="hljs-keyword">await</span> askUpdateQ(todo)

            <span class="hljs-comment">// If user marked status as completed, we delete the todo else we update the data</span>
            <span class="hljs-keyword">if</span>(update.status === <span class="hljs-string">'completed'</span>){
                <span class="hljs-comment">// Changing spinner text and starting it again</span>
                spinner.text = <span class="hljs-string">'Deleting the todo...'</span>
                spinner.start()

                <span class="hljs-comment">// Deleting the todo</span>
                <span class="hljs-keyword">await</span> Todos.deleteOne({<span class="hljs-attr">_id</span> : todo._id})

                <span class="hljs-comment">// Stopping the spinner and display the success message</span>
                spinner.stop()
                <span class="hljs-built_in">console</span>.log(chalk.greenBright(<span class="hljs-string">'Deleted the todo.'</span>))
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-comment">// Update the todo</span>
                spinner.text = <span class="hljs-string">'Updating the todo'</span>
                spinner.start()
                <span class="hljs-keyword">await</span> Todos.updateOne({<span class="hljs-attr">_id</span>: todo._id}, update, {<span class="hljs-attr">runValidators</span>: <span class="hljs-literal">true</span>})
                spinner.stop()
                <span class="hljs-built_in">console</span>.log(chalk.greenBright(<span class="hljs-string">'Updated the todo.'</span>))
            }
        }
        <span class="hljs-comment">// Disconnecting from the database</span>
        <span class="hljs-keyword">await</span> disconnectDB()
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-comment">// Error Handling</span>
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Something went wrong, Error: '</span>, error)
        process.exit(<span class="hljs-number">1</span>)
    }
}
</code></pre>
<p>Here's a breakdown of the above code:</p>
<ol>
<li>Obtain the code of the task which the user wants to update. For this, we are utilizing the <code>getTaskCode()</code> function defined in the <code>./commands/deleteTask.js</code> file. We simply call the function and assign the returned response object to the <code>userCode</code> variable.</li>
<li>Connect to the database using <code>await connectDB()</code>.</li>
<li>Start a spinner to indicate that the code is finding the todo.</li>
<li>Use <code>Todos.findOne({ code: userCode.code })</code> to find the task the user wants to update and assign it to the <code>todo</code> variable. We are doing this because we will need the original values of the task.</li>
<li>Stop the spinner.</li>
<li>If no matching task is found, display a message using <code>chalk</code> indicating that the task wasn't found.</li>
<li>If the task is found, prompt the user to input updated properties by calling the <code>askUpdateQ()</code> function and pass the <code>todo</code> object (original task) in the function. Assign the returned object to <code>update</code> variable.</li>
<li>If the user marks the status as "completed," the task is deleted from the database using <code>deleteOne()</code>. If marked as "pending," the task's name and description are updated using <code>updateOne()</code>.   </li>
</ol>
<p><code>updateOne()</code> method takes in 3 parameters – Query Object, Update Object, and the Options object. Here, <code>{_id: todo._id}</code> is the Query Object. Mongoose searches the entire collection for a task whose <code>id</code> property matches with <code>todo_.id</code>. On finding the task, it replaces the task with the update object, that is <code>update</code> in our case. The third parameter, <code>{ runValidators: true }</code>, ensures that Mongoose validates the <code>update</code> object against the schema's rules before executing it. If the validation fails, the update will be rejected, and you'll receive an error. If the validation is successful, the document will be updated successfully in the database.  </p>
<p>Both in case of the Delete and Update Operation, we change the text of the spinner using <code>spinner.text</code> and start it before performing the operation and once the operation is completed, we stop the spinner.</p>
<ol start="9">
<li>Display appropriate success messages in the console based on the operation performed.</li>
<li>Disconnect from the database using <code>await disconnectDB()</code>.</li>
</ol>
<p>If I call the <code>updateTask()</code> function and run the code using the command: <code>node ./commands/updateTask.js</code>, I get to see something like this in my console:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/update.gif" alt="GIF showing the output which is displayed in the terminal as a result of running the `updateTask.js` file" width="600" height="400" loading="lazy">
<em>Output seen on terminal when <code>updateTask.js</code> file is executed. It shows how the code successfully fetches the original task and successfully replaces it with the updated values provided by the user.</em></p>
<p>With this, you've successfully implemented all CRUD operations. Now, let's use the <code>commander</code> library to bring everything together and create a fully functional CLI tool.</p>
<h1 id="heading-how-to-write-the-cli-entry-point-using-commander">How to Write the CLI Entry Point using Commander</h1>
<p>In the final stages of our project, we're going to leverage the power of the <code>commander</code> library to craft a user-friendly CLI interface. With <code>commander</code>, we can neatly define different commands – such as read, add, update, and delete – in an organized and intuitive manner.</p>
<p>Our code will reside in the <code>index.js</code> file, which serves as the entry point of our application. Below is the complete code:</p>
<pre><code class="lang-javascript"><span class="hljs-meta">#!/usr/bin/env node</span>

<span class="hljs-comment">// Importing the required functions for each command</span>
<span class="hljs-keyword">import</span> addTask <span class="hljs-keyword">from</span> <span class="hljs-string">'./commands/addTask.js'</span>
<span class="hljs-keyword">import</span> deleteTask <span class="hljs-keyword">from</span> <span class="hljs-string">'./commands/deleteTask.js'</span>
<span class="hljs-keyword">import</span> readTask <span class="hljs-keyword">from</span> <span class="hljs-string">'./commands/readTask.js'</span>
<span class="hljs-keyword">import</span> updateTask <span class="hljs-keyword">from</span> <span class="hljs-string">'./commands/updateTask.js'</span>

<span class="hljs-comment">// Importing the Command class from Commander.js library</span>
<span class="hljs-keyword">import</span> { Command } <span class="hljs-keyword">from</span> <span class="hljs-string">'commander'</span>

<span class="hljs-comment">// Creating an instance of the Command class</span>
<span class="hljs-keyword">const</span> program = <span class="hljs-keyword">new</span> Command()

<span class="hljs-comment">// Setting the name and description of the CLI tool</span>
program
.name(<span class="hljs-string">'todo'</span>)
.description(<span class="hljs-string">'Your terminal task manager!'</span>)
.version(<span class="hljs-string">'1.0.0'</span>)

<span class="hljs-comment">// Defining a command called 'add'</span>
program
.command(<span class="hljs-string">'add'</span>)
.description(<span class="hljs-string">'Create a new todo.'</span>)
.action(addTask)

<span class="hljs-comment">// Defining a command called 'read'</span>
program
.command(<span class="hljs-string">'read'</span>)
.description(<span class="hljs-string">'Reads all the todos.'</span>)
.action(readTask)

<span class="hljs-comment">// Defining a command called 'update'</span>
program
.command(<span class="hljs-string">'update'</span>)
.description(<span class="hljs-string">'Updates a todo.'</span>)
.action(updateTask)

<span class="hljs-comment">// Defining a command called 'delete'</span>
program
.command(<span class="hljs-string">'delete'</span>)
.description(<span class="hljs-string">'Deletes a todo.'</span>)
.action(deleteTask)

<span class="hljs-comment">// Parsing the command-line arguments and executing the corresponding actions</span>
program.parse()
</code></pre>
<ol>
<li>The very first line, <code>#!/usr/bin/env node</code>, is a "shebang." It informs the system to execute the script using the Node.js interpreter. This enables us to run the script directly from the command line without explicitly typing <code>node</code> before the script filename.</li>
<li>Next, we import all the required functions that contain the logic for each command.</li>
<li>The line <code>import { Command } from 'commander'</code> imports the <code>Command</code> class from the Commander.js library. The subsequent line, <code>const program = new Command()</code>, creates an instance of the <code>Command</code> class. This instance is essential for defining and managing commands for our CLI tool.</li>
<li>We then set the CLI tool's information. The <code>.name()</code>, <code>.description()</code>, and <code>.version()</code> methods set the name, description, and version of our CLI tool. These details are displayed when users invoke the tool with specific flags such as <code>--help</code> or <code>--version</code>.</li>
<li>Next, we define the various commands. Each <code>program.command()</code> block defines a command for our CLI tool. Within each block, the command's name is set using a string argument (for example, <code>'add'</code>, <code>'read'</code>). The <code>.description()</code> method provides the command's description, while the <code>.action()</code> method associates a function (for example, <code>addTask</code>, <code>readTask</code>) with a specific command. When a user enters a command in the terminal, this associated function is executed.</li>
<li>The <code>program.parse()</code> line is essential for parsing the command-line arguments provided by the user. Based on the command entered, Commander.js will execute the associated action function.</li>
</ol>
<h1 id="heading-how-to-test-the-cli-tool">How to Test the CLI Tool</h1>
<p>We're now nearly at the finish line of creating our Task Manager CLI tool! Before we can install and utilize the tool, we just need to make a small adjustment to the <code>package.json</code> file. Simply add the following entry to the JSON file:</p>
<pre><code class="lang-json"><span class="hljs-string">"bin"</span>: {
  <span class="hljs-attr">"todo"</span>: <span class="hljs-string">"index.js"</span>
}
</code></pre>
<p>If you've ever built a CLI tool and wish for users to access it from the command line in a manner similar to commands like <code>node</code> or <code>npm</code>, then the "bin" property comes into play.</p>
<p>The "bin" property in the <code>package.json</code> file enables you to specify commands that become globally accessible once your package is installed. In simpler terms, it lets you create shortcuts for running specific scripts or functions from the command line. </p>
<p>The provided code instructs Node.js to execute the script defined in <code>index.js</code> whenever someone enters <code>todo</code> in the terminal. In essence, this transforms your script into a globally accessible command-line tool.</p>
<p>The final step before you can start using the tool is to install it globally on your system! Run the following command to do so:</p>
<pre><code class="lang-text">npm i -g .
</code></pre>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Congratulations if you've followed along this far! You're now fully equipped to begin using your Task Manager CLI tool.</p>
<p>Here are the commands you can use to operate the tool:</p>
<ul>
<li><code>todo add</code>  – Create a new task</li>
<li><code>todo read</code> – Read all your pending tasks</li>
<li><code>todo update</code> – Update a specific task</li>
<li><code>todo delete</code> – Delete a task</li>
</ul>
<p>You can also use these 2 options using the tool:</p>
<ul>
<li><code>todo --version</code> or <code>todo -V</code> – To know the version number of this tool</li>
<li><code>todo --help</code> or <code>todo -h</code> – To display help for command</li>
</ul>
<p>And that wraps up this handbook. I hope you've found it enjoyable and informative. </p>
<p>I encourage you to share your learning journey on Twitter and LinkedIn using the hashtag #LearnInPublic. Also, be sure to follow freeCodeCamp for more informative coding tutorials.</p>
<p>If you are facing any issues while following along with this tutorial, you can always refer to the entire code available on GitHub - <a target="_blank" href="https://github.com/KrishJ4856/task-manager-cli-fcc">Task Manager CLI GitHub Repo</a>. You can also connect with me on Twitter (X) - <a target="_blank" href="https://twitter.com/Krish4856">@Krish4856</a>. My DM's are open!</p>
<p>See you next time! 👋 ❤️ ✨</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
