<?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[ Express 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[ Express JS - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 29 May 2026 16:31:44 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/express-js/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <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 Streamline Your File Upload Process in Express.js with Multer ]]>
                </title>
                <description>
                    <![CDATA[ By Kelvin Moses File uploading is a common requirement in web development projects. But handling file uploads in Node.js can be complex and time-consuming. That's where Multer comes in.  Multer is a powerful middleware for Node.js that simplifies the... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/simplify-your-file-upload-process-in-express-js/</link>
                <guid isPermaLink="false">66d45f33264384a65d5a9536</guid>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 12 Jun 2023 21:05:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/file-stream.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Kelvin Moses</p>
<p>File uploading is a common requirement in web development projects. But handling file uploads in Node.js can be complex and time-consuming. That's where Multer comes in. </p>
<p>Multer is a powerful middleware for Node.js that simplifies the file upload process by handling multipart/form-data requests. In this tutorial, you will learn how to leverage the power of Multer to streamline your file upload process.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>To follow along with this tutorial and implement the file upload process using Multer, you should have the following prerequisites:</p>
<ol>
<li>Basic knowledge of JavaScript and Node.js: Familiarity with JavaScript and Node.js is essential to understand the concepts and code examples in this tutorial.</li>
<li>Node.js and npm: Ensure that you have Node.js and npm (Node Package Manager) installed on your machine. You can download and install them from the official Node.js website: <a target="_blank" href="https://nodejs.org">https://nodejs.org</a>.</li>
<li>A text editor or an integrated development environment (IDE): You'll need a text editor or an IDE to write and edit your code. Popular choices include Visual Studio Code, Sublime Text, Atom, or WebStorm.</li>
<li>Command-line interface (CLI): You should be comfortable using the command line or terminal to run commands and navigate through your project's directory structure.</li>
<li>Basic understanding of HTML: This tutorial assumes a basic understanding of HTML to create an HTML form for file uploads.</li>
</ol>
<p>By ensuring that you have these prerequisites in place, you'll be ready to follow along and implement the file upload process using Multer.</p>
<p>Let's get started with the first step: setting up your project.</p>
<h2 id="heading-step-1-set-up-the-project">Step 1: Set Up the Project</h2>
<p>Start by creating a new Node.js project and initializing it with a package.json file:</p>
<pre><code class="lang-bash">$ mkdir multer-tutorial
$ <span class="hljs-built_in">cd</span> multer-tutorial
$ npm init -y
</code></pre>
<p>Next, install the necessary dependencies, including Express and Multer:</p>
<pre><code class="lang-bash">$ npm install express multer
</code></pre>
<h2 id="heading-step-2-create-an-express-server">Step 2: Create an Express Server</h2>
<p>Create a new file named server.js and set up a basic Express server:</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();
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>;

app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running on port <span class="hljs-subst">${port}</span>`</span>);
});
<span class="hljs-string">``</span>


## Step <span class="hljs-number">3</span>: <span class="hljs-built_in">Set</span> Up Multer Middleware

In <span class="hljs-built_in">this</span> step, you<span class="hljs-string">'ll create a separate file named upload.js to set up the Multer middleware. Multer is a middleware for handling multipart/form-data requests, specifically designed for file uploads in Node.js.

First, import the **multer** module using **require('</span>multer<span class="hljs-string">')**. This ensures that you have access to the Multer functionality. 

Next, define the storage configuration for uploaded files using **multer.diskStorage()**. This configuration determines where the uploaded files will be stored on the server. It takes an object with two functions: **destination** and **filename**.

The destination function specifies the directory where the uploaded files will be saved. In this example, we set it to **'</span>uploads/<span class="hljs-string">'**, which means the files will be stored in a folder named "uploads" in the root directory of your project. You can customize the destination path based on your requirements.

The filename function determines the name of the uploaded file. In this example, we use **Date.now()** to generate a unique timestamp for each uploaded file, which helps prevent filename clashes. 

We append the original name of the file using **file.originalname** to maintain some context about the uploaded file. You can modify this function to generate filenames based on your specific needs.

After setting up the storage configuration, you create an instance of Multer by calling **multer({ storage })**, passing in the **storage** configuration object. This creates the Multer middleware that you can use in your Express application to handle file uploads.

Finally, you export the Multer instance using **module.exports** so that it can be imported and used in other parts of your application, such as in the Express route for handling file uploads.

By setting up Multer middleware in this way, you have configured the storage destination and filename for uploaded files, allowing Multer to handle file uploads seamlessly in your application.


``` javascript 
const multer = require('</span>multer<span class="hljs-string">');

// Set up storage for uploaded files
const storage = multer.diskStorage({
  destination: (req, file, cb) =&gt; {
    cb(null, '</span>uploads/<span class="hljs-string">');
  },
  filename: (req, file, cb) =&gt; {
    cb(null, Date.now() + '</span>-<span class="hljs-string">' + file.originalname);
  }
});

// Create the multer instance
const upload = multer({ storage: storage });

module.exports = upload;</span>
</code></pre>
<h2 id="heading-step-4-handle-file-uploads-in-express">Step 4: Handle File Uploads in Express</h2>
<p>In your server.js file, require the upload.js file and set up a route for file uploads:</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();
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>;

<span class="hljs-comment">// Require the upload middleware</span>
<span class="hljs-keyword">const</span> upload = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./upload'</span>);

<span class="hljs-comment">// Set up a route for file uploads</span>
app.post(<span class="hljs-string">'/upload'</span>, upload.single(<span class="hljs-string">'file'</span>), <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// Handle the uploaded file</span>
  res.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'File uploaded successfully!'</span> });
});

app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running on port <span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<h2 id="heading-step-5-create-an-html-form">Step 5: Create an HTML Form</h2>
<p>In this step, you will create an HTML form that allows users to select and upload a file to your server. The form will be submitted using the POST method and will have an encoding type of "multipart/form-data" to handle file upload:</p>
<p>To create the HTML form, you will use the <strong>&lt; form &gt;</strong> element with the following attributes:</p>
<ul>
<li><strong>action</strong>: This attribute specifies the URL or route where the form data will be sent when the form is submitted. In this case, you will set the action attribute to '<strong>/upload'</strong>, which is the route you created in Step 4 to handle file uploads.</li>
<li><strong>method</strong>: This attribute specifies the HTTP method to be used when submitting the form. For file uploads, you should use the POST method, as it allows larger amounts of data to be sent. So, set the method attribute to "POST".</li>
<li><strong>enctype</strong>: This attribute specifies the content type used to submit the form data. For file uploads, you need to set the enctype attribute to "multipart/form-data". This encoding type is necessary for browsers to properly handle file uploads.</li>
</ul>
<p>Inside the form, you will add an <strong>&lt; input &gt;</strong> element of type "file". This element allows users to select a file from their local machine. Give the input element a <strong>name</strong> attribute so that it can be identified when the form is submitted. In this example, the name attribute is set to "file". You can adjust the name attribute value based on your needs.</p>
<p>Finally, you can add any additional form fields or submit buttons as needed. When the form is submitted, the selected file(s) will be sent to the specified route for handling.</p>
<p>By creating this HTML form, users will be able to select and upload files to your server using the provided input field.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>File Upload<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</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">h1</span>&gt;</span>File Upload<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"/upload"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">enctype</span>=<span class="hljs-string">"multipart/form-data"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"file"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"file"</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>Upload<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">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h2 id="heading-step-6-test-your-file-upload">Step 6: Test Your File Upload</h2>
<p>Start your server by running node server.js in the project's root directory. Open your browser and navigate to http://localhost:3000. You should see a file upload form. Select a file and click the "Upload" button. If everything is set up correctly, you should receive a JSON response saying "File uploaded successfully!".</p>
<p>That's it! You've successfully simplified your file upload process using Multer. </p>
<p>Multer provides additional features and options for handling various scenarios, such as uploading multiple files or setting file size limits. Check out the Multer documentation for more details and customization options.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to simplify your file upload process using Multer, a powerful middleware for Node.js. With Multer, you can handle file uploads effortlessly by configuring storage options, handling single or multiple file uploads, and customizing various aspects of the process.</p>
<p>By leveraging Multer, you can enhance your web application's functionality and save time and effort in handling file uploads. </p>
<p>Remember to explore Multer's documentation for advanced options and features, such as validation, error handling, and integration with cloud storage services.</p>
<p>Happy coding!</p>
<p>Let's connect @ <a target="_blank" href="https://twitter.com/iam_kelvinjnr">iam_kelvinjnr</a>
You can download the source code @ <a target="_blank" href="https://github.com/iamkelv/article-file-upload">GitHub</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Secure Your MERN Stack App with JWT-Based User Authentication and Authorization ]]>
                </title>
                <description>
                    <![CDATA[ By FADAHUNSI SEYI SAMUEL MongoDB, Express, React, and Node.js are the components of the MERN stack, one of the most widely used web development stacks out there today. The MERN stack enables programmers to create dependable web applications with stro... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-secure-your-mern-stack-application/</link>
                <guid isPermaLink="false">66d45edb7df3a1f32ee7f859</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 15 May 2023 17:15:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/trlyJUK.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By FADAHUNSI SEYI SAMUEL</p>
<p><a target="_blank" href="https://www.mongodb.com/docs/">MongoDB</a>, <a target="_blank" href="https://expressjs.com/en/starter/installing.html">Express</a>, <a target="_blank" href="https://react.dev/learn">React</a>, and <a target="_blank" href="https://nodejs.org/en/docs">Node.js</a> are the components of the MERN stack, one of the most widely used web development stacks out there today.</p>
<p>The MERN stack enables programmers to create dependable web applications with strong capabilities. Yet, security should be a key concern with any web application.</p>
<p>User authentication and permissions are some of the most important security features of any web service. In order to protect sensitive information and stop unauthorized access to important functions, these make sure that only authorized users can access certain areas of the application.</p>
<p>By the end of this article, you will have a firm grasp on how to integrate <a target="_blank" href="https://jwt.io/introduction">JWT</a>  (Json Web Token)-based user authentication and authorization into your MERN stack web application.</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-user-authentication-amp-authorization">What is User Authentication &amp; Authorization?</a></li>
<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-why-use-the-mern-stack">Why Use the MERN Stack?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-project-environment">How to Set Up the Project Environment</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-new-react-application">How to Create a New React Application</a></li>
<li><a class="post-section-overview" href="#heading-nodejs-and-expressjs-installation-and-configuration">Node.js and Express.js Installation and Configuration</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-mongodb">How to Set Up MongoDB</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-backend">How to Implement the Backend</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-signup-route">How to Handle the SIGNUP Route</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-login-route">How to Handle the LOGIN Route</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-home-route">How to Handle the HOME Route</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/p/43c39ded-b2ce-4029-8fbe-66015525449f/howtoimplementthefrontend">How to Implement the Frontend</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-signup-logic">How to Handle the Signup Logic</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-login-logic">How to Handle the Login Logic</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-the-home-page-logic">How to Handle the Home Page Logic</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-what-is-user-authentication-amp-authorization">What is User Authentication &amp; Authorization?</h2>
<p>In application security, authentication and authorization are two crucial ideas that work together to guarantee access to the resources of an application. </p>
<p>Many people frequently confuse these words – but after reading this guide, will we? NOT AGAIN!</p>
<h3 id="heading-authentication">Authentication</h3>
<p>Verifying a user's or an entity's identity is the process called  <strong>Authentication</strong>. It entails validating the user's credentials, such as a username and password, to ensure that the user is who they claim to be.</p>
<h3 id="heading-authorization">Authorization</h3>
<p>The process of authorizing or refusing access to particular resources or functions within an application is known as <strong>Authorization</strong>. Once a user has been verified as authentic, the program checks their level of authorization to decide which areas of the application they can access.</p>
<p><strong>Authentication</strong> is comparable to when a college applicant is admitted to a program based on the results of a written exam. The student is permitted on school grounds, but is not permitted in a department or class that is not their own (that was not given to them during admission). This action is known as <strong>Authorization</strong>.</p>
<h2 id="heading-what-is-the-mern-stack">What is the MERN Stack?</h2>
<p>Let's talk about the various elements of the MERN stack before we start creating the authentication mechanism.</p>
<ol>
<li><strong>MongoDB</strong> is a NoSQL database that uses dynamic schemas and documents that resemble JSON to store data. MongoDB is a popular option for creating scalable web applications because it is effective at managing big amounts of data.</li>
<li><strong>Express.js</strong> is a Node.js web application framework that offers a selection of functionality for creating online applications. Express.js is a well-liked option for developing online applications since it is compact, quick, and simple to use.</li>
<li><strong>React.js</strong> is a JavaScript library used to create user interfaces. By disassembling complicated user interfaces into smaller, reusable components, React.js offers a declarative method for doing so.</li>
<li><strong>Node.js</strong> is based on the V8 JavaScript engine in Chrome, and is a JavaScript runtime. The ability to run JavaScript on the server-side makes Node.js the perfect platform for creating web applications.</li>
</ol>
<h2 id="heading-why-use-the-mern-stack">Why Use the MERN Stack?</h2>
<p>The MERN stack is a great option for developing web applications since it includes all of the technologies needed to create a cutting-edge, scalable online application.</p>
<p>Following a discussion of the various elements of the MERN stack, we will use code snippets to develop a whole user authentication system from scratch.</p>
<h2 id="heading-how-to-set-up-the-project-environment">How to Set Up the Project Environment</h2>
<p>To get started with building the authentication system, we first need to set up the project. We will create a new React application using <code>create-react-app</code> and install the required dependencies. We will also set up <code>MongoDB</code> and configure our <code>Node.js</code> server.</p>
<p>NB: In this article, we will be making use of <a target="_blank" href="https://code.visualstudio.com/download">Visual studio code</a> editor, which I highly recommend.</p>
<p>Before we dive into this, you're going to create a folder which will contain other sub folders as you move on in this article.</p>
<p>After creating your folder, it should look like the image below:</p>
<p><img src="https://i.imgur.com/JrxZbI3.png" alt="Folder structure" width="1366" height="768" loading="lazy"></p>
<p>The folder you just created will contain two sub folders called the <code>client</code> and <code>server</code>. Run the commands below in your terminal to create the sub folders:</p>
<pre><code>mkdir client
</code></pre><p>This will create the <code>client</code> sub folder.</p>
<pre><code>mkdir server
</code></pre><p>This will create the <code>server</code> sub folder. Your application folder should look like this:</p>
<p><img src="https://i.imgur.com/jwPj09J.png" alt="Application folder" width="1366" height="768" loading="lazy"></p>
<h3 id="heading-how-to-create-a-new-react-application">How to Create a New React Application</h3>
<p>You can create a new React application using <code>create-react-app</code>. Open your terminal and run the below command to create a new React application.</p>
<p>But first, you will need to go into the <code>client</code> folder using <code>cd client</code>, then run the following command:</p>
<pre><code class="lang-shell">npx create-react-app
</code></pre>
<p>After the command above has successfully created the app, type <code>npm start</code> in your terminal. Make sure you're in your <code>client</code> directory. Your output should look like the image below:</p>
<p><img src="https://i.imgur.com/Y8N9gbL.png" alt="Y8N9gbL" width="1366" height="768" loading="lazy"></p>
<p>Before we move to the server directory, you will need to remove some boilerplate in your React application. Your <code>client</code> should look like the image below;</p>
<p><img src="https://i.imgur.com/27WytE6.png" alt="27WytE6" width="1366" height="768" loading="lazy"></p>
<p>Once you're done with the above, restart your React application by running <code>npm start</code> in your terminal. Your application should be looking like this:</p>
<p><img src="https://i.imgur.com/ws2F4wH.png" alt="ws2F4wH" width="1366" height="768" loading="lazy"></p>
<p>Now, you've successfully setup your client side of the application 😊 yeah!</p>
<h3 id="heading-nodejs-and-expressjs-installation-and-configuration">Node.js and Express.js Installation and Configuration</h3>
<p>To setup your backend application, run <code>mkdir server</code> in your terminal to get into the <code>server</code> sub folder. After getting into the <code>server</code> sub folder, run the following command to initialize the backend application:</p>
<pre><code class="lang-shell">npm init --yes
</code></pre>
<p>The <code>npm init --yes</code> command in Node.js creates a new <code>package.json</code> file for a project with default settings, without asking the user any questions.</p>
<p>The <code>--yes</code> or <code>-y</code> flag tells npm to use default values for all prompts that would normally appear during the initialization process.</p>
<p>The server folder should now contain a <code>package.json</code> file just like so:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"server"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-string">"description"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-string">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>
  },
  <span class="hljs-string">"keywords"</span>: [],
  <span class="hljs-string">"author"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-string">"license"</span>: <span class="hljs-string">"ISC"</span>
}
</code></pre>
<p>To install Express.js and other dependencies, run the following commands in your terminal:</p>
<pre><code class="lang-shell"> npm install express cors bcrypt cookie-parser nodemon jsonwebtoken mongoose dotenv
</code></pre>
<p>The above commands install the following dependencies:</p>
<ul>
<li><code>Express.js</code>, which is our Node.js web application framework.</li>
<li><code>bcrypt</code>, which helps us hash the user's password.</li>
<li><code>cookie-parser</code> is the the cookie-parser middleware that handles cookie-based sessions. It extracts information from cookies that may be required for authentication or other purposes.</li>
<li><code>nodemon</code> is a tool used to automatically restart a Node.js application whenever changes are made to the code. </li>
<li><code>CORS</code> is a middleware used to enable Cross-Origin Resource Sharing (CORS) for an Express.js application.</li>
<li><code>jsonwebtoken</code> helps us create and verify JSON Web Tokens. </li>
<li><code>dotenv</code> allows you to store configuration data in a <code>.env</code> file, which is typically not committed to version control, to separate sensitive information from your codebase. This file contains key-value pairs that represent the environment variables.</li>
</ul>
<p>After installing the required dependencies, create a new file called <code>index.js</code> in the root directory of your <code>server</code> sub folder of your application. The <code>index.js</code> file will contain our Node.js server. </p>
<p>In the <code>index.js</code> file of your <code>server</code>, add the following code:</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();
<span class="hljs-keyword">const</span> PORT = <span class="hljs-number">4000</span>;

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>Before you start the server, update your <code>package.json</code> file in the server by adding the code below:</p>
<pre><code class="lang-javascript">  <span class="hljs-string">"scripts"</span>:{
  <span class="hljs-attr">start</span>: <span class="hljs-string">"nodemon index.js"</span>,
  <span class="hljs-attr">test</span>: <span class="hljs-string">'echo "Error: no test specified" &amp;&amp; exit 1'</span>,
};
</code></pre>
<p>This will make sure your application restarts on any update. Now, you can start your <code>server</code> by running <code>npm start</code> in your terminal.</p>
<p>If all these are successfully executed, your terminal should look like this:</p>
<p><img src="https://i.imgur.com/EsjRkqi.png" alt="Image" width="1366" height="768" loading="lazy"></p>
<h3 id="heading-how-to-set-up-mongodb">How to Set Up MongoDB</h3>
<p>You're almost done with setting up your application. If you do not have <code>mongodb</code> installed your computer, follow these <a target="_blank" href="https://www.mongodb.com/docs/manual/installation/">steps</a>.</p>
<p>Now, I assume you have successfully installed <code>mongodb</code> on your computer. To link your database to your backend, follow the procedures below.</p>
<p>STEP 1: Go into your MongoDB cloud clusters, which should look like the image below:</p>
<p><img src="https://i.imgur.com/MZbppS2.png" alt="MZbppS2" width="1366" height="768" loading="lazy"></p>
<p>STEP 2: Click on the Database Access, which is on the left of the sidebar. Click on <code>ADD NEW DATABASE USER</code> which will pop up a modal, like the image below:</p>
<p><img src="https://i.imgur.com/Hyiky7V.png" alt="Hyiky7V" width="1366" height="768" loading="lazy"></p>
<p>STEP 3: Fill out the <code>Password Authentication</code> with your desired username and password for the database of this particular project.</p>
<p>STEP 4: Before saving this, click the <code>Built-in Role</code> dropdown, and select <code>Read and write to any database</code>. Now, go ahead to click <code>Add user</code>.</p>
<p>STEP 5: Click on <code>Database</code>, and on the left side of the sidebar, click the <code>connect</code> button, which is beside <code>View Monitoring</code>. A modal popup will be displayed, then click <code>connect your application</code> and copy the code snippet you find there.</p>
<p><img src="https://i.imgur.com/Hqmbxro.png" alt="Hqmbxro" width="1366" height="768" loading="lazy"></p>
<p>You will replace <code>&lt;username&gt;</code> and <code>&lt;password&gt;</code> with the username and password you created in <code>STEP 3</code> in your <code>index.js</code> file in the server folder.</p>
<p>Before going into your <code>index.js</code> file, you will create a <code>.env</code> file in your <code>server</code> directory, which will contain your <code>MONGODB_URL</code>, <code>PORT</code>, <code>database_name</code>, and <code>database_password</code> like the code below:</p>
<pre><code class="lang-javascript">MONGO_URL =
  <span class="hljs-string">"mongodb+srv://database_name:database_password@cluster0.fbx6x.mongodb.net/?retryWrites=true&amp;w=majority"</span>;
PORT = <span class="hljs-number">4000</span>;
</code></pre>
<p>Once you're done with this, go into your <code>index.js</code> in your <code>server</code> directory, and update it with the code below:</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> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</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> app = express();
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
<span class="hljs-keyword">const</span> { MONGO_URL, PORT } = process.env;

mongoose
  .connect(MONGO_URL, {
    <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>,
  })
  .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"MongoDB is  connected successfully"</span>))
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(err));

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});

app.use(
  cors({
    <span class="hljs-attr">origin</span>: [<span class="hljs-string">"http://localhost:4000"</span>],
    <span class="hljs-attr">methods</span>: [<span class="hljs-string">"GET"</span>, <span class="hljs-string">"POST"</span>, <span class="hljs-string">"PUT"</span>, <span class="hljs-string">"DELETE"</span>],
    <span class="hljs-attr">credentials</span>: <span class="hljs-literal">true</span>,
  })
);

app.use(express.json());
</code></pre>
<p>In the code above, we are configuring our application to be able to have access to the <code>.env</code> file. You can get the information in your <code>.env</code> file by doing <code>process.env</code>.</p>
<p>So you're destructing the values from the <code>.env</code> file by doing <code>process.env</code> so you don't repeat yourself (DRY) which is a good engineering practice.</p>
<ul>
<li>CORS (Cross origin resource sharing): You can allow requests from other domains to access the resources on your server by using the <code>cors()</code> express middleware function. The CORS headers that your server should include in the response can be specified using the function's optional configuration object parameter, which is taken as a parameter by the function which is the <code>origin</code>, <code>methods</code> and <code>credentials</code>.</li>
<li>express.json(): The <code>express.json()</code> will add a <code>body</code> property to the <code>request</code> or <code>req</code> object. This includes the request body's parsed JSON data. <code>req.body</code> in your route handler function will allow you to access this data.</li>
<li>useNewUrlParser: This property specifies that Mongoose should use the new URL parser to parse MongoDB connection strings. This is set to true by default.</li>
<li>useUnifiedTopology: This property specifies that Mongoose should use the new Server Discovery and Monitoring engine. This is set to false by default.</li>
</ul>
<p>After following the steps above, you will restart your application by doing <code>npm start</code> in your <code>server</code> directory. Your terminal should look like the image below;</p>
<p><img src="https://i.imgur.com/Ly8zIk5.png" alt="Ly8zIk5" width="1366" height="768" loading="lazy"></p>
<h2 id="heading-how-to-implement-the-backend">How to Implement the Backend</h2>
<p>Create the following folders in the <code>server</code> directory of your application after first ensuring that you are in that directory. <code>Controllers</code>, <code>Middlewares</code>, <code>Routes</code>, <code>Models</code>, and <code>util</code> are the names of these folders.</p>
<h3 id="heading-how-to-handle-the-signup-route">How to Handle the SIGNUP Route</h3>
<p>Create a file called <code>UserModel.js</code> in the <code>Models</code> directory and put the following code into it to get started:</p>
<pre><code class="lang-javascript"><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> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"bcryptjs"</span>);

<span class="hljs-keyword">const</span> userSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
  <span class="hljs-attr">email</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-string">"Your email address is required"</span>],
    <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span>,
  },
  <span class="hljs-attr">username</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-string">"Your username is required"</span>],
  },
  <span class="hljs-attr">password</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-string">"Your password is required"</span>],
  },
  <span class="hljs-attr">createdAt</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
  },
});

userSchema.pre(<span class="hljs-string">"save"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">this</span>.password = <span class="hljs-keyword">await</span> bcrypt.hash(<span class="hljs-built_in">this</span>.password, <span class="hljs-number">12</span>);
});

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">"User"</span>, userSchema);
</code></pre>
<p>The user schema and user password will be created in the above code using <code>mongoose</code> and <code>bcryptjs</code>, respectively, for security purposes.</p>
<p>The <code>password</code> is hashed for security reasons prior to saving the user.</p>
<p>Next, you will setup a function to handle the generation of a atoken, which will be called <code>SecretToken.js</code> in the <code>util</code> folder. Copy and paste the code below into the newly created file (<code>SecretToken.js</code>):</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
<span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"jsonwebtoken"</span>);

<span class="hljs-built_in">module</span>.exports.createSecretToken = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> jwt.sign({ id }, process.env.TOKEN_KEY, {
    <span class="hljs-attr">expiresIn</span>: <span class="hljs-number">3</span> * <span class="hljs-number">24</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>,
  });
};
</code></pre>
<p>Once that's done, create a file called <code>AuthController.js</code> in the <code>Controllers</code> directory and paste in the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> User = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../Models/UserModel"</span>);
<span class="hljs-keyword">const</span> { createSecretToken } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../util/SecretToken"</span>);
<span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"bcryptjs"</span>);

<span class="hljs-built_in">module</span>.exports.Signup = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { email, password, username, createdAt } = 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.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User already exists"</span> });
    }
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.create({ email, password, username, createdAt });
    <span class="hljs-keyword">const</span> token = createSecretToken(user._id);
    res.cookie(<span class="hljs-string">"token"</span>, token, {
      <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">false</span>,
    });
    res
      .status(<span class="hljs-number">201</span>)
      .json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User signed in successfully"</span>, <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>, user });
    next();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
  }
};
</code></pre>
<p>The user's inputs are obtained from the <code>req.body</code> in the code above, and you then check the <code>email</code> to make sure no past registrations have been made. We'll use the values obtained from <code>req.body</code> to create the new <code>user</code> after that has occurred.</p>
<p>You don't need to worry about how the unique <code>_id</code> was obtained because MongoDB always assigns a new user with a unique <code>_id</code></p>
<p>The newly formed <code>user</code>'s <code>_id</code> is then supplied as an parameter to the <code>createSecretToken()</code> function, which handles token generation.</p>
<p>The <code>cookie</code> will be sent to the client with key of <code>"token"</code>, and value of <code>token</code>.</p>
<p>Next, create a file called <code>AuthRoute.js</code> in the <code>Routes</code> directory. Paste the code below into the newly created file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { Signup } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../Controllers/AuthController"</span>);
<span class="hljs-keyword">const</span> router = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>).Router();

router.post(<span class="hljs-string">"/signup"</span>, Signup);

<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<p>In the code above, the <code>/signup</code> route has a <code>post</code> method attached to it, when it's been called, the <code>Signup</code> controller will be executed.</p>
<p>Next, update your <code>index.js</code> file so it can be aware of the routes. Your <code>index.js</code> file should look like the code below:</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> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</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> app = express();
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
<span class="hljs-keyword">const</span> cookieParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cookie-parser"</span>);
<span class="hljs-keyword">const</span> authRoute = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./Routes/AuthRoute"</span>);
<span class="hljs-keyword">const</span> { MONGO_URL, PORT } = process.env;

mongoose
  .connect(MONGO_URL, {
    <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>,
  })
  .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"MongoDB is  connected successfully"</span>))
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(err));

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});

app.use(
  cors({
    <span class="hljs-attr">origin</span>: [<span class="hljs-string">"http://localhost:3000"</span>],
    <span class="hljs-attr">methods</span>: [<span class="hljs-string">"GET"</span>, <span class="hljs-string">"POST"</span>, <span class="hljs-string">"PUT"</span>, <span class="hljs-string">"DELETE"</span>],
    <span class="hljs-attr">credentials</span>: <span class="hljs-literal">true</span>,
  })
);
app.use(cookieParser());

app.use(express.json());

app.use(<span class="hljs-string">"/"</span>, authRoute);
</code></pre>
<p>The <code>cookie-parser</code> manages cookie-based sessions or extracts data from cookies. It's added to the code above along with the <code>authRoute</code> that the application will utilize.</p>
<p>Now, let's go ahead to test the <code>/signup</code> route with a tool called <a target="_blank" href="https://www.postman.com/downloads/">Postman</a>. Make sure you're in the <code>server</code> directory in the terminal, then run <code>npm start</code> to start your application.</p>
<p><img src="https://i.imgur.com/zzN1QyQ.png" alt="zzN1QyQ" width="1366" height="768" loading="lazy"></p>
<p>The image above shows the response gotten when a request is sent.</p>
<p><img src="https://i.imgur.com/8jrGe0T.png" alt="8jrGe0T" width="1366" height="768" loading="lazy"></p>
<p>The image above shows the generated cookie from the response.</p>
<p><img src="https://i.imgur.com/KJ8haPB.png" alt="KJ8haPB" width="1366" height="768" loading="lazy"></p>
<p>The image above illustrates what happens when you try to use a registered email.</p>
<p>By now, the user will be created in the database like the image below:</p>
<p><img src="https://i.imgur.com/XQsjWRt.png" alt="XQsjWRt" width="1366" height="768" loading="lazy"></p>
<h3 id="heading-how-to-handle-the-login-route">How to Handle the LOGIN Route</h3>
<p>Open the <code>AuthController.js</code> file in the <code>Controllers</code> directory, and update it with the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports.Login = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { email, password } = req.body;
    <span class="hljs-keyword">if</span>(!email || !password ){
      <span class="hljs-keyword">return</span> res.json({<span class="hljs-attr">message</span>:<span class="hljs-string">'All fields are required'</span>})
    }
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findOne({ email });
    <span class="hljs-keyword">if</span>(!user){
      <span class="hljs-keyword">return</span> res.json({<span class="hljs-attr">message</span>:<span class="hljs-string">'Incorrect password or email'</span> }) 
    }
    <span class="hljs-keyword">const</span> auth = <span class="hljs-keyword">await</span> bcrypt.compare(password,user.password)
    <span class="hljs-keyword">if</span> (!auth) {
      <span class="hljs-keyword">return</span> res.json({<span class="hljs-attr">message</span>:<span class="hljs-string">'Incorrect password or email'</span> }) 
    }
     <span class="hljs-keyword">const</span> token = createSecretToken(user._id);
     res.cookie(<span class="hljs-string">"token"</span>, token, {
       <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span>,
       <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">false</span>,
     });
     res.status(<span class="hljs-number">201</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User logged in successfully"</span>, <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span> });
     next()
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
  }
}
</code></pre>
<p>You are determining in the code above whether the <code>email</code> and <code>password</code> match any previously stored <code>user</code> in the database.</p>
<p>Then add the following code to the file <code>AuthRoute.js</code> in the <code>Routes</code> directory:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { Signup, Login } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../Controllers/AuthController'</span>)
<span class="hljs-keyword">const</span> router = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>).Router()

router.post(<span class="hljs-string">'/signup'</span>, Signup)
router.post(<span class="hljs-string">'/login'</span>, Login)

<span class="hljs-built_in">module</span>.exports = router
</code></pre>
<p>Now, let's go ahead to test the application:</p>
<p><img src="https://i.imgur.com/gwRjAGk.png" alt="gwRjAGk" width="1366" height="768" loading="lazy"></p>
<p>If you try to use an unregistered <code>email</code> or <code>password</code>, you'll get the message below:</p>
<p><img src="https://i.imgur.com/fLj20iU.png" alt="fLj20iU" width="1366" height="768" loading="lazy"></p>
<h3 id="heading-how-to-handle-the-home-route">How to Handle the HOME Route</h3>
<p>Now, you will create a <code>AuthMiddleware.js</code> file, in the <code>Middlewares</code> directory, and paste in the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> User = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../Models/UserModel"</span>);
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
<span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"jsonwebtoken"</span>);

<span class="hljs-built_in">module</span>.exports.userVerification = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> token = req.cookies.token
  <span class="hljs-keyword">if</span> (!token) {
    <span class="hljs-keyword">return</span> res.json({ <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span> })
  }
  jwt.verify(token, process.env.TOKEN_KEY, <span class="hljs-keyword">async</span> (err, data) =&gt; {
    <span class="hljs-keyword">if</span> (err) {
     <span class="hljs-keyword">return</span> res.json({ <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span> })
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findById(data.id)
      <span class="hljs-keyword">if</span> (user) <span class="hljs-keyword">return</span> res.json({ <span class="hljs-attr">status</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">user</span>: user.username })
      <span class="hljs-keyword">else</span> <span class="hljs-keyword">return</span> res.json({ <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span> })
    }
  })
}
</code></pre>
<p>The code above checks if the user has access to the route by checking if the <code>token</code>s match.</p>
<p>Next, update the <code>AuthRoute.js</code> file in the <code>Routes</code> directory with the code below:</p>
<pre><code class="lang-javascript">router.post(<span class="hljs-string">'/'</span>,userVerification)
</code></pre>
<p>Now, you can go ahead to test your route. It should look like the image below:</p>
<p><img src="https://i.imgur.com/xk1J1Zs.png" alt="xk1J1Zs" width="1366" height="768" loading="lazy"></p>
<h2 id="heading-how-to-implement-the-frontend">How to Implement the Frontend</h2>
<p>To get started, go into the <code>client</code> directory and install the following in your terminal:</p>
<pre><code class="lang-shell">npm install react-cookie react-router-dom react-toastify axios
</code></pre>
<p>Now, update the <code>index.js</code> file in the <code>client</code> directory with the code snippet below:</p>
<p><img src="https://i.imgur.com/LcoXMWB.png" alt="LcoXMWB" width="1326" height="938" loading="lazy"></p>
<p>In the code above, wrapping your <code>App</code> component with <code>BrowserRouter</code> is necessary to enable client-side routing and take advantage of its benefits in your application.</p>
<p>NB: Remove the <code>React.StrictMode</code> later when you are testing the application and your data is being fetched twice.</p>
<p>Also, import <code>react-toastify</code> so it can be available in your application.</p>
<p>Now, go ahead to create the <code>pages</code> directory in your <code>client</code> directory, which will contain the <code>Home.jsx</code> file, <code>Login.jsx</code> file, <code>Signup.jsx</code> and <code>index.js</code> to export the components. Your folder should look like the image below:</p>
<p><img src="https://i.imgur.com/G4rQ48P.png" alt="G4rQ48P" width="1366" height="768" loading="lazy"></p>
<p>Now, fill the <code>Login.jsx</code>, <code>Signup.jsx</code>, and <code>Home.jsx</code>, respectively, with the code below. These snippets below, are functional components which will be modified later in this guide. </p>
<p>NB: This can be automatically generated by typing the shortcut <code>rafce</code> + <code>enter</code> in the file you want to add the snippet in your visual studio code editor. Make sure this <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets">extension</a> is installed in your visual studio code for this to work.</p>
<p><code>Login.jsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> Login = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Login Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Login
</code></pre>
<p><code>Signup.jsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> Signup = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Signup Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Signup
</code></pre>
<p><code>Home.jsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Home PAGE<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home
</code></pre>
<p>After that's done, you will go into the <code>index.js</code> file in the <code>pages</code> directory to export the newly created components. It should look like the image below:</p>
<p><img src="https://i.imgur.com/XKroJyH.png" alt="XKroJyH" width="942" height="406" loading="lazy"></p>
<p>The method shown above makes importing components easier by requiring only one import line.</p>
<p>Now, update the <code>App.js</code> file in the <code>src</code> directory with the code below.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Route, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> { Login, Signup } <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages"</span>;
<span class="hljs-keyword">import</span> Home <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages/Home"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </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"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Home</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/login"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Login</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/signup"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Signup</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</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>
<p>The routes will be made available in your application using the above code. The example below will help to clarify:</p>
<p><img src="https://i.imgur.com/w78YqgX.gif" alt="w78YqgX" width="1376" height="772" loading="lazy"></p>
<h3 id="heading-how-to-handle-the-signup-logic">How to Handle the Signup Logic</h3>
<p>In the <code>Signup.jsx</code> file in the <code>pages</code> directory, paste the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Link, useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { ToastContainer, toast } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-toastify"</span>;

<span class="hljs-keyword">const</span> Signup = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> navigate = useNavigate();
  <span class="hljs-keyword">const</span> [inputValue, setInputValue] = useState({
    <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">username</span>: <span class="hljs-string">""</span>,
  });
  <span class="hljs-keyword">const</span> { email, password, username } = inputValue;
  <span class="hljs-keyword">const</span> handleOnChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { name, value } = e.target;
    setInputValue({
      ...inputValue,
      [name]: value,
    });
  };

  <span class="hljs-keyword">const</span> handleError = <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span>
    toast.error(err, {
      <span class="hljs-attr">position</span>: <span class="hljs-string">"bottom-left"</span>,
    });
  <span class="hljs-keyword">const</span> handleSuccess = <span class="hljs-function">(<span class="hljs-params">msg</span>) =&gt;</span>
    toast.success(msg, {
      <span class="hljs-attr">position</span>: <span class="hljs-string">"bottom-right"</span>,
    });

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.post(
        <span class="hljs-string">"http://localhost:4000/signup"</span>,
        {
          ...inputValue,
        },
        { <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span> }
      );
      <span class="hljs-keyword">const</span> { success, message } = data;
      <span class="hljs-keyword">if</span> (success) {
        handleSuccess(message);
        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
          navigate(<span class="hljs-string">"/"</span>);
        }, <span class="hljs-number">1000</span>);
      } <span class="hljs-keyword">else</span> {
        handleError(message);
      }
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
    }
    setInputValue({
      ...inputValue,
      <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">username</span>: <span class="hljs-string">""</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">"form_container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Signup Account<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</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">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your email"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChange}</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">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Username<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{username}</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your username"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChange}</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">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"password"</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your password"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChange}</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">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
          Already have an account? <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"/<span class="hljs-attr">login</span>"}&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</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">ToastContainer</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> Signup;
</code></pre>
<h3 id="heading-how-to-handle-the-login-logic">How to Handle the Login Logic</h3>
<p>Add the following code snippet to the <code>Login.jsx</code> file in the <code>pages</code> directory:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Link, useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { ToastContainer, toast } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-toastify"</span>;

<span class="hljs-keyword">const</span> Login = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> navigate = useNavigate();
  <span class="hljs-keyword">const</span> [inputValue, setInputValue] = useState({
    <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
  });
  <span class="hljs-keyword">const</span> { email, password } = inputValue;
  <span class="hljs-keyword">const</span> handleOnChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { name, value } = e.target;
    setInputValue({
      ...inputValue,
      [name]: value,
    });
  };

  <span class="hljs-keyword">const</span> handleError = <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span>
    toast.error(err, {
      <span class="hljs-attr">position</span>: <span class="hljs-string">"bottom-left"</span>,
    });
  <span class="hljs-keyword">const</span> handleSuccess = <span class="hljs-function">(<span class="hljs-params">msg</span>) =&gt;</span>
    toast.success(msg, {
      <span class="hljs-attr">position</span>: <span class="hljs-string">"bottom-left"</span>,
    });

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.post(
        <span class="hljs-string">"http://localhost:4000/login"</span>,
        {
          ...inputValue,
        },
        { <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span> }
      );
      <span class="hljs-built_in">console</span>.log(data);
      <span class="hljs-keyword">const</span> { success, message } = data;
      <span class="hljs-keyword">if</span> (success) {
        handleSuccess(message);
        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
          navigate(<span class="hljs-string">"/"</span>);
        }, <span class="hljs-number">1000</span>);
      } <span class="hljs-keyword">else</span> {
        handleError(message);
      }
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
    }
    setInputValue({
      ...inputValue,
      <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">password</span>: <span class="hljs-string">""</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">"form_container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Login Account<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</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">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your email"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChange}</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">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"password"</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your password"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChange}</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">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
          Already have an account? <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"/<span class="hljs-attr">signup</span>"}&gt;</span>Signup<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</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">ToastContainer</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> Login;
</code></pre>
<h3 id="heading-how-to-handle-the-home-page-logic">How to Handle the Home Page Logic</h3>
<p>Copy and paste the following code snippet into the <code>Home.jsx</code> file located in the <code>pages</code> directory:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> { useCookies } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-cookie"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { ToastContainer, toast } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-toastify"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> navigate = useNavigate();
  <span class="hljs-keyword">const</span> [cookies, removeCookie] = useCookies([]);
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>);
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> verifyCookie = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">if</span> (!cookies.token) {
        navigate(<span class="hljs-string">"/login"</span>);
      }
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.post(
        <span class="hljs-string">"http://localhost:4000"</span>,
        {},
        { <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span> }
      );
      <span class="hljs-keyword">const</span> { status, user } = data;
      setUsername(user);
      <span class="hljs-keyword">return</span> status
        ? toast(<span class="hljs-string">`Hello <span class="hljs-subst">${user}</span>`</span>, {
            <span class="hljs-attr">position</span>: <span class="hljs-string">"top-right"</span>,
          })
        : (removeCookie(<span class="hljs-string">"token"</span>), navigate(<span class="hljs-string">"/login"</span>));
    };
    verifyCookie();
  }, [cookies, navigate, removeCookie]);
  <span class="hljs-keyword">const</span> Logout = <span class="hljs-function">() =&gt;</span> {
    removeCookie(<span class="hljs-string">"token"</span>);
    navigate(<span class="hljs-string">"/signup"</span>);
  };
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"home_page"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>
          {" "}
          Welcome <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{username}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{Logout}</span>&gt;</span>LOGOUT<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">ToastContainer</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Ensure that the styles below are copied into your <code>index.css</code> file:</p>
<pre><code class="lang-css">*,
<span class="hljs-selector-pseudo">::before</span>,
<span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">box-sizing</span>: border-box;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-selector-tag">label</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.2rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#656262</span>;
}

<span class="hljs-selector-tag">html</span>,
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(
    <span class="hljs-number">90deg</span>,
    rgba(<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">36</span>, <span class="hljs-number">1</span>) <span class="hljs-number">0%</span>,
    <span class="hljs-built_in">rgba</span>(<span class="hljs-number">143</span>, <span class="hljs-number">187</span>, <span class="hljs-number">204</span>, <span class="hljs-number">1</span>) <span class="hljs-number">35%</span>,
    <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>) <span class="hljs-number">100%</span>
  );
  <span class="hljs-attribute">font-family</span>: Verdana, Geneva, Tahoma, sans-serif;
}

<span class="hljs-selector-class">.form_container</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">8px</span> <span class="hljs-number">8px</span> <span class="hljs-number">24px</span> <span class="hljs-number">0px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">66</span>, <span class="hljs-number">68</span>, <span class="hljs-number">90</span>, <span class="hljs-number">1</span>);
}

<span class="hljs-selector-class">.form_container</span> &gt; <span class="hljs-selector-tag">h2</span> {
  <span class="hljs-attribute">margin-block</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">padding-block</span>: <span class="hljs-number">0.6rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>);
}

<span class="hljs-selector-class">.form_container</span> &gt; <span class="hljs-selector-tag">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">1.4rem</span>;
}

<span class="hljs-selector-class">.form_container</span> <span class="hljs-selector-tag">div</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">0.3rem</span>;
}

<span class="hljs-selector-class">.form_container</span> <span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">border-bottom</span>: <span class="hljs-number">1px</span> solid gray;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.1rem</span>;
  <span class="hljs-attribute">outline</span>: none;
}

<span class="hljs-selector-class">.form_container</span> <span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">::placeholder</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.9rem</span>;
  <span class="hljs-attribute">font-style</span>: italic;
}

<span class="hljs-selector-class">.form_container</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>);
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.6rem</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.3rem</span>;
}

<span class="hljs-selector-tag">span</span> <span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">text-decoration</span>: none;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>);
}

<span class="hljs-selector-class">.home_page</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#000</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">text-transform</span>: uppercase;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.home_page</span> <span class="hljs-selector-tag">span</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>);
}

<span class="hljs-selector-class">.home_page</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">27</span>, <span class="hljs-number">73</span>, <span class="hljs-number">83</span>);
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span> <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">transition</span>: ease-in <span class="hljs-number">0.3s</span>;
  <span class="hljs-attribute">border</span>: none;
}

<span class="hljs-selector-class">.home_page</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">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">212</span>, <span class="hljs-number">255</span>, <span class="hljs-number">1</span>);
}


<span class="hljs-keyword">@media</span> <span class="hljs-keyword">only</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">1200px</span>){
  <span class="hljs-selector-class">.home_page</span>{
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5rem</span>;
  }
  <span class="hljs-selector-class">.home_page</span> <span class="hljs-selector-tag">button</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.6rem</span> <span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5rem</span>;
  }
}
</code></pre>
<p>I'll now quickly demonstrate everything you've learned in this article.</p>
<p><img src="https://i.imgur.com/1mQJVm7.gif" alt="1mQJVm7" width="1376" height="772" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you've learned how to use JWT for authentication and authorization, helping you build secure Node.js applications. </p>
<p>This guide can help you guard against security threats and prevent unauthorized access by implementing strong authentication and authorization procedures.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Test Your Express.js and Mongoose Apps with Jest and SuperTest ]]>
                </title>
                <description>
                    <![CDATA[ By Rakesh Potnuru Testing is a vital part of software development. The sooner you start testing, the better.  In this article, I'll show you how to write tests for your NodeJs/ExpressJS and MongoDB/Mongoose applications with Jest and Supertest. Let's... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-test-in-express-and-mongoose-apps/</link>
                <guid isPermaLink="false">66d460c9787a2a3b05af43f6</guid>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Jest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 27 Sep 2022 23:26:16 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/how-to-write-tests.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rakesh Potnuru</p>
<p>Testing is a vital part of software development. The sooner you start testing, the better. </p>
<p>In this article, I'll show you how to write tests for your NodeJs/ExpressJS and MongoDB/Mongoose applications with <strong>Jest</strong> and <strong>Supertest</strong>.</p>
<h2 id="heading-lets-get-started">Let's get started</h2>
<p>First let's set up a demo Express.js app.</p>
<p>Let's say we are building a backend REST API for an eCommerce application.</p>
<p>This app should:</p>
<ul>
<li>Get all the products</li>
<li>Get a product by id</li>
<li>Add product(s) to the database</li>
<li>Delete product(s) from the database</li>
<li>Update product information</li>
</ul>
<h2 id="heading-expressjs-app-set-up">Express.js App Set Up</h2>
<h3 id="heading-step-1-project-set-up">Step 1: Project set up</h3>
<p>First, create a folder and start a blank application with <code>npm</code>.</p>
<pre><code class="lang-bash">npm init
</code></pre>
<p>Fill all the details it asks for.</p>
<p>Then, install <code>express</code>, <code>mongoose</code>, <code>axios</code> and <code>dotenv</code> with the following command:</p>
<pre><code class="lang-bash">npm i express mongoose axios dotenv
</code></pre>
<p>Here's a link to the <a target="_blank" href="https://github.com/itsrakeshhq/jest-tests-demo/blob/a1725cb3379f78a03cf8d3d4cfa22127469e8b50/package.json">package.json</a> on my GitHub.</p>
<h3 id="heading-step-2-create-the-boilerplate">Step 2: Create the boilerplate</h3>
<p>Let's create all the folders and files and then fill them with some boilerplate code.</p>
<p>This is how your folder hierarchy should look:</p>
<pre><code class="lang-bash">.
├── controllers
│   └── product.controller.js
├── models
│   └── product.model.js
├── routes
│   └── product.route.js
├── package-lock.json
├── package.json
├── .env
├── app.js
└── server.js
</code></pre>
<p>Use these files' code by copying and pasting. Analyze the code and flow as best you can.</p>
<ul>
<li><code>[product.controller.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/controllers/product.controller.js)</code></li>
<li><code>[product.model.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/models/product.model.js)</code></li>
<li><code>[product.route.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/routes/product.route.js)</code></li>
<li><code>[app.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/app.js)</code> </li>
<li><code>[server.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/server.js)</code></li>
</ul>
<h3 id="heading-step-3-database-setup">Step 3: Database setup</h3>
<p>I advise using two databases for a project—one for testing, the other for development. But just one database will be sufficient for learning purposes.</p>
<p>First, create a <a target="_blank" href="https://mongodb.com">MongoDB</a> account or log in.</p>
<p>Then create a new project. Give it a name and press the <strong>Next</strong> button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-205148.png" alt="Naming the project" width="600" height="400" loading="lazy">
<em>Naming the project</em></p>
<p>Then click <strong>Create Project</strong> after that.</p>
<p>We must create a database in the following window by selecting a cloud provider, a location, and specs. So press <strong>Build a Database</strong> to get going.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-205911.png" alt="Build a database" width="600" height="400" loading="lazy">
<em>Build a database</em></p>
<p>Choose "Shared" because it is sufficient for learning purposes. And then click <strong>Create</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-211701.png" alt="Choose a deployment option" width="600" height="400" loading="lazy">
<em>Choose a deployment option</em></p>
<p>Next, select "aws" as your cloud provider and the region that is closest to you. Following your selection, click <strong>Create Cluster</strong>.</p>
<p>The cluster's formation will take some time. Create a user to access your database in the meanwhile.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-212537.png" alt="Create Superuser" width="600" height="400" loading="lazy">
<em>Create Superuser</em></p>
<p>Choose "My Local Environment" because we are developing our application. You can then add an IP addresses. To conclude, click <strong>Close</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-213347.png" alt="Add IP addresses" width="600" height="400" loading="lazy">
<em>Add IP addresses</em></p>
<p>You will receive a URI string after the database is set up, which we'll use to connect to the database. The string appears as follows:</p>
<pre><code class="lang-bash">mongodb+srv://&lt;YOUR_USERNAME&gt;:&lt;YOUR_PASSWORD&gt;@&lt;YOUR_CLUSTER_URL&gt;/&lt;DATABASE_NAME&gt;?retryWrites=<span class="hljs-literal">true</span>&amp;w=majority
</code></pre>
<p>Put this string in the <code>.env</code> file.</p>
<pre><code class="lang-bash">MONGODB_URI=your database string
</code></pre>
<p>Now we're ready to start testing our app.</p>
<h2 id="heading-how-to-write-tests-with-jest-and-supertest">How to Write Tests with Jest and SuperTest</h2>
<h3 id="heading-step-1-install-packages">Step 1: Install packages</h3>
<p>You need three npm packages to begin writing tests: <code>jest</code>, <code>supertest</code>, and <code>cross-env</code>. You can install them like this:</p>
<pre><code class="lang-bash">npm i jest supertest cross-env
</code></pre>
<ul>
<li><code>jest</code>: Jest is a framework for testing JavaScript code. Unit testing is the main usage of it.</li>
<li><code>supertest</code>: Using Supertest, we can test endpoints and routes on HTTP servers.</li>
<li><code>cross-env</code>: You can set environmental variables inline within a command using cross-env.</li>
</ul>
<h3 id="heading-step-2-add-test-script">Step 2: Add test script</h3>
<p>Open your <code>package.json</code> file and add the test script to the scripts.</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"cross-env NODE_ENV=test jest --testTimeout=5000"</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"node server.js"</span>,
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"nodemon server.js"</span>
},
</code></pre>
<p>In this case, we're using <code>cross-env</code> to set environment variables, <code>jest</code> to execute test suites, and <code>testTimeout</code> is set to <code>5000</code> because certain requests might take a while to finish.</p>
<h3 id="heading-step-3-start-writing-tests">Step 3: Start writing tests</h3>
<p>First, create a folder called <code>tests</code> at the application's root, and then create a file there called <code>product.test.js</code>. Jest searches for the folder <code>tests</code> at the project's root when you do <code>npm run test</code>. As a result, you must place your test files in the <code>tests</code> folder.</p>
<p>Next, import the <code>supertest</code> and <code>mongoose</code> packages into the test file.</p>
<pre><code class="lang-javascript"><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> request = <span class="hljs-built_in">require</span>(<span class="hljs-string">"supertest"</span>);
</code></pre>
<p>Import <code>dotenv</code> to load environment variables, and import <code>app.js</code> as that is where our application starts.</p>
<pre><code class="lang-javascript"><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> request = <span class="hljs-built_in">require</span>(<span class="hljs-string">"supertest"</span>);
<span class="hljs-keyword">const</span> app = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../app"</span>);

<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
</code></pre>
<p>You'll need to connect and disconnect the database before and after each test (because we don't require the database once testing is complete).</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* Connecting to the database before each test. */</span>
beforeEach(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> mongoose.connect(process.env.MONGODB_URI);
});

<span class="hljs-comment">/* Closing database connection after each test. */</span>
afterEach(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> mongoose.connection.close();
});
</code></pre>
<p>Now you can write your first unit test.</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">"GET /api/products"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should return all products"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).get(<span class="hljs-string">"/api/products"</span>);
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
    expect(res.body.length).toBeGreaterThan(<span class="hljs-number">0</span>);
  });
});
</code></pre>
<p>In the above code, </p>
<ul>
<li>We use <code>describe</code> to describe the unit test. Even though it is not required, it will be useful to identify tests in test results.</li>
<li>In <code>it</code>, we write the actual test code. Tell what the test performs in the first argument, and then in the second argument, write a callback function that contains the test code.</li>
<li>In the callback function, the request is sent to the endpoint first, and the expected and actual responses are then compared. The test passes if both answers match, else, it fails. ✨ As simple as that ✨.</li>
</ul>
<p>You can write tests for all the endpoints in the same manner.</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">"GET /api/products/:id"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should return a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).get(
      <span class="hljs-string">"/api/products/6331abc9e9ececcc2d449e44"</span>
    );
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
    expect(res.body.name).toBe(<span class="hljs-string">"Product 1"</span>);
  });
});

describe(<span class="hljs-string">"POST /api/products"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should create a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).post(<span class="hljs-string">"/api/products"</span>).send({
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Product 2"</span>,
      <span class="hljs-attr">price</span>: <span class="hljs-number">1009</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">"Description 2"</span>,
    });
    expect(res.statusCode).toBe(<span class="hljs-number">201</span>);
    expect(res.body.name).toBe(<span class="hljs-string">"Product 2"</span>);
  });
});

describe(<span class="hljs-string">"PUT /api/products/:id"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should update a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app)
      .patch(<span class="hljs-string">"/api/products/6331abc9e9ececcc2d449e44"</span>)
      .send({
        <span class="hljs-attr">name</span>: <span class="hljs-string">"Product 4"</span>,
        <span class="hljs-attr">price</span>: <span class="hljs-number">104</span>,
        <span class="hljs-attr">description</span>: <span class="hljs-string">"Description 4"</span>,
      });
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
    expect(res.body.price).toBe(<span class="hljs-number">104</span>);
  });
});

describe(<span class="hljs-string">"DELETE /api/products/:id"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should delete a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).delete(
      <span class="hljs-string">"/api/products/6331abc9e9ececcc2d449e44"</span>
    );
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
  });
});
</code></pre>
<p>Then run <code>npm run test</code> to run the test suites (suite - test file).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-428.png" alt="Image" width="600" height="400" loading="lazy">
<em>Test results</em></p>
<p>And that's it! You now know how to test your Express/Mongoose apps with Jest and SuperTest.</p>
<p>Now go forth and create new tests for your apps. :)</p>
<p>If you have any questions, feel free to message me on <a target="_blank" href="https://twitter.com/rakesh_at_tweet">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ REST API Design Best Practices Handbook – How to Build a REST API with JavaScript, Node.js, and Express.js ]]>
                </title>
                <description>
                    <![CDATA[ By Jean-Marc Möckel I've created and consumed many API's over the past few years. During that time, I've come across good and bad practices and have experienced nasty situations when consuming and building API's. But there also have been great moment... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/rest-api-design-best-practices-build-a-rest-api/</link>
                <guid isPermaLink="false">66d45f383a8352b6c5a2aa6d</guid>
                
                    <category>
                        <![CDATA[ best practices ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 04 May 2022 15:10:32 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/05/rest-api-design-course-header.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jean-Marc Möckel</p>
<p>I've created and consumed many API's over the past few years. During that time, I've come across good and bad practices and have experienced nasty situations when consuming and building API's. But there also have been great moments.</p>
<p>There are helpful articles online which present many best practices, but many of them lack some practicality in my opinion. Knowing the theory with few examples is good, but I've always wondered how the implementation would look in a more real world example.</p>
<p>Providing simple examples helps to understand the concept itself without a lot of complexity, but in practice things aren't always so simple. I'm pretty sure you know what I'm talking about 😁</p>
<p>That's why I've decided to write this tutorial. I've merged all those learnings (good and bad) together into one digestible article while providing a practical example that can be followed along. In the end, we'll build a full API while we're implementing one best practice after another.</p>
<p>A few things to remember before we start off:</p>
<p>Best practices are, as you might have guessed, not specific laws or rules to follow. They are conventions or tips that have evolved over time and turned out to be effective. Some have became standard nowadays. But this doesn't mean you have to adapt them 1:1.</p>
<p>They should give you a direction to make your API's better in terms of user experience (for the consumer and the builder), security, and performance. </p>
<p>Just keep in mind that projects are different and require different approaches. There might be situations where you can't or shouldn't follow a certain convention. So every engineer has to decide this for themselves or with their.</p>
<p>Now that we've got those things out of our way, without further ado let's get to work!</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-our-example-project">Our Example Project</a><ul>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-architecture">Architecture</a></li>
<li><a class="post-section-overview" href="#heading-basic-setup">Basic Setup</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-rest-api-best-practices">REST API Best Practices</a><ul>
<li><a class="post-section-overview" href="#heading-versioning">Versioning</a></li>
<li><a class="post-section-overview" href="#heading-name-resources-in-plural">Name resources in plural</a></li>
<li><a class="post-section-overview" href="#heading-accept-and-respond-with-data-in-json-format">Accept and respond with data in JSON format</a></li>
<li><a class="post-section-overview" href="#heading-respond-with-standard-http-error-codes">Respond with standard HTTP Error Codes</a></li>
<li><a class="post-section-overview" href="#heading-avoid-verbs-in-endpoint-names">Avoid verbs in endpoint names</a></li>
<li><a class="post-section-overview" href="#heading-group-associated-resources-together-logical-nesting">Group associated resources together</a></li>
<li><a class="post-section-overview" href="#heading-integrate-filtering-sorting-amp-pagination">Integrate filtering, sorting &amp; pagination</a></li>
<li><a class="post-section-overview" href="#heading-use-data-caching-for-performance-improvements">Use data caching for performance improvements</a></li>
<li><a class="post-section-overview" href="#heading-good-security-practices">Good security practices</a></li>
<li><a class="post-section-overview" href="#heading-document-your-api-properly">Document your API properly</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-our-example-project">Our Example Project</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/alvaro-reyes-qWwpHwip31M-unsplash--1-.jpg" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@alvarordesign?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText"&gt;Alvaro Reyes on &lt;a href="https://unsplash.com/s/photos/project?utm_source=unsplash&amp;utm_medium=referral&amp;utm<em>content=creditCopyText)</em></p>
<p>Before we start implementing the best practices into our example project, I'd like to give you a brief introduction to what we'll be building.</p>
<p>We'll build a REST API for a CrossFit Training Application. If you're not familiar with CrossFit, it's a fitness method and competitive sport that combines high-intensity workouts with elements from several sports (olympic weightlifting, gymnastics, and others).</p>
<p>In our application we'd like to create, read, update and delete <strong>WOD</strong>'s (<strong>W</strong>orkouts <strong>o</strong>f the <strong>D</strong>ay). This will help our users (that will be gym owners) come up with workout plans and maintain their own workouts inside a single application. On top of that, they also can add some important training tips for each workout.</p>
<p>Our job will require us to design and implement an API for that application.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>In order to follow along you need to have some experience in JavaScript, Node.js, Express.js and in Backend Architecture. Terms like REST and API shouldn't be new to you and you should have an understanding of the <a target="_blank" href="https://en.wikipedia.org/wiki/Client%E2%80%93server_model">Client-Server-Model</a>.</p>
<p>Of course you don't have to be an expert in those topics, but familiarity and ideally some experience should be enough.</p>
<p>If not all prerequisites apply to you, it's of course not a reason to skip this tutorial. There's still a lot to learn here for you as well. But having those skills will make it easier for you to follow along.</p>
<p>Even though this API is written in JavaScript and Express, the best practices are not limited to these tools. They can be applied to other programming languages or frameworks as well.</p>
<h3 id="heading-architecture">Architecture</h3>
<p>As discussed above, we'll be using Express.js for our API. I don't want to come up with a complex architecture so I'd like to stick to the <strong>3 Layer Architecture:</strong></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-25-um-14.33.24-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Inside the <strong>Controller</strong> we'll be handling all stuff that is related to HTTP. That means we're dealing with requests and responses for our endpoints. Above that layer is also a little <strong>Router</strong> from Express that passes requests to the corresponding controller.</p>
<p>The whole business logic will be in the <strong>Service Layer</strong> that exports certain services (methods) which are used by the controller.</p>
<p>The third layer is the <strong>Data Access Layer</strong> where we'll be working with our Database. We'll be exporting some methods for certain database operations like creating a WOD that can be used by our Service Layer.</p>
<p>In our example we're not using a <em>real</em> database such as MongoDB or PostgreSQL because I'd like to focus more on the best practices itself. Therefore we're using a local JSON file that mimics our Database. But this logic can be transferred to other databases of course.</p>
<h3 id="heading-basic-setup">Basic Setup</h3>
<p>Now we should be ready to create a basic setup for our API. We won't overcomplicate things, and we'll build a simple but organized project structure.</p>
<p>First, let's create the overall folder structure with all necessary files and dependencies. After that, we'll make a quick test to check if everything is running properly:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create project folder &amp; navigate into it</span>
mkdir crossfit-wod-api &amp;&amp; <span class="hljs-built_in">cd</span> crossfit-wod-api
</code></pre>
<pre><code class="lang-bash"><span class="hljs-comment"># Create a src folder &amp; navigate into it</span>
mkdir src &amp;&amp; <span class="hljs-built_in">cd</span> src
</code></pre>
<pre><code class="lang-bash"><span class="hljs-comment"># Create sub folders</span>
mkdir controllers &amp;&amp; mkdir services &amp;&amp; mkdir database &amp;&amp; mkdir routes
</code></pre>
<pre><code class="lang-bash"><span class="hljs-comment"># Create an index file (entry point of our API)</span>
touch index.js
</code></pre>
<pre><code class="lang-bash"><span class="hljs-comment"># We're currently in the src folder, so we need to move one level up first </span>
<span class="hljs-built_in">cd</span> .. 

<span class="hljs-comment"># Create package.json file </span>
npm init -y
</code></pre>
<p>Install dependencies for the basic setup:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Dev Dependencies </span>
npm i -D nodemon 

<span class="hljs-comment"># Dependencies </span>
npm i express
</code></pre>
<p>Open the project up in your favorite Text Editor and configure Express:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/index.js </span>
<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-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3000</span>; 

<span class="hljs-comment">// For testing purposes </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">"&lt;h2&gt;It's Working!&lt;/h2&gt;"</span>); 
}); 

app.listen(PORT, <span class="hljs-function">() =&gt;</span> { 
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`API is listening on port <span class="hljs-subst">${PORT}</span>`</span>); 
});
</code></pre>
<p>Integrate a new script called <strong>"dev"</strong> inside package.json:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"crossfit-wod-api"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"nodemon src/index.js"</span>
  },
  <span class="hljs-attr">"keywords"</span>: [],
  <span class="hljs-attr">"author"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"license"</span>: <span class="hljs-string">"ISC"</span>,
  <span class="hljs-attr">"devDependencies"</span>: {
    <span class="hljs-attr">"nodemon"</span>: <span class="hljs-string">"^2.0.15"</span>
  },
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"express"</span>: <span class="hljs-string">"^4.17.3"</span>
  }
}
</code></pre>
<p>The script makes sure that the development server restarts automatically when we make changes (thanks to nodemon).</p>
<p>Spin up the development server:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Look at your terminal, and there should be a message that the <strong>"API is listening on port 3000"</strong>.</p>
<p>Visit <strong>localhost:3000</strong> inside your browser. When everything is setup correctly, you should see the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-11.09.44.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Great! We're all set up now to implement the best practices.</p>
<h2 id="heading-rest-api-best-practices">REST API Best Practices</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/constantin-wenning-idDvA4jPBO8-unsplash--1-.jpg" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@conniwenningsimages?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText"&gt;Constantin Wenning on &lt;a href="https://unsplash.com/s/photos/handshake?utm_source=unsplash&amp;utm_medium=referral&amp;utm<em>content=creditCopyText)</em></p>
<p>Yeah! Now that we have a really basic Express setup, we can extend our API with the following best practices.</p>
<p>Let's start simple with our fundamental CRUD endpoints. After that we'll be extending the API with each best practice.</p>
<h3 id="heading-versioning">Versioning</h3>
<p>Wait a second. Before we write any API-specific code we should be aware of versioning. Like in other applications there will be improvements, new features, and stuff like that. So it's important to version our API as well.</p>
<p>The big advantage is that we can work on new features or improvements on a new version while the clients are still using the current version and are not affected by breaking changes.</p>
<p>We also don't force the clients to use the new version straight away. They can use the current version and migrate on their own when the new version is stable.</p>
<p>The current and new versions are basically running in parallel and don't affect each other.</p>
<p>But how can we differentiate between the versions? One good practice is to add a path segment like <strong>v1</strong> or <strong>v2</strong> into the URL.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Version 1 </span>
<span class="hljs-string">"/api/v1/workouts"</span> 

<span class="hljs-comment">// Version 2 </span>
<span class="hljs-string">"/api/v2/workouts"</span> 

<span class="hljs-comment">// ...</span>
</code></pre>
<p>That's what we expose to the outside world and what can be consumed by other developers. But we also need to structure our project in order to differentiate between each version.</p>
<p>There are many different approaches to handling versioning inside an Express API. In our case I'd like to create a sub folder for each version inside our <strong>src</strong> directory called <strong>v1</strong>.</p>
<pre><code class="lang-bash">mkdir src/v1
</code></pre>
<p>Now we move our routes folder into that new v1 directory.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Get the path to your current directory (copy it) </span>
<span class="hljs-built_in">pwd</span> 

<span class="hljs-comment"># Move "routes" into "v1" (insert the path from above into {pwd}) </span>
mv {<span class="hljs-built_in">pwd</span>}/src/routes {<span class="hljs-built_in">pwd</span>}/src/v1
</code></pre>
<p>The new directory <strong>/src/v1/routes</strong> will store all our routes for version 1. We will add "real" content later on. But for now let's add a simple <strong>index.js</strong> file to test things out.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># In /src/v1/routes </span>
touch index.js
</code></pre>
<p>Inside there we spin up a simple router.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/v1/routes/index.js</span>
<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> router = express.Router();

router.route(<span class="hljs-string">"/"</span>).get(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">`&lt;h2&gt;Hello from <span class="hljs-subst">${req.baseUrl}</span>&lt;/h2&gt;`</span>);
});

<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<p>Now we have to hook up our router for v1 inside our root entry point inside src/index.js.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/index.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> v1Router = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./v1/routes"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3000</span>;

<span class="hljs-comment">// *** REMOVE ***</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">"&lt;h2&gt;It's Working!&lt;/h2&gt;"</span>);
});

<span class="hljs-comment">// *** ADD ***</span>
app.use(<span class="hljs-string">"/api/v1"</span>, v1Router);

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`API is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>Now visit <strong>localhost:3000/api/v1</strong> inside your browser and you should see the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-11.22.28.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Congratulations! You've just structured the project for handling different versions. We are now passing incoming requests with "/api/v1" to our version 1 router, that will route each request to the corresponding controller method later.</p>
<p>Before we move on, I'd like to point something out.</p>
<p>We just moved our routes folder into our v1 directory. The other folders like controllers or services still remain inside our src directory. That is okay for now because we are building a rather small API. We can use the same controllers and services in each version globally.</p>
<p>When the API is growing and requires different controller methods specific for v2, for example, it would be a better idea to move the controllers folder into the v2 directory as well to have all specific logic for that particular version encapsulated.</p>
<p>Another reason for that could be that we might change a service that is used by all other versions. We don't want to break things in the other versions. So it would be a wise decision to move the services folder also into a specific version folder.</p>
<p>But as I said, in our example it's okay for me to only differentiate between the routes and let the router handle the rest. Nonetheless it's important to keep that in mind to have a clear structure when the API scales up and needs changes.</p>
<h3 id="heading-name-resources-in-plural">Name Resources in Plural</h3>
<p>After setting it all up we can now dive into the real implementation of our API. Like I said, I'd like to start with our fundamental CRUD endpoints.</p>
<p>In other words, let's start implementing endpoints for creating, reading, updating and deleting workouts.</p>
<p>First, let's hook up a specific controller, service, and router for our workouts.</p>
<pre><code class="lang-bash">touch src/controllers/workoutController.js 

touch src/services/workoutService.js 

touch src/v1/routes/workoutRoutes.js
</code></pre>
<p>I always like to start with the routes first. Let's think about how we can name our endpoints. This goes hand in hand with this particular best practice.</p>
<p>We could name the creation endpoint <strong>/api/v1/workout</strong> because we'd like to add one workout, right? Basically there's nothing wrong with that approach – but this can lead to misunderstandings.</p>
<p>Always remember: Your API is used by other humans and should be precise. This goes also for naming your resources.</p>
<p>I always imagine a resource like a box. In our example the box is a collection that stores different <strong>workouts</strong>.</p>
<p>Naming your resources in plural has the big advantage that it's crystal clear to other humans, that this is a collection that consists of different workouts.</p>
<p>So, let's define our endpoints inside our workout router.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/v1/routes/workoutRoutes.js</span>
<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> router = express.Router();

router.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">"Get all workouts"</span>);
});

router.get(<span class="hljs-string">"/:workoutId"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Get an existing workout"</span>);
});

router.post(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Create a new workout"</span>);
});

router.patch(<span class="hljs-string">"/:workoutId"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Update an existing workout"</span>);
});

router.delete(<span class="hljs-string">"/:workoutId"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Delete an existing workout"</span>);
});

<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<p>You can delete our test file <strong>index.js</strong> inside <strong>src/v1/routes</strong>.</p>
<p>Now let's jump into our entry point and hook up our v1 workout router.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/index.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-comment">// *** REMOVE ***</span>
<span class="hljs-keyword">const</span> v1Router = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./v1/routes"</span>);
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> v1WorkoutRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./v1/routes/workoutRoutes"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3000</span>;

<span class="hljs-comment">// *** REMOVE ***</span>
app.use(<span class="hljs-string">"/api/v1"</span>, v1Router);

<span class="hljs-comment">// *** ADD ***</span>
app.use(<span class="hljs-string">"/api/v1/workouts"</span>, v1WorkoutRouter);

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`API is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>That went smoothly, right? Now we're catching all requests that are going to <strong>/api/v1/workouts</strong> with our v1WorkoutRouter.</p>
<p>Inside our router we will call a different method handled by our controller for each different endpoint.</p>
<p>Let's create a method for each endpoint. Just sending a message back should be fine for now.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/controllers/workoutController.js</span>
<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Get all workouts"</span>);
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Get an existing workout"</span>);
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Create a new workout"</span>);
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Update an existing workout"</span>);
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Delete an existing workout"</span>);
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<p>Now it's time to refactor our workout router a bit and use the controller methods.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/v1/routes/workoutRoutes.js</span>
<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> workoutController = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../../controllers/workoutController"</span>);

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

router.get(<span class="hljs-string">"/"</span>, workoutController.getAllWorkouts);

router.get(<span class="hljs-string">"/:workoutId"</span>, workoutController.getOneWorkout);

router.post(<span class="hljs-string">"/"</span>, workoutController.createNewWorkout);

router.patch(<span class="hljs-string">"/:workoutId"</span>, workoutController.updateOneWorkout);

router.delete(<span class="hljs-string">"/:workoutId"</span>, workoutController.deleteOneWorkout);

<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<p>Now we can test our <strong>GET /api/v1/workouts/:workoutId</strong> endpoint by typing <strong>localhost:3000/api/v1/workouts/2342</strong> inside the browser. You should see something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-11.29.19.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We've made it! The first layer of our architecture is done. Let's create our service layer by implementing the next best practice.</p>
<h3 id="heading-accept-and-respond-with-data-in-json-format">Accept and respond with data in JSON format</h3>
<p>When interacting with an API, you always send specific data with your request or you receive data with the response. There are many different data formats but JSON (Javascript Object Notation) is a standardized format.</p>
<p>Although there's the term <strong>JavaScript</strong> in JSON, it's not tied to it specifically. You can also write your API with Java or Python that can handle JSON as well.</p>
<p>Because of its standardization, API's should accept and respond with data in JSON format.</p>
<p>Let's take a look at our current implementation and see how we can integrate this best practice.</p>
<p>First, we create our service layer.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/services/workoutService.js</span>
<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<p>It's also a good practice to name the service methods the same as the controller methods so that you have a connection between those. Let's start off with just returning nothing.</p>
<p>Inside our workout controller we can use these methods.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/controllers/workoutController.js</span>
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> workoutService = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../services/workoutService"</span>);

<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">const</span> allWorkouts = workoutService.getAllWorkouts();
  res.send(<span class="hljs-string">"Get all workouts"</span>);
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">const</span> workout = workoutService.getOneWorkout();
  res.send(<span class="hljs-string">"Get an existing workout"</span>);
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">const</span> createdWorkout = workoutService.createNewWorkout();
  res.send(<span class="hljs-string">"Create a new workout"</span>);
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">const</span> updatedWorkout = workoutService.updateOneWorkout();
  res.send(<span class="hljs-string">"Update an existing workout"</span>);
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// *** ADD ***</span>
  workoutService.deleteOneWorkout();
  res.send(<span class="hljs-string">"Delete an existing workout"</span>);
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<p>At the moment nothing should have changed inside our responses. But under the hood our controller layer talks now with our service layer.</p>
<p>Inside our service methods we'll be handling our business logic like transforming data structures and communicating with our Database Layer.</p>
<p>To do that, we need a database and a collection of methods that actually handle the database interaction. Our database will be a simple JSON file that is pre-filled with some workouts already.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create a new file called db.json inside src/database </span>
touch src/database/db.json 

<span class="hljs-comment"># Create a Workout File that stores all workout specific methods in /src/database </span>
touch src/database/Workout.js
</code></pre>
<p>Copy the following into db.json:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"workouts"</span>: [
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"61dbae02-c147-4e28-863c-db7bd402b2d6"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Tommy V"</span>,
      <span class="hljs-attr">"mode"</span>: <span class="hljs-string">"For Time"</span>,
      <span class="hljs-attr">"equipment"</span>: [
        <span class="hljs-string">"barbell"</span>,
        <span class="hljs-string">"rope"</span>
      ],
      <span class="hljs-attr">"exercises"</span>: [
        <span class="hljs-string">"21 thrusters"</span>,
        <span class="hljs-string">"12 rope climbs, 15 ft"</span>,
        <span class="hljs-string">"15 thrusters"</span>,
        <span class="hljs-string">"9 rope climbs, 15 ft"</span>,
        <span class="hljs-string">"9 thrusters"</span>,
        <span class="hljs-string">"6 rope climbs, 15 ft"</span>
      ],
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"4/20/2022, 2:21:56 PM"</span>,
      <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"4/20/2022, 2:21:56 PM"</span>,
      <span class="hljs-attr">"trainerTips"</span>: [
        <span class="hljs-string">"Split the 21 thrusters as needed"</span>,
        <span class="hljs-string">"Try to do the 9 and 6 thrusters unbroken"</span>,
        <span class="hljs-string">"RX Weights: 115lb/75lb"</span>
      ]
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"4a3d9aaa-608c-49a7-a004-66305ad4ab50"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Dead Push-Ups"</span>,
      <span class="hljs-attr">"mode"</span>: <span class="hljs-string">"AMRAP 10"</span>,
      <span class="hljs-attr">"equipment"</span>: [
        <span class="hljs-string">"barbell"</span>
      ],
      <span class="hljs-attr">"exercises"</span>: [
        <span class="hljs-string">"15 deadlifts"</span>,
        <span class="hljs-string">"15 hand-release push-ups"</span>
      ],
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"1/25/2022, 1:15:44 PM"</span>,
      <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"3/10/2022, 8:21:56 AM"</span>,
      <span class="hljs-attr">"trainerTips"</span>: [
        <span class="hljs-string">"Deadlifts are meant to be light and fast"</span>,
        <span class="hljs-string">"Try to aim for unbroken sets"</span>,
        <span class="hljs-string">"RX Weights: 135lb/95lb"</span>
      ]
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"d8be2362-7b68-4ea4-a1f6-03f8bc4eede7"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Heavy DT"</span>,
      <span class="hljs-attr">"mode"</span>: <span class="hljs-string">"5 Rounds For Time"</span>,
      <span class="hljs-attr">"equipment"</span>: [
        <span class="hljs-string">"barbell"</span>,
        <span class="hljs-string">"rope"</span>
      ],
      <span class="hljs-attr">"exercises"</span>: [
        <span class="hljs-string">"12 deadlifts"</span>,
        <span class="hljs-string">"9 hang power cleans"</span>,
        <span class="hljs-string">"6 push jerks"</span>
      ],
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"11/20/2021, 5:39:07 PM"</span>,
      <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"11/20/2021, 5:39:07 PM"</span>,
      <span class="hljs-attr">"trainerTips"</span>: [
        <span class="hljs-string">"Aim for unbroken push jerks"</span>,
        <span class="hljs-string">"The first three rounds might feel terrible, but stick to it"</span>,
        <span class="hljs-string">"RX Weights: 205lb/145lb"</span>
      ]
    }
  ]
}
</code></pre>
<p>As you can see there are three workouts inserted. One workout consists of an id, name, mode, equipment, exercises, createdAt, updatedAt, and trainerTips.</p>
<p>Let's start with the simplest one and return all workouts that are stored and start with implementing the corresponding method inside our Data Access Layer (src/database/Workout.js).</p>
<p>Again, I've chosen to name the method inside here the same as the one in the service and the controller. But this it totally optional.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/database/Workout.js</span>
<span class="hljs-keyword">const</span> DB = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./db.json"</span>);

<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> DB.workouts;
};

<span class="hljs-built_in">module</span>.exports = { getAllWorkouts };
</code></pre>
<p>Jump right back into our workout service and implement the logic for <strong>getAllWorkouts.</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/database/workoutService.js</span>
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> Workout = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../database/Workout"</span>);
<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">const</span> allWorkouts = Workout.getAllWorkouts();
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">return</span> allWorkouts;
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<p>Returning all workouts is pretty simple and we don't have to do transformations because it's already a JSON file. We also don't need to take in any arguments for now. So this implementation is pretty straightforward. But we'll come back to this later.</p>
<p>Back in our workout controller we receive the return value from <code>workoutService.getAllWorkouts()</code> and simply send it as a response to the client. We've looped the database response through our service to the controller.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/controllers/workoutControllers.js</span>
<span class="hljs-keyword">const</span> workoutService = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../services/workoutService"</span>);

<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> allWorkouts = workoutService.getAllWorkouts();
  <span class="hljs-comment">// *** ADD ***</span>
  res.send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: allWorkouts });
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> workout = workoutService.getOneWorkout();
  res.send(<span class="hljs-string">"Get an existing workout"</span>);
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> createdWorkout = workoutService.createNewWorkout();
  res.send(<span class="hljs-string">"Create a new workout"</span>);
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> updatedWorkout = workoutService.updateOneWorkout();
  res.send(<span class="hljs-string">"Update an existing workout"</span>);
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  workoutService.deleteOneWorkout();
  res.send(<span class="hljs-string">"Delete an existing workout"</span>);
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<p>Go to <strong>localhost:3000/api/v1/workouts</strong> inside your browser and you should see the response JSON.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-11.38.14.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>That went great! We're sending back data in JSON format. But what about accepting it? Let's think about an endpoint where we need to receive JSON data from the client. The endpoint for creating or updating a workout needs data from the client.</p>
<p>Inside our workout controller we extract the request body for creating a new workout and we pass it on to the workout service. Inside the workout service we'll insert it into our DB.json and send the newly created workout back to the client.</p>
<p>To be able to parse the sent JSON inside the request body, we need to install <strong>body-parser</strong> first and configure it.</p>
<pre><code class="lang-bash">npm i body-parser
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/index.js </span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> bodyParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"body-parser"</span>);
<span class="hljs-keyword">const</span> v1WorkoutRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./v1/routes/workoutRoutes"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3000</span>;

<span class="hljs-comment">// *** ADD ***</span>
app.use(bodyParser.json());
app.use(<span class="hljs-string">"/api/v1/workouts"</span>, v1WorkoutRouter);

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`API is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>Now we're able to receive the JSON data inside our controllers under <strong>req.body.</strong></p>
<p>In order to test it properly, just open your favorite HTTP client (I'm using Postman), create a POST request to localhost:3000/api/v1/workouts and a request body in JSON format like this:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"Core Buster"</span>,
  <span class="hljs-string">"mode"</span>: <span class="hljs-string">"AMRAP 20"</span>,
  <span class="hljs-string">"equipment"</span>: [
    <span class="hljs-string">"rack"</span>,
    <span class="hljs-string">"barbell"</span>,
    <span class="hljs-string">"abmat"</span>
  ],
  <span class="hljs-string">"exercises"</span>: [
    <span class="hljs-string">"15 toes to bars"</span>,
    <span class="hljs-string">"10 thrusters"</span>,
    <span class="hljs-string">"30 abmat sit-ups"</span>
  ],
  <span class="hljs-string">"trainerTips"</span>: [
    <span class="hljs-string">"Split your toes to bars into two sets maximum"</span>,
    <span class="hljs-string">"Go unbroken on the thrusters"</span>,
    <span class="hljs-string">"Take the abmat sit-ups as a chance to normalize your breath"</span>
  ]
}
</code></pre>
<p>As you've might noticed, there are some properties missing like "id", "createdAt" and "updatedAt". That's the job of our API to add those properties before inserting it. We'll take care of it inside our workout service later.</p>
<p>Inside the method <strong>createNewWorkout</strong> in our workout controller, we can extract the body from the request object, do some validation, and pass it as an argument to our workout service.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/controllers/workoutController.js</span>
...

const createNewWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { body } = req;
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">if</span> (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    <span class="hljs-keyword">return</span>;
  }
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">const</span> newWorkout = {
    <span class="hljs-attr">name</span>: body.name,
    <span class="hljs-attr">mode</span>: body.mode,
    <span class="hljs-attr">equipment</span>: body.equipment,
    <span class="hljs-attr">exercises</span>: body.exercises,
    <span class="hljs-attr">trainerTips</span>: body.trainerTips,
  };
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">const</span> createdWorkout = workoutService.createNewWorkout(newWorkout);
  <span class="hljs-comment">// *** ADD ***</span>
  res.status(<span class="hljs-number">201</span>).send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: createdWorkout });
};

...
</code></pre>
<p>To improve the request validation you normally would use a third party package like <a target="_blank" href="https://express-validator.github.io/docs/">express-validator</a>.</p>
<p>Let's go into our workout service and receive the data inside our createNewWorkout method.</p>
<p>After that we add the missing properties to the object and pass it to a new method in our Data Access Layer to store it inside our DB.</p>
<p>First, we create a simple Util Function to overwrite our JSON file to persist the data.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create a utils file inside our database directory </span>
touch src/database/utils.js
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/database/utils.js</span>
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

<span class="hljs-keyword">const</span> saveToDatabase = <span class="hljs-function">(<span class="hljs-params">DB</span>) =&gt;</span> {
  fs.writeFileSync(<span class="hljs-string">"./src/database/db.json"</span>, <span class="hljs-built_in">JSON</span>.stringify(DB, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>), {
    <span class="hljs-attr">encoding</span>: <span class="hljs-string">"utf-8"</span>,
  });
};

<span class="hljs-built_in">module</span>.exports = { saveToDatabase };
</code></pre>
<p>Then we can use this function in our Workout.js file.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/database/Workout.js</span>
<span class="hljs-keyword">const</span> DB = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./db.json"</span>);
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> { saveToDatabase } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./utils"</span>);


<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> DB.workouts;
};

<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">newWorkout</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> isAlreadyAdded =
    DB.workouts.findIndex(<span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.name === newWorkout.name) &gt; <span class="hljs-number">-1</span>;
  <span class="hljs-keyword">if</span> (isAlreadyAdded) {
    <span class="hljs-keyword">return</span>;
  }
  DB.workouts.push(newWorkout);
  saveToDatabase(DB);
  <span class="hljs-keyword">return</span> newWorkout;
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  <span class="hljs-comment">// *** ADD ***</span>
  createNewWorkout,
};
</code></pre>
<p>That was smooth! The next step is to use the database methods inside our workout service.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install the uuid package </span>
npm i uuid
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/services/workoutService.js</span>
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> { <span class="hljs-attr">v4</span>: uuid } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"uuid"</span>);
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> Workout = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../database/Workout"</span>);

<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> allWorkouts = Workout.getAllWorkouts();
    <span class="hljs-keyword">return</span> allWorkouts;
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">newWorkout</span>) =&gt;</span> {
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">const</span> workoutToInsert = {
    ...newWorkout,
    <span class="hljs-attr">id</span>: uuid(),
    <span class="hljs-attr">createdAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
    <span class="hljs-attr">updatedAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
  };
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">const</span> createdWorkout = Workout.createNewWorkout(workoutToInsert);
  <span class="hljs-keyword">return</span> createdWorkout;
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span>;
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<p>Wow! This was fun, right? Now you can go to your HTTP client, send the POST request again, and you should receive the newly created workout as JSON.</p>
<p>If you try to add the same workout for a second time, you still receive a 201 status code, but without the newly inserted workout. </p>
<p>This means that our database method cancels the insertion for now and is just returning nothing. That's because our if-statement to check if there is already a workout inserted with the same name kicks in. That's good for now, we'll handle that case in the next best practice!</p>
<p>Now, send a GET request to <strong>localhost:3000/api/v1/workouts</strong> to read all workouts. I'm choosing the browser for that. You should see that our workout got successfully inserted and persisted:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-11.57.23.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You can implement the other methods by yourself or just copy my implementations.</p>
<p>First, the workout controller (you can just copy the whole content):</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/controllers/workoutController.js</span>
<span class="hljs-keyword">const</span> workoutService = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../services/workoutService"</span>);

<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> allWorkouts = workoutService.getAllWorkouts();
  res.send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: allWorkouts });
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> {
    <span class="hljs-attr">params</span>: { workoutId },
  } = req;
  <span class="hljs-keyword">if</span> (!workoutId) {
    <span class="hljs-keyword">return</span>;
  }
  <span class="hljs-keyword">const</span> workout = workoutService.getOneWorkout(workoutId);
  res.send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: workout });
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { body } = req;
  <span class="hljs-keyword">if</span> (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    <span class="hljs-keyword">return</span>;
  }
  <span class="hljs-keyword">const</span> newWorkout = {
    <span class="hljs-attr">name</span>: body.name,
    <span class="hljs-attr">mode</span>: body.mode,
    <span class="hljs-attr">equipment</span>: body.equipment,
    <span class="hljs-attr">exercises</span>: body.exercises,
    <span class="hljs-attr">trainerTips</span>: body.trainerTips,
  };
  <span class="hljs-keyword">const</span> createdWorkout = workoutService.createNewWorkout(newWorkout);
  res.status(<span class="hljs-number">201</span>).send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: createdWorkout });
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> {
    body,
    <span class="hljs-attr">params</span>: { workoutId },
  } = req;
  <span class="hljs-keyword">if</span> (!workoutId) {
    <span class="hljs-keyword">return</span>;
  }
  <span class="hljs-keyword">const</span> updatedWorkout = workoutService.updateOneWorkout(workoutId, body);
  res.send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: updatedWorkout });
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> {
    <span class="hljs-attr">params</span>: { workoutId },
  } = req;
  <span class="hljs-keyword">if</span> (!workoutId) {
    <span class="hljs-keyword">return</span>;
  }
  workoutService.deleteOneWorkout(workoutId);
  res.status(<span class="hljs-number">204</span>).send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span> });
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<p>Then, the workout service (you can just copy the whole content):</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/services/workoutServices.js</span>
<span class="hljs-keyword">const</span> { <span class="hljs-attr">v4</span>: uuid } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"uuid"</span>);
<span class="hljs-keyword">const</span> Workout = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../database/Workout"</span>);

<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> allWorkouts = Workout.getAllWorkouts();
  <span class="hljs-keyword">return</span> allWorkouts;
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> workout = Workout.getOneWorkout(workoutId);
  <span class="hljs-keyword">return</span> workout;
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">newWorkout</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> workoutToInsert = {
    ...newWorkout,
    <span class="hljs-attr">id</span>: uuid(),
    <span class="hljs-attr">createdAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
    <span class="hljs-attr">updatedAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
  };
  <span class="hljs-keyword">const</span> createdWorkout = Workout.createNewWorkout(workoutToInsert);
  <span class="hljs-keyword">return</span> createdWorkout;
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId, changes</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> updatedWorkout = Workout.updateOneWorkout(workoutId, changes);
  <span class="hljs-keyword">return</span> updatedWorkout;
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId</span>) =&gt;</span> {
  Workout.deleteOneWorkout(workoutId);
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<p>And finally our database methods inside the Data Access Layer (you can just copy the whole content):</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/database/Workout.js</span>
<span class="hljs-keyword">const</span> DB = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./db.json"</span>);
<span class="hljs-keyword">const</span> { saveToDatabase } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./utils"</span>);

<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> DB.workouts;
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> workout = DB.workouts.find(<span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.id === workoutId);
  <span class="hljs-keyword">if</span> (!workout) {
    <span class="hljs-keyword">return</span>;
  }
  <span class="hljs-keyword">return</span> workout;
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">newWorkout</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> isAlreadyAdded =
    DB.workouts.findIndex(<span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.name === newWorkout.name) &gt; <span class="hljs-number">-1</span>;
  <span class="hljs-keyword">if</span> (isAlreadyAdded) {
    <span class="hljs-keyword">return</span>;
  }
  DB.workouts.push(newWorkout);
  saveToDatabase(DB);
  <span class="hljs-keyword">return</span> newWorkout;
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId, changes</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> indexForUpdate = DB.workouts.findIndex(
    <span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.id === workoutId
  );
  <span class="hljs-keyword">if</span> (indexForUpdate === <span class="hljs-number">-1</span>) {
    <span class="hljs-keyword">return</span>;
  }
  <span class="hljs-keyword">const</span> updatedWorkout = {
    ...DB.workouts[indexForUpdate],
    ...changes,
    <span class="hljs-attr">updatedAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
  };
  DB.workouts[indexForUpdate] = updatedWorkout;
  saveToDatabase(DB);
  <span class="hljs-keyword">return</span> updatedWorkout;
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> indexForDeletion = DB.workouts.findIndex(
    <span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.id === workoutId
  );
  <span class="hljs-keyword">if</span> (indexForDeletion === <span class="hljs-number">-1</span>) {
    <span class="hljs-keyword">return</span>;
  }
  DB.workouts.splice(indexForDeletion, <span class="hljs-number">1</span>);
  saveToDatabase(DB);
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  createNewWorkout,
  getOneWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<p>Great! Let's move on to the next best practice and see how we can handle errors properly.</p>
<h3 id="heading-respond-with-standard-http-error-codes">Respond with standard HTTP Error Codes</h3>
<p>We've already came pretty far, but we're not finished yet. Our API has the ability now to handle basic CRUD operations with data storage. That's great, but not really ideal.</p>
<p>Why? Let me explain.</p>
<p>In a perfect world everything works smoothly without any errors. But as you might know, in the real world a lot of errors can happen – either from a human or a technical perspective.</p>
<p>You might probably know that weird feeling when things are working right from the beginning without any errors. This is great and enjoyable, but as developers we're more used to things that are not working properly. 😁</p>
<p>The same goes for our API. We should handle certain cases that might go wrong or throw an error. This will also harden our API.</p>
<p>When something goes wrong (either from the request or inside our API) we send HTTP Error codes back. I've seen and used API's that were returning all the time a 400 error code when a request was buggy without any specific message about WHY this error occurred or what the mistake was. So debugging became a pain.</p>
<p>That's the reason why it's always a good practice to return proper HTTP error codes for different cases. This helps the consumer or the engineer who built the API to identify the problem more easily.</p>
<p>To improve the experience we also can send a quick error message along with the error response. But as I've written in the introduction this isn't always very wise and should be considered by the engineer themself.</p>
<p>For example, returning something like <strong>"The username is already signed up"</strong> should be well thought out because you're providing information about your users that you should really hide.</p>
<p>In our Crossfit API we will take a look at the creation endpoint and see what errors might arise and how we can handle them. At the end of this tip you'll find again the complete implementation for the other endpoints.</p>
<p>Let's start looking at our createNewWorkout method inside our workout controller:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/controllers/workoutController.js</span>
...

const createNewWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { body } = req;
  <span class="hljs-keyword">if</span> (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    <span class="hljs-keyword">return</span>;
  }
  <span class="hljs-keyword">const</span> newWorkout = {
    <span class="hljs-attr">name</span>: body.name,
    <span class="hljs-attr">mode</span>: body.mode,
    <span class="hljs-attr">equipment</span>: body.equipment,
    <span class="hljs-attr">exercises</span>: body.exercises,
    <span class="hljs-attr">trainerTips</span>: body.trainerTips,
  };
  <span class="hljs-keyword">const</span> createdWorkout = workoutService.createNewWorkout(newWorkout);
  res.status(<span class="hljs-number">201</span>).send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: createdWorkout });
};

...
</code></pre>
<p>We already caught the case that the request body is not built up properly and got missing keys that we expect.</p>
<p>This would be a good example to send back a 400 HTTP error with a corresponding error message.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/controllers/workoutController.js</span>
...

const createNewWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { body } = req;
  <span class="hljs-keyword">if</span> (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    res
      .status(<span class="hljs-number">400</span>)
      .send({
        <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>,
        <span class="hljs-attr">data</span>: {
          <span class="hljs-attr">error</span>:
            <span class="hljs-string">"One of the following keys is missing or is empty in request body: 'name', 'mode', 'equipment', 'exercises', 'trainerTips'"</span>,
        },
      });
    <span class="hljs-keyword">return</span>;
  }
  <span class="hljs-keyword">const</span> newWorkout = {
    <span class="hljs-attr">name</span>: body.name,
    <span class="hljs-attr">mode</span>: body.mode,
    <span class="hljs-attr">equipment</span>: body.equipment,
    <span class="hljs-attr">exercises</span>: body.exercises,
    <span class="hljs-attr">trainerTips</span>: body.trainerTips,
  };
  <span class="hljs-keyword">const</span> createdWorkout = workoutService.createNewWorkout(newWorkout);
  res.status(<span class="hljs-number">201</span>).send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: createdWorkout });
};

...
</code></pre>
<p>If we try to add a new workout but forget to provide the "mode" property in our request body, we should see the error message along with the 400 HTTP error code.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-15.17.21.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>A developer who is consuming the API is now better informed about what to look for. They immediately know to go inside the request body and see if they've missed providing one of the required properties.</p>
<p>Leaving this error message more generic for all properties will be okay for now. Typically you'd use a schema validator for handling that.</p>
<p>Let's go one layer deeper into our workout service and see what potential errors might occur.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/services/workoutService.js</span>
...

const createNewWorkout = <span class="hljs-function">(<span class="hljs-params">newWorkout</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> workoutToInsert = {
    ...newWorkout,
    <span class="hljs-attr">id</span>: uuid(),
    <span class="hljs-attr">createdAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
    <span class="hljs-attr">updatedAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
  };
  <span class="hljs-keyword">const</span> createdWorkout = Workout.createNewWorkout(workoutToInsert);
  <span class="hljs-keyword">return</span> createdWorkout;
};

...
</code></pre>
<p>One thing that might go wrong is the database insertion <strong>Workout.createNewWorkout().</strong> I like to wrap this thing in a try/catch block to catch the error when it occurs.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/services/workoutService.js</span>
...

const createNewWorkout = <span class="hljs-function">(<span class="hljs-params">newWorkout</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> workoutToInsert = {
    ...newWorkout,
    <span class="hljs-attr">id</span>: uuid(),
    <span class="hljs-attr">createdAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
    <span class="hljs-attr">updatedAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
  };
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> createdWorkout = Workout.createNewWorkout(workoutToInsert);
    <span class="hljs-keyword">return</span> createdWorkout;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> error;
  }
};

...
</code></pre>
<p>Every error that gets thrown inside our Workout.createNewWorkout() method will be caught inside our catch block. We're just throwing it back, so we can adjust our responses later inside our controller.</p>
<p>Let's define our errors in Workout.js:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/database/Workout.js</span>
...

const createNewWorkout = <span class="hljs-function">(<span class="hljs-params">newWorkout</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> isAlreadyAdded =
    DB.workouts.findIndex(<span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.name === newWorkout.name) &gt; <span class="hljs-number">-1</span>;
  <span class="hljs-keyword">if</span> (isAlreadyAdded) {
    <span class="hljs-keyword">throw</span> {
      <span class="hljs-attr">status</span>: <span class="hljs-number">400</span>,
      <span class="hljs-attr">message</span>: <span class="hljs-string">`Workout with the name '<span class="hljs-subst">${newWorkout.name}</span>' already exists`</span>,
    };
  }
  <span class="hljs-keyword">try</span> {
    DB.workouts.push(newWorkout);
    saveToDatabase(DB);
    <span class="hljs-keyword">return</span> newWorkout;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> { <span class="hljs-attr">status</span>: <span class="hljs-number">500</span>, <span class="hljs-attr">message</span>: error?.message || error };
  }
};

...
</code></pre>
<p>As you can see, an error consists of two things, a status and a message. I'm using just the <strong>throw</strong> keyword here to send out a different data structure than a string, which is required in <strong>throw new Error()</strong>. </p>
<p>A little downside of just throwing is that we don't get a stack trace. But normally this error throwing would be handled by a third party library of our choice (for example Mongoose if you use a MongoDB database). But for the purposes of this tutorial this should be fine.</p>
<p>Now we're able to throw and catch errors in the service and data access layer. We can move into our workout controller now, catch the errors there as well, and respond accordingly.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/controllers/workoutController.js</span>
...

const createNewWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { body } = req;
  <span class="hljs-keyword">if</span> (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    res
      .status(<span class="hljs-number">400</span>)
      .send({
        <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>,
        <span class="hljs-attr">data</span>: {
          <span class="hljs-attr">error</span>:
            <span class="hljs-string">"One of the following keys is missing or is empty in request body: 'name', 'mode', 'equipment', 'exercises', 'trainerTips'"</span>,
        },
      });
    <span class="hljs-keyword">return</span>;
  }
  <span class="hljs-keyword">const</span> newWorkout = {
    <span class="hljs-attr">name</span>: body.name,
    <span class="hljs-attr">mode</span>: body.mode,
    <span class="hljs-attr">equipment</span>: body.equipment,
    <span class="hljs-attr">exercises</span>: body.exercises,
    <span class="hljs-attr">trainerTips</span>: body.trainerTips,
  };
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> createdWorkout = workoutService.createNewWorkout(newWorkout);
    res.status(<span class="hljs-number">201</span>).send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: createdWorkout });
  } <span class="hljs-keyword">catch</span> (error) {
    res
      .status(error?.status || <span class="hljs-number">500</span>)
      .send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>, <span class="hljs-attr">data</span>: { <span class="hljs-attr">error</span>: error?.message || error } });
  }
};

...
</code></pre>
<p>You can test things out by adding a workout with the same name twice or not providing a required property inside your request body. You should receive the corresponding HTTP error codes along with the error message.</p>
<p>To wrap this up and move to the next tip, you can copy the other implemented methods into the following files or you can try it on your own:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/controllers/workoutController.js</span>
<span class="hljs-keyword">const</span> workoutService = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../services/workoutService"</span>);

<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> allWorkouts = workoutService.getAllWorkouts();
    res.send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: allWorkouts });
  } <span class="hljs-keyword">catch</span> (error) {
    res
      .status(error?.status || <span class="hljs-number">500</span>)
      .send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>, <span class="hljs-attr">data</span>: { <span class="hljs-attr">error</span>: error?.message || error } });
  }
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> {
    <span class="hljs-attr">params</span>: { workoutId },
  } = req;
  <span class="hljs-keyword">if</span> (!workoutId) {
    res
      .status(<span class="hljs-number">400</span>)
      .send({
        <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>,
        <span class="hljs-attr">data</span>: { <span class="hljs-attr">error</span>: <span class="hljs-string">"Parameter ':workoutId' can not be empty"</span> },
      });
  }
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> workout = workoutService.getOneWorkout(workoutId);
    res.send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: workout });
  } <span class="hljs-keyword">catch</span> (error) {
    res
      .status(error?.status || <span class="hljs-number">500</span>)
      .send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>, <span class="hljs-attr">data</span>: { <span class="hljs-attr">error</span>: error?.message || error } });
  }
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { body } = req;
  <span class="hljs-keyword">if</span> (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    res
      .status(<span class="hljs-number">400</span>)
      .send({
        <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>,
        <span class="hljs-attr">data</span>: {
          <span class="hljs-attr">error</span>:
            <span class="hljs-string">"One of the following keys is missing or is empty in request body: 'name', 'mode', 'equipment', 'exercises', 'trainerTips'"</span>,
        },
      });
    <span class="hljs-keyword">return</span>;
  }
  <span class="hljs-keyword">const</span> newWorkout = {
    <span class="hljs-attr">name</span>: body.name,
    <span class="hljs-attr">mode</span>: body.mode,
    <span class="hljs-attr">equipment</span>: body.equipment,
    <span class="hljs-attr">exercises</span>: body.exercises,
    <span class="hljs-attr">trainerTips</span>: body.trainerTips,
  };
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> createdWorkout = workoutService.createNewWorkout(newWorkout);
    res.status(<span class="hljs-number">201</span>).send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: createdWorkout });
  } <span class="hljs-keyword">catch</span> (error) {
    res
      .status(error?.status || <span class="hljs-number">500</span>)
      .send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>, <span class="hljs-attr">data</span>: { <span class="hljs-attr">error</span>: error?.message || error } });
  }
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> {
    body,
    <span class="hljs-attr">params</span>: { workoutId },
  } = req;
  <span class="hljs-keyword">if</span> (!workoutId) {
    res
      .status(<span class="hljs-number">400</span>)
      .send({
        <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>,
        <span class="hljs-attr">data</span>: { <span class="hljs-attr">error</span>: <span class="hljs-string">"Parameter ':workoutId' can not be empty"</span> },
      });
  }
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> updatedWorkout = workoutService.updateOneWorkout(workoutId, body);
    res.send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: updatedWorkout });
  } <span class="hljs-keyword">catch</span> (error) {
    res
      .status(error?.status || <span class="hljs-number">500</span>)
      .send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>, <span class="hljs-attr">data</span>: { <span class="hljs-attr">error</span>: error?.message || error } });
  }
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> {
    <span class="hljs-attr">params</span>: { workoutId },
  } = req;
  <span class="hljs-keyword">if</span> (!workoutId) {
    res
      .status(<span class="hljs-number">400</span>)
      .send({
        <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>,
        <span class="hljs-attr">data</span>: { <span class="hljs-attr">error</span>: <span class="hljs-string">"Parameter ':workoutId' can not be empty"</span> },
      });
  }
  <span class="hljs-keyword">try</span> {
    workoutService.deleteOneWorkout(workoutId);
    res.status(<span class="hljs-number">204</span>).send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span> });
  } <span class="hljs-keyword">catch</span> (error) {
    res
      .status(error?.status || <span class="hljs-number">500</span>)
      .send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>, <span class="hljs-attr">data</span>: { <span class="hljs-attr">error</span>: error?.message || error } });
  }
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
  getRecordsForWorkout,
};
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/services/workoutService.js</span>
<span class="hljs-keyword">const</span> { <span class="hljs-attr">v4</span>: uuid } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"uuid"</span>);
<span class="hljs-keyword">const</span> Workout = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../database/Workout"</span>);

<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> allWorkouts = Workout.getAllWorkouts();
    <span class="hljs-keyword">return</span> allWorkouts;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> error;
  }
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> workout = Workout.getOneWorkout(workoutId);
    <span class="hljs-keyword">return</span> workout;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> error;
  }
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">newWorkout</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> workoutToInsert = {
    ...newWorkout,
    <span class="hljs-attr">id</span>: uuid(),
    <span class="hljs-attr">createdAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
    <span class="hljs-attr">updatedAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
  };
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> createdWorkout = Workout.createNewWorkout(workoutToInsert);
    <span class="hljs-keyword">return</span> createdWorkout;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> error;
  }
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId, changes</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> updatedWorkout = Workout.updateOneWorkout(workoutId, changes);
    <span class="hljs-keyword">return</span> updatedWorkout;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> error;
  }
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    Workout.deleteOneWorkout(workoutId);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> error;
  }
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/database/Workout.js</span>
<span class="hljs-keyword">const</span> DB = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./db.json"</span>);
<span class="hljs-keyword">const</span> { saveToDatabase } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./utils"</span>);

<span class="hljs-keyword">const</span> getAllWorkouts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">return</span> DB.workouts;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> { <span class="hljs-attr">status</span>: <span class="hljs-number">500</span>, <span class="hljs-attr">message</span>: error };
  }
};

<span class="hljs-keyword">const</span> getOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> workout = DB.workouts.find(<span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.id === workoutId);
    <span class="hljs-keyword">if</span> (!workout) {
      <span class="hljs-keyword">throw</span> {
        <span class="hljs-attr">status</span>: <span class="hljs-number">400</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">`Can't find workout with the id '<span class="hljs-subst">${workoutId}</span>'`</span>,
      };
    }
    <span class="hljs-keyword">return</span> workout;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> { <span class="hljs-attr">status</span>: error?.status || <span class="hljs-number">500</span>, <span class="hljs-attr">message</span>: error?.message || error };
  }
};

<span class="hljs-keyword">const</span> createNewWorkout = <span class="hljs-function">(<span class="hljs-params">newWorkout</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> isAlreadyAdded =
      DB.workouts.findIndex(<span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.name === newWorkout.name) &gt; <span class="hljs-number">-1</span>;
    <span class="hljs-keyword">if</span> (isAlreadyAdded) {
      <span class="hljs-keyword">throw</span> {
        <span class="hljs-attr">status</span>: <span class="hljs-number">400</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">`Workout with the name '<span class="hljs-subst">${newWorkout.name}</span>' already exists`</span>,
      };
    }
    DB.workouts.push(newWorkout);
    saveToDatabase(DB);
    <span class="hljs-keyword">return</span> newWorkout;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> { <span class="hljs-attr">status</span>: error?.status || <span class="hljs-number">500</span>, <span class="hljs-attr">message</span>: error?.message || error };
  }
};

<span class="hljs-keyword">const</span> updateOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId, changes</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> isAlreadyAdded =
      DB.workouts.findIndex(<span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.name === changes.name) &gt; <span class="hljs-number">-1</span>;
    <span class="hljs-keyword">if</span> (isAlreadyAdded) {
      <span class="hljs-keyword">throw</span> {
        <span class="hljs-attr">status</span>: <span class="hljs-number">400</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">`Workout with the name '<span class="hljs-subst">${changes.name}</span>' already exists`</span>,
      };
    }
    <span class="hljs-keyword">const</span> indexForUpdate = DB.workouts.findIndex(
      <span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.id === workoutId
    );
    <span class="hljs-keyword">if</span> (indexForUpdate === <span class="hljs-number">-1</span>) {
      <span class="hljs-keyword">throw</span> {
        <span class="hljs-attr">status</span>: <span class="hljs-number">400</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">`Can't find workout with the id '<span class="hljs-subst">${workoutId}</span>'`</span>,
      };
    }
    <span class="hljs-keyword">const</span> updatedWorkout = {
      ...DB.workouts[indexForUpdate],
      ...changes,
      <span class="hljs-attr">updatedAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString(<span class="hljs-string">"en-US"</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">"UTC"</span> }),
    };
    DB.workouts[indexForUpdate] = updatedWorkout;
    saveToDatabase(DB);
    <span class="hljs-keyword">return</span> updatedWorkout;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> { <span class="hljs-attr">status</span>: error?.status || <span class="hljs-number">500</span>, <span class="hljs-attr">message</span>: error?.message || error };
  }
};

<span class="hljs-keyword">const</span> deleteOneWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> indexForDeletion = DB.workouts.findIndex(
      <span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span> workout.id === workoutId
    );
    <span class="hljs-keyword">if</span> (indexForDeletion === <span class="hljs-number">-1</span>) {
      <span class="hljs-keyword">throw</span> {
        <span class="hljs-attr">status</span>: <span class="hljs-number">400</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">`Can't find workout with the id '<span class="hljs-subst">${workoutId}</span>'`</span>,
      };
    }
    DB.workouts.splice(indexForDeletion, <span class="hljs-number">1</span>);
    saveToDatabase(DB);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> { <span class="hljs-attr">status</span>: error?.status || <span class="hljs-number">500</span>, <span class="hljs-attr">message</span>: error?.message || error };
  }
};

<span class="hljs-built_in">module</span>.exports = {
  getAllWorkouts,
  createNewWorkout,
  getOneWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre>
<h3 id="heading-avoid-verbs-in-endpoint-names">Avoid verbs in endpoint names</h3>
<p>It doesn't make much sense to use verbs inside your endpoints and is, in fact, pretty useless. Generally each URL should point towards a resource (remember the box example from above). Nothing more and nothing less.</p>
<p>Using a verb inside a URL shows a certain behavior which a resource itself can not have.</p>
<p>We've already implemented the endpoints correctly without using verbs inside the URL, but let's take a look how our URL's would look like if we had used verbs.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Current implementations (without verbs)</span>
GET <span class="hljs-string">"/api/v1/workouts"</span> 
GET <span class="hljs-string">"/api/v1/workouts/:workoutId"</span> 
POST <span class="hljs-string">"/api/v1/workouts"</span> 
PATCH <span class="hljs-string">"/api/v1/workouts/:workoutId"</span> 
DELETE <span class="hljs-string">"/api/v1/workouts/:workoutId"</span>  

<span class="hljs-comment">// Implementation using verbs </span>
GET <span class="hljs-string">"/api/v1/getAllWorkouts"</span> 
GET <span class="hljs-string">"/api/v1/getWorkoutById/:workoutId"</span> 
CREATE <span class="hljs-string">"/api/v1/createWorkout"</span> 
PATCH <span class="hljs-string">"/api/v1/updateWorkout/:workoutId"</span> 
DELETE <span class="hljs-string">"/api/v1/deleteWorkout/:workoutId"</span>
</code></pre>
<p>Do you see the difference? Having a completely different URL for every behavior can become confusing and unnecessarily complex pretty fast.</p>
<p>Imagine we've got 300 different endpoints. Using a separate URL for each one might be an overhead (and documentation) hell.</p>
<p>Another reason I'd like to point out for not using verbs inside your URL is that the HTTP verb itself already indicates the action.</p>
<p>Things like <strong>"GET /api/v1/getAllWorkouts"</strong> or <strong>"DELETE api/v1/deleteWorkout/workoutId"</strong> are unnecessary.</p>
<p>When you take a look at our current implementation it becomes way cleaner because we're only using two different URL's and the actual behavior is handled via the HTTP verb and the corresponding request payload.</p>
<p>I always imagine that the HTTP verb describes the action (what we'd like to do) and the URL itself (that points towards a resource) the target. <strong>"GET /api/v1/workouts"</strong> is also more fluent in human language.</p>
<h3 id="heading-group-associated-resources-together-logical-nesting">Group associated resources together (logical nesting)</h3>
<p>When you're designing your API, there might be cases where you have resources that are associated with others. It's a good practice to group them together into one endpoint and nest them properly.</p>
<p>Let's consider that, in our API, we also have a list of members that are signed up in our CrossFit box ("box" is the name for a CrossFit gym). In order to motivate our members we track the overall box records for each workout.</p>
<p>For example, there is a workout where you have to do a certain order of exercises as quickly as possible. We record the times for all members to have a list of the time for each member who completed this workout.</p>
<p>Now, the frontend needs an endpoint that responds with all records for a specific workout in order to display it in the UI.</p>
<p>The workouts, the members, and the records are stored in different places in the database. So what we need here is a box (records) inside another box (workouts), right?</p>
<p>The URI for that endpoint will be <strong>/api/v1/workouts/:workoutId/records</strong>. This is a good practice to allow logical nesting of URL's. The URL itself doesn't necessarily have to mirror the database structure.</p>
<p>Let's start implementing that endpoint.</p>
<p>First, add a new table into your db.json called "members". Place it under "workouts".</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"workouts"</span>: [ ...
  ],
  <span class="hljs-attr">"members"</span>: [
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"12a410bc-849f-4e7e-bfc8-4ef283ee4b19"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Jason Miller"</span>,
      <span class="hljs-attr">"gender"</span>: <span class="hljs-string">"male"</span>,
      <span class="hljs-attr">"dateOfBirth"</span>: <span class="hljs-string">"23/04/1990"</span>,
      <span class="hljs-attr">"email"</span>: <span class="hljs-string">"jason@mail.com"</span>,
      <span class="hljs-attr">"password"</span>: <span class="hljs-string">"666349420ec497c1dc890c45179d44fb13220239325172af02d1fb6635922956"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"2b9130d4-47a7-4085-800e-0144f6a46059"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Tiffany Brookston"</span>,
      <span class="hljs-attr">"gender"</span>: <span class="hljs-string">"female"</span>,
      <span class="hljs-attr">"dateOfBirth"</span>: <span class="hljs-string">"09/06/1996"</span>,
      <span class="hljs-attr">"email"</span>: <span class="hljs-string">"tiffy@mail.com"</span>,
      <span class="hljs-attr">"password"</span>: <span class="hljs-string">"8a1ea5669b749354110dcba3fac5546c16e6d0f73a37f35a84f6b0d7b3c22fcc"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"11817fb1-03a1-4b4a-8d27-854ac893cf41"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Catrin Stevenson"</span>,
      <span class="hljs-attr">"gender"</span>: <span class="hljs-string">"female"</span>,
      <span class="hljs-attr">"dateOfBirth"</span>: <span class="hljs-string">"17/08/2001"</span>,
      <span class="hljs-attr">"email"</span>: <span class="hljs-string">"catrin@mail.com"</span>,
      <span class="hljs-attr">"password"</span>: <span class="hljs-string">"18eb2d6c5373c94c6d5d707650d02c3c06f33fac557c9cfb8cb1ee625a649ff3"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"6a89217b-7c28-4219-bd7f-af119c314159"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Greg Bronson"</span>,
      <span class="hljs-attr">"gender"</span>: <span class="hljs-string">"male"</span>,
      <span class="hljs-attr">"dateOfBirth"</span>: <span class="hljs-string">"08/04/1993"</span>,
      <span class="hljs-attr">"email"</span>: <span class="hljs-string">"greg@mail.com"</span>,
      <span class="hljs-attr">"password"</span>: <span class="hljs-string">"a6dcde7eceb689142f21a1e30b5fdb868ec4cd25d5537d67ac7e8c7816b0e862"</span>
    }
  ]
}
</code></pre>
<p>Before you start asking – yes, the passwords are hashed. 😉</p>
<p>After that, add some "records" under "members".</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"workouts"</span>: [ ...
  ],
  <span class="hljs-attr">"members"</span>: [ ...
  ],
  <span class="hljs-attr">"records"</span>: [
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"ad75d475-ac57-44f4-a02a-8f6def58ff56"</span>,
      <span class="hljs-attr">"workout"</span>: <span class="hljs-string">"4a3d9aaa-608c-49a7-a004-66305ad4ab50"</span>,
      <span class="hljs-attr">"record"</span>: <span class="hljs-string">"160 reps"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"0bff586f-2017-4526-9e52-fe3ea46d55ab"</span>,
      <span class="hljs-attr">"workout"</span>: <span class="hljs-string">"d8be2362-7b68-4ea4-a1f6-03f8bc4eede7"</span>,
      <span class="hljs-attr">"record"</span>: <span class="hljs-string">"7:23 minutes"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"365cc0bb-ba8f-41d3-bf82-83d041d38b82"</span>,
      <span class="hljs-attr">"workout"</span>: <span class="hljs-string">"a24d2618-01d1-4682-9288-8de1343e53c7"</span>,
      <span class="hljs-attr">"record"</span>: <span class="hljs-string">"358 reps"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"62251cfe-fdb6-4fa6-9a2d-c21be93ac78d"</span>,
      <span class="hljs-attr">"workout"</span>: <span class="hljs-string">"4a3d9aaa-608c-49a7-a004-66305ad4ab50"</span>,
      <span class="hljs-attr">"record"</span>: <span class="hljs-string">"145 reps"</span>
    }
  ],
}
</code></pre>
<p>To make sure you've got the same workouts like I do with the same id's, copy the workouts as well:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"workouts"</span>: [
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"61dbae02-c147-4e28-863c-db7bd402b2d6"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Tommy V"</span>,
      <span class="hljs-attr">"mode"</span>: <span class="hljs-string">"For Time"</span>,
      <span class="hljs-attr">"equipment"</span>: [
        <span class="hljs-string">"barbell"</span>,
        <span class="hljs-string">"rope"</span>
      ],
      <span class="hljs-attr">"exercises"</span>: [
        <span class="hljs-string">"21 thrusters"</span>,
        <span class="hljs-string">"12 rope climbs, 15 ft"</span>,
        <span class="hljs-string">"15 thrusters"</span>,
        <span class="hljs-string">"9 rope climbs, 15 ft"</span>,
        <span class="hljs-string">"9 thrusters"</span>,
        <span class="hljs-string">"6 rope climbs, 15 ft"</span>
      ],
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"4/20/2022, 2:21:56 PM"</span>,
      <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"4/20/2022, 2:21:56 PM"</span>,
      <span class="hljs-attr">"trainerTips"</span>: [
        <span class="hljs-string">"Split the 21 thrusters as needed"</span>,
        <span class="hljs-string">"Try to do the 9 and 6 thrusters unbroken"</span>,
        <span class="hljs-string">"RX Weights: 115lb/75lb"</span>
      ]
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"4a3d9aaa-608c-49a7-a004-66305ad4ab50"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Dead Push-Ups"</span>,
      <span class="hljs-attr">"mode"</span>: <span class="hljs-string">"AMRAP 10"</span>,
      <span class="hljs-attr">"equipment"</span>: [
        <span class="hljs-string">"barbell"</span>
      ],
      <span class="hljs-attr">"exercises"</span>: [
        <span class="hljs-string">"15 deadlifts"</span>,
        <span class="hljs-string">"15 hand-release push-ups"</span>
      ],
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"1/25/2022, 1:15:44 PM"</span>,
      <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"3/10/2022, 8:21:56 AM"</span>,
      <span class="hljs-attr">"trainerTips"</span>: [
        <span class="hljs-string">"Deadlifts are meant to be light and fast"</span>,
        <span class="hljs-string">"Try to aim for unbroken sets"</span>,
        <span class="hljs-string">"RX Weights: 135lb/95lb"</span>
      ]
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"d8be2362-7b68-4ea4-a1f6-03f8bc4eede7"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Heavy DT"</span>,
      <span class="hljs-attr">"mode"</span>: <span class="hljs-string">"5 Rounds For Time"</span>,
      <span class="hljs-attr">"equipment"</span>: [
        <span class="hljs-string">"barbell"</span>,
        <span class="hljs-string">"rope"</span>
      ],
      <span class="hljs-attr">"exercises"</span>: [
        <span class="hljs-string">"12 deadlifts"</span>,
        <span class="hljs-string">"9 hang power cleans"</span>,
        <span class="hljs-string">"6 push jerks"</span>
      ],
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"11/20/2021, 5:39:07 PM"</span>,
      <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"4/22/2022, 5:49:18 PM"</span>,
      <span class="hljs-attr">"trainerTips"</span>: [
        <span class="hljs-string">"Aim for unbroken push jerks"</span>,
        <span class="hljs-string">"The first three rounds might feel terrible, but stick to it"</span>,
        <span class="hljs-string">"RX Weights: 205lb/145lb"</span>
      ]
    },
    {
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Core Buster"</span>,
      <span class="hljs-attr">"mode"</span>: <span class="hljs-string">"AMRAP 20"</span>,
      <span class="hljs-attr">"equipment"</span>: [
        <span class="hljs-string">"rack"</span>,
        <span class="hljs-string">"barbell"</span>,
        <span class="hljs-string">"abmat"</span>
      ],
      <span class="hljs-attr">"exercises"</span>: [
        <span class="hljs-string">"15 toes to bars"</span>,
        <span class="hljs-string">"10 thrusters"</span>,
        <span class="hljs-string">"30 abmat sit-ups"</span>
      ],
      <span class="hljs-attr">"trainerTips"</span>: [
        <span class="hljs-string">"Split your toes to bars in two sets maximum"</span>,
        <span class="hljs-string">"Go unbroken on the thrusters"</span>,
        <span class="hljs-string">"Take the abmat sit-ups as a chance to normalize your breath"</span>
      ],
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"a24d2618-01d1-4682-9288-8de1343e53c7"</span>,
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"4/22/2022, 5:50:17 PM"</span>,
      <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"4/22/2022, 5:50:17 PM"</span>
    }
  ],
  <span class="hljs-attr">"members"</span>: [ ...
  ],
  <span class="hljs-attr">"records"</span>: [ ...
  ]
}
</code></pre>
<p>Okay, let's take a few minutes to think about our implementation. </p>
<p>We've got a resource called "workouts" on the one side and another called "records" on the other side. </p>
<p>To move on in our architecture it would be advisable to create another controller, another service, and another collection of database methods that are responsible for records. </p>
<p>Chances are high that have we to implement CRUD endpoints for the records as well, because records should be added, updated or deleted in the future as well. But this won't be the primary task for now.</p>
<p>We'll also need a record router to catch the specific requests for the records, but we don't need it right now. This could be a great chance for you to implement the CRUD operations for the records with their own routes and train a bit.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create records controller </span>
touch src/controllers/recordController.js 

<span class="hljs-comment"># Create records service </span>
touch src/services/recordService.js 

<span class="hljs-comment"># Create records database methods </span>
touch src/database/Record.js
</code></pre>
<p>That was easy. Let's move on and start backwards with implementing our database methods.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/database/Record.js</span>
<span class="hljs-keyword">const</span> DB = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./db.json"</span>);

<span class="hljs-keyword">const</span> getRecordForWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> record = DB.records.filter(<span class="hljs-function">(<span class="hljs-params">record</span>) =&gt;</span> record.workout === workoutId);
    <span class="hljs-keyword">if</span> (!record) {
      <span class="hljs-keyword">throw</span> {
        <span class="hljs-attr">status</span>: <span class="hljs-number">400</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">`Can't find workout with the id '<span class="hljs-subst">${workoutId}</span>'`</span>,
      };
    }
    <span class="hljs-keyword">return</span> record;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> { <span class="hljs-attr">status</span>: error?.status || <span class="hljs-number">500</span>, <span class="hljs-attr">message</span>: error?.message || error };
  }
};
<span class="hljs-built_in">module</span>.exports = { getRecordForWorkout };
</code></pre>
<p>Pretty straightforward, right? We filter all the records that are related to the workout id out of the query parameter.</p>
<p>The next one is our record service:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/services/recordService.js</span>
<span class="hljs-keyword">const</span> Record = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../database/Record"</span>);

<span class="hljs-keyword">const</span> getRecordForWorkout = <span class="hljs-function">(<span class="hljs-params">workoutId</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> record = Record.getRecordForWorkout(workoutId);
    <span class="hljs-keyword">return</span> record;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> error;
  }
};
<span class="hljs-built_in">module</span>.exports = { getRecordForWorkout };
</code></pre>
<p>Again, nothing new here.</p>
<p>Now we're able to create a new route in our workout router and direct the request to our record service.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/v1/routes/workoutRoutes.js</span>
<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> workoutController = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../../controllers/workoutController"</span>);
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> recordController = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../../controllers/recordController"</span>);

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

router.get(<span class="hljs-string">"/"</span>, workoutController.getAllWorkouts);

router.get(<span class="hljs-string">"/:workoutId"</span>, workoutController.getOneWorkout);

<span class="hljs-comment">// *** ADD ***</span>
router.get(<span class="hljs-string">"/:workoutId/records"</span>, recordController.getRecordForWorkout);

router.post(<span class="hljs-string">"/"</span>, workoutController.createNewWorkout);

router.patch(<span class="hljs-string">"/:workoutId"</span>, workoutController.updateOneWorkout);

router.delete(<span class="hljs-string">"/:workoutId"</span>, workoutController.deleteOneWorkout);

<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<p>Great! Let's test things out in our browser.</p>
<p>First, we fetch all workouts to get a workout id.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-15.36.48.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's see if we can fetch all records for that:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-15.36.32.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, logical nesting makes sense when you have resources that can be tied together. Theoretically you can nest it how deep you want, but the rule of thumb here is to go three levels deep at a maximum.</p>
<p>If you want to nest deeper than that, you could do a little tweak inside your database records. I'll show you a little example.</p>
<p>Imagine the frontend also needs an endpoint to get information about which member exactly holds the current record and wants to receive metadata about them.</p>
<p>Of course we could implement the following URI:</p>
<pre><code class="lang-javascript">GET /api/v1/workouts/:workoutId/records/members/:memberId
</code></pre>
<p>The endpoint now becomes less manageable the more nesting we add to it. Therefore it's a good practice to store the URI to receive information about a member directly into the record.</p>
<p>Consider the following inside the database:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"workouts"</span>: [ ...
  ],
  <span class="hljs-attr">"members"</span>: [ ...
  ],
  <span class="hljs-attr">"records"</span>: [ ... {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"ad75d475-ac57-44f4-a02a-8f6def58ff56"</span>,
      <span class="hljs-attr">"workout"</span>: <span class="hljs-string">"4a3d9aaa-608c-49a7-a004-66305ad4ab50"</span>,
      <span class="hljs-attr">"record"</span>: <span class="hljs-string">"160 reps"</span>,
      <span class="hljs-attr">"memberId"</span>: <span class="hljs-string">"11817fb1-03a1-4b4a-8d27-854ac893cf41"</span>,
      <span class="hljs-attr">"member"</span>: <span class="hljs-string">"/members/:memberId"</span>
    },
  ]
}
</code></pre>
<p>As you can see, we've added the two properties "memberId" and "member" to our records inside the database. This has the huge advantage that we don't have to nest deeper our existing endpoint.</p>
<p>The frontend just needs to call  <strong>GET /api/v1/workouts/:workoutId/records</strong> and receives automatically all records that are connected with this workout. </p>
<p>On top of that it gets the member id and the endpoint to fetch information about that member. So, we avoided the deeper nesting of our endpoint.</p>
<p>Of course, this only works if we can handle requests to "/members/:memberId" 😁 This sounds like a great training opportunity for you to implement this situation!</p>
<h3 id="heading-integrate-filtering-sorting-amp-pagination">Integrate filtering, sorting &amp; pagination</h3>
<p>Right now we're able to do quite a few operations with our API. That's great progress, but there's more.</p>
<p>During the last sections we focused on improving our developer experience and how our API can be interacted with. But the overall performance of our API is another key factor we should work on.</p>
<p>That's why integrating filtering, sorting, and pagination is also an essential factor on my list.</p>
<p>Imagine we've got 2,000 workouts, 450 records, and 500 members stored in our DB. When calling our endpoint to get all workouts we don't want to send all 2,000 workouts at once. This will be a very slow response of course, or it'll bring our systems down (maybe with 200,000 😁).</p>
<p>That's the reason why filtering and pagination are important. Filtering, as the name already says, is useful because it allows us to get specific data out of our whole collection. For example all workouts that have the mode "For Time".</p>
<p>Pagination is another mechanism to split our whole collection of workouts into multiple "pages" where each page only consists of twenty workouts, for example. This technique helps us to make sure that we don't send more than twenty workouts at the same time with our response to the client.</p>
<p>Sorting can be a complex task. So it's more effective to do it in our API and to send the sorted data to the client.</p>
<p>Let's start with integrating some filtering mechanism into our API. We will upgrade our endpoint that sends all workouts by accepting filter parameters. Normally in a GET request we add the filter criteria as a query parameter.</p>
<p>Our new URI will look like this, when we'd like to get only the workouts that are in the mode of "AMRAP" (<strong>A</strong>s <strong>M</strong>any <strong>R</strong>ounds <strong>A</strong>s <strong>P</strong>ossible): <strong>/api/v1/workouts?mode=amrap.</strong></p>
<p>To make this more fun we need to add some more workouts. Paste these workouts into your "workouts" collection inside db.json:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Jumping (Not) Made Easy"</span>,
  <span class="hljs-attr">"mode"</span>: <span class="hljs-string">"AMRAP 12"</span>,
  <span class="hljs-attr">"equipment"</span>: [
    <span class="hljs-string">"jump rope"</span>
  ],
  <span class="hljs-attr">"exercises"</span>: [
    <span class="hljs-string">"10 burpees"</span>,
    <span class="hljs-string">"25 double-unders"</span>
  ],
  <span class="hljs-attr">"trainerTips"</span>: [
    <span class="hljs-string">"Scale to do 50 single-unders, if double-unders are too difficult"</span>
  ],
  <span class="hljs-attr">"id"</span>: <span class="hljs-string">"8f8318f8-b869-4e9d-bb78-88010193563a"</span>,
  <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"4/25/2022, 2:45:28 PM"</span>,
  <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"4/25/2022, 2:45:28 PM"</span>
},
{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Burpee Meters"</span>,
  <span class="hljs-attr">"mode"</span>: <span class="hljs-string">"3 Rounds For Time"</span>,
  <span class="hljs-attr">"equipment"</span>: [
    <span class="hljs-string">"Row Erg"</span>
  ],
  <span class="hljs-attr">"exercises"</span>: [
    <span class="hljs-string">"Row 500 meters"</span>,
    <span class="hljs-string">"21 burpees"</span>,
    <span class="hljs-string">"Run 400 meters"</span>,
    <span class="hljs-string">"Rest 3 minutes"</span>
  ],
  <span class="hljs-attr">"trainerTips"</span>: [
    <span class="hljs-string">"Go hard"</span>,
    <span class="hljs-string">"Note your time after the first run"</span>,
    <span class="hljs-string">"Try to hold your pace"</span>
  ],
  <span class="hljs-attr">"id"</span>: <span class="hljs-string">"0a5948af-5185-4266-8c4b-818889657e9d"</span>,
  <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"4/25/2022, 2:48:53 PM"</span>,
  <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"4/25/2022, 2:48:53 PM"</span>
},
{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Dumbbell Rower"</span>,
  <span class="hljs-attr">"mode"</span>: <span class="hljs-string">"AMRAP 15"</span>,
  <span class="hljs-attr">"equipment"</span>: [
    <span class="hljs-string">"Dumbbell"</span>
  ],
  <span class="hljs-attr">"exercises"</span>: [
    <span class="hljs-string">"15 dumbbell rows, left arm"</span>,
    <span class="hljs-string">"15 dumbbell rows, right arm"</span>,
    <span class="hljs-string">"50-ft handstand walk"</span>
  ],
  <span class="hljs-attr">"trainerTips"</span>: [
    <span class="hljs-string">"RX weights for women: 35-lb"</span>,
    <span class="hljs-string">"RX weights for men: 50-lb"</span>
  ],
  <span class="hljs-attr">"id"</span>: <span class="hljs-string">"3dc53bc8-27b8-4773-b85d-89f0a354d437"</span>,
  <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"4/25/2022, 2:56:03 PM"</span>,
  <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"4/25/2022, 2:56:03 PM"</span>
}
</code></pre>
<p>After that we have to accept and handle query parameters. Our workout controller will be the right place to start:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/controllers/workoutController.js</span>
...

const getAllWorkouts = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// *** ADD ***</span>
  <span class="hljs-keyword">const</span> { mode } = req.query;
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// *** ADD ***</span>
    <span class="hljs-keyword">const</span> allWorkouts = workoutService.getAllWorkouts({ mode });
    res.send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"OK"</span>, <span class="hljs-attr">data</span>: allWorkouts });
  } <span class="hljs-keyword">catch</span> (error) {
    res
      .status(error?.status || <span class="hljs-number">500</span>)
      .send({ <span class="hljs-attr">status</span>: <span class="hljs-string">"FAILED"</span>, <span class="hljs-attr">data</span>: { <span class="hljs-attr">error</span>: error?.message || error } });
  }
};

...
</code></pre>
<p>We're extracting "mode" from the req.query object and defining a parameter of workoutService.getAllWorkouts. This will be an object that consists of our filter parameters. </p>
<p>I'm using the shorthand syntax here, to create a new key called "mode" inside the object with the value of whatever is in "req.query.mode". This could be either a truthy value or undefined if there isn't a query parameter called "mode". We can extend this object the more filter parameters we'd like to accept.</p>
<p>In our workout service, pass it to your database method:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/services/workoutService.js</span>
...

const getAllWorkouts = <span class="hljs-function">(<span class="hljs-params">filterParams</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// *** ADD ***</span>
    <span class="hljs-keyword">const</span> allWorkouts = Workout.getAllWorkouts(filterParams);
    <span class="hljs-keyword">return</span> allWorkouts;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> error;
  }
};

...
</code></pre>
<p>Now we can use it in our database method and apply the filtering:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/database/Workout.js</span>
...

const getAllWorkouts = <span class="hljs-function">(<span class="hljs-params">filterParams</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">let</span> workouts = DB.workouts;
    <span class="hljs-keyword">if</span> (filterParams.mode) {
      <span class="hljs-keyword">return</span> DB.workouts.filter(<span class="hljs-function">(<span class="hljs-params">workout</span>) =&gt;</span>
        workout.mode.toLowerCase().includes(filterParams.mode)
      );
    }
    <span class="hljs-comment">// Other if-statements will go here for different parameters</span>
    <span class="hljs-keyword">return</span> workouts;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> { <span class="hljs-attr">status</span>: <span class="hljs-number">500</span>, <span class="hljs-attr">message</span>: error };
  }
};

...
</code></pre>
<p>Pretty straightforward, right? All we do here is check if we actually have a truthy value for the key "mode" inside our "filterParams". If this is true, we filter all those workouts that have got the same "mode". If this is not true, then there is no query parameter called "mode" and we return all workouts because we don't need to filter.</p>
<p>We defined "workouts" here as a "let" variable because when adding more if-statements for different filters we can overwrite "workouts" and chain the filters.</p>
<p>Inside your browser you can visit localhost:3000/api/v1/workouts?mode=amrap and you'll receive all "AMRAP" workouts that are stored:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-15.48.57.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you leave the query parameter out, you should get all workouts like before. You can try it further with adding "for%20time" as the value for the "mode" parameter (remember --&gt; "%20" means "whitespace") and you should receive all workouts that have the mode "For Time" if there are any stored. </p>
<p>When typing in a value that is not stored, that you should receive an empty array.</p>
<p>The parameters for sorting and pagination follow the same philosophy. Let's look at a few features we could possibly implement:</p>
<ul>
<li>Receive all workouts that require a barbell: <strong>/api/v1/workouts?equipment=barbell</strong></li>
<li>Get only 5 workouts: <strong>/api/v1/workouts?length=5</strong></li>
<li>When using pagination, receive the second page: <strong>/api/v1/workouts?page=2</strong></li>
<li>Sort the workouts in the response in descending order by their creation date: <strong>/api/v1/workouts?sort=-createdAt</strong></li>
<li>You can also combine the parameters, to get the last 10 updated workouts for example: <strong>/api/v1/workouts?sort=-updatedAt&amp;length=10</strong></li>
</ul>
<h3 id="heading-use-data-caching-for-performance-improvements">Use data caching for performance improvements</h3>
<p>Using a data cache is also a great practice to improve the overall experience and performance of our API.</p>
<p>It makes a lot of sense to use a cache to serve data from, when the data is an often requested resource or/and querying that data from the database is a heavy lift and may take multiple seconds.</p>
<p>You can store this type of data inside your cache and serve it from there instead of going to the database every time to query the data.</p>
<p>One important thing you have to keep in mind when serving data from a cache is that this data can become outdated. So you have to make sure that the data inside the cache is always up to date.</p>
<p>There are many different solutions out there. One appropriate example is to use <a target="_blank" href="https://www.npmjs.com/package/redis">redis</a> or the express middleware <a target="_blank" href="https://www.npmjs.com/package/apicache">apicache</a>.</p>
<p>I'd like to go with apicache, but if you want to use Redis, I can highly recommend that you check out their great <a target="_blank" href="https://docs.redis.com/latest/rs/references/client_references/client_nodejs/">docs</a>.</p>
<p>Let's think a second about a scenario in our API where a cache would make sense. I think requesting to receive all workouts would effectively be served from our cache.</p>
<p>First, let's install our middleware:</p>
<pre><code class="lang-bash">npm i apicache
</code></pre>
<p>Now, we have to import it into our workout router and configure it.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/v1/routes/workoutRoutes.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> apicache = <span class="hljs-built_in">require</span>(<span class="hljs-string">"apicache"</span>);
<span class="hljs-keyword">const</span> workoutController = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../../controllers/workoutController"</span>);
<span class="hljs-keyword">const</span> recordController = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../../controllers/recordController"</span>);

<span class="hljs-keyword">const</span> router = express.Router();
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> cache = apicache.middleware;

<span class="hljs-comment">// *** ADD ***</span>
router.get(<span class="hljs-string">"/"</span>, cache(<span class="hljs-string">"2 minutes"</span>), workoutController.getAllWorkouts);

router.get(<span class="hljs-string">"/:workoutId"</span>, workoutController.getOneWorkout);

router.get(<span class="hljs-string">"/:workoutId/records"</span>, recordController.getRecordForWorkout);

router.post(<span class="hljs-string">"/"</span>, workoutController.createNewWorkout);

router.patch(<span class="hljs-string">"/:workoutId"</span>, workoutController.updateOneWorkout);

router.delete(<span class="hljs-string">"/:workoutId"</span>, workoutController.deleteOneWorkout);

<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<p>Getting started is pretty straightforward, right? We can define a new cache by calling <strong>apicache.middleware</strong> and use it as a middleware inside our get route. You just have to put it as a parameter between the actual path and our workout controller.</p>
<p>Inside there you can define how long your data should be cached. For the sake of this tutorial I've chosen two minutes. The time depends on how fast or how often your data inside your cache changes.</p>
<p>Let's test things out!</p>
<p>Inside Postman or another HTTP client of your choice, define a new request that gets all workouts. I've done it inside the browser until now, but I'd like to visualize the response times better for you. That's the reason why I'm requesting the resource via Postman right now.</p>
<p>Let's call our request for the first time:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-26-um-15.36.46-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see it took our API 22.93 ms to respond. Once our cache is empty again (after two minutes) it has to be filled again. This happens with our first request.</p>
<p>So in the case above, the data was NOT served from our cache. It took the "regular" way from the database and filled our cache.</p>
<p>Now, with our second request we receive a shorter response time, because it was directly served from the cache:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-26-um-15.36.59-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We were able to serve three times faster than in our previous request! All thanks to our cache.</p>
<p>In our example we've cached just one route, but you can also cache all routes by implementing it like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/index.js</span>
<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> bodyParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"body-parser"</span>);
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> apicache = <span class="hljs-built_in">require</span>(<span class="hljs-string">"apicache"</span>);
<span class="hljs-keyword">const</span> v1WorkoutRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./v1/routes/workoutRoutes"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> cache = apicache.middleware;
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3000</span>;

app.use(bodyParser.json());
<span class="hljs-comment">// *** ADD ***</span>
app.use(cache(<span class="hljs-string">"2 minutes"</span>));
app.use(<span class="hljs-string">"/api/v1/workouts"</span>, v1WorkoutRouter);

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`API is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>There's one <strong>important</strong> thing I'd like to note here when it comes to caching. While it seems to solve a lot of problems for you, it also can bring some problems into your application.</p>
<p>A few things you have to be aware of when using a cache:</p>
<ul>
<li>you always have to make sure that the data inside the cache is up to date because you don't want to serve outdated data </li>
<li>while the first request is being processed and the cache is about to be filled and more requests are coming in, you have to decide if you delay those other requests and serve the data from the cache or if they also receive data straight from the database like the first request</li>
<li>it's another component inside your infrastructure if you're choosing a distributed cache like Redis (so you have to ask yourself if it really makes sense to use it)</li>
</ul>
<p>Here's how to do it usually:</p>
<p>I like to start as simple and as clean as possible with everything I build. The same goes for API's. </p>
<p>When I start building an API and there are no particular reasons to use a cache straight away, I leave it out and see what happens over time. When reasons arise to use a cache, I can implement it then.</p>
<h3 id="heading-good-security-practices">Good security practices</h3>
<p>Wow! This has been quite a great journey so far. We've touched on many important points and extended our API accordingly.</p>
<p>We've spoken about best practices to increase the usability and performance of our API. Security is also a key factor for API's. You can build the best API, but when it is a vulnerable piece of software running on a server it becomes useless and dangerous.</p>
<p>The first and absolute must have is to use SSL/TLS because it's a standard nowadays for communications on the internet. It's even more important for API's where private data is send between the client and our API.</p>
<p>If you've got resources that should only be available to authenticated users, you should protect them with an authentication check. </p>
<p>In Express, for example, you can implement it as a middleware like we did with our cache for specific routes and check first if the request is authenticated before it accesses a resource.</p>
<p>There may be also resources or interactions with our API we don't want to allow every user to request. Then you should come up with a role system for your users. So you have to add another checking logic to that route and validate if the user has the privilege to access this resource.</p>
<p>User roles would also make sense in our use case when we only want specific users (like coaches) to create, update, and delete our workouts and records. Reading can be for everyone (also "regular" members).</p>
<p>This can be handled inside another middleware we use for the routes we'd like to protect. For example our POST request to /api/v1/workouts for creating a new workout. </p>
<p>Inside the first middleware we'll check if the user is authenticated. If this is true, we'll go to the next middleware, that would be the one for checking the user's role. If the user has the appropriate role for accessing this resource the request is be passed to the corresponding controller.</p>
<p>Inside the route handler it would look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/v1/routes/workoutRoutes.js</span>
...

<span class="hljs-comment">// Custom made middlewares</span>
<span class="hljs-keyword">const</span> authenticate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../../middlewares/authenticate"</span>);
<span class="hljs-keyword">const</span> authorize = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../../middlewares/authorize"</span>);

router.post(<span class="hljs-string">"/"</span>, authenticate, authorize, workoutController.createNewWorkout);

...
</code></pre>
<p>To read further and get some more best practices on that topic, I can suggest reading <a target="_blank" href="https://restfulapi.net/security-essentials/">this article</a>.</p>
<h3 id="heading-document-your-api-properly">Document your API properly</h3>
<p>I know that documentation is definitely not a favorite task of developers, but it's a necessary thing to do. Especially when it comes to an API.</p>
<p>Some people say:</p>
<blockquote>
<p>"An API is just as good as it's documentation"</p>
</blockquote>
<p>I think there's a lot truth in this statement because if an API is not well documented it can't be used properly and therefore becomes useless. The documentation helps make developers' lives a lot easier, too.</p>
<p>Always remember that the documentation is usually the first interaction consumers have with your API. The faster users can understand the documentation, the faster they can use the API.</p>
<p>So, it's our job to implement a good and precise documentation. There are some great tools out there that make our lives easier.</p>
<p>Like in other fields of computer science there's also some sort of standard for documenting API's called <a target="_blank" href="https://swagger.io/specification/">OpenAPI Specification</a>.</p>
<p>Let's see how we can create some documentation that justifies that specification. We'll use the <a target="_blank" href="https://www.npmjs.com/package/swagger-ui-express">swagger-ui-express</a> and <a target="_blank" href="https://www.npmjs.com/package/swagger-jsdoc">swagger-jsdoc</a> packages to accomplish this. You'll be amazed how awesome this is in a second!</p>
<p>First, we setup our bare structure for our documentation. Because we've planned to have different versions of our API, the docs will be a bit different, too. That's the reason why I'd like to define our swagger file to spin up our documentation inside the corresponding version folder.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install required npm packages </span>
npm i swagger-jsdoc swagger-ui-express 

<span class="hljs-comment"># Create a new file to setup the swagger docs </span>
touch src/v1/swagger.js
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/v1/swagger.js</span>
<span class="hljs-keyword">const</span> swaggerJSDoc = <span class="hljs-built_in">require</span>(<span class="hljs-string">"swagger-jsdoc"</span>);
<span class="hljs-keyword">const</span> swaggerUi = <span class="hljs-built_in">require</span>(<span class="hljs-string">"swagger-ui-express"</span>);

<span class="hljs-comment">// Basic Meta Informations about our API</span>
<span class="hljs-keyword">const</span> options = {
  <span class="hljs-attr">definition</span>: {
    <span class="hljs-attr">openapi</span>: <span class="hljs-string">"3.0.0"</span>,
    <span class="hljs-attr">info</span>: { <span class="hljs-attr">title</span>: <span class="hljs-string">"Crossfit WOD API"</span>, <span class="hljs-attr">version</span>: <span class="hljs-string">"1.0.0"</span> },
  },
  <span class="hljs-attr">apis</span>: [<span class="hljs-string">"./src/v1/routes/workoutRoutes.js"</span>, <span class="hljs-string">"./src/database/Workout.js"</span>],
};

<span class="hljs-comment">// Docs in JSON format</span>
<span class="hljs-keyword">const</span> swaggerSpec = swaggerJSDoc(options);

<span class="hljs-comment">// Function to setup our docs</span>
<span class="hljs-keyword">const</span> swaggerDocs = <span class="hljs-function">(<span class="hljs-params">app, port</span>) =&gt;</span> {
  <span class="hljs-comment">// Route-Handler to visit our docs</span>
  app.use(<span class="hljs-string">"/api/v1/docs"</span>, swaggerUi.serve, swaggerUi.setup(swaggerSpec));
  <span class="hljs-comment">// Make our docs in JSON format available</span>
  app.get(<span class="hljs-string">"/api/v1/docs.json"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.setHeader(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>);
    res.send(swaggerSpec);
  });
  <span class="hljs-built_in">console</span>.log(
    <span class="hljs-string">`Version 1 Docs are available on http://localhost:<span class="hljs-subst">${port}</span>/api/v1/docs`</span>
  );
};

<span class="hljs-built_in">module</span>.exports = { swaggerDocs };
</code></pre>
<p>So, the setup is pretty straightforward. We've defined some basic metadata of our API, created the docs in JSON format, and created a function that makes our docs available. </p>
<p>To control if everything is up and running, we log a simple message to the console where we can find our docs.</p>
<p>This will be the function we'll use in our root file, where we created the Express server to make sure that the docs are booted up as well.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/index.js</span>
<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> bodyParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"body-parser"</span>);
<span class="hljs-keyword">const</span> v1WorkoutRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./v1/routes/workoutRoutes"</span>);
<span class="hljs-comment">// *** ADD ***</span>
<span class="hljs-keyword">const</span> { <span class="hljs-attr">swaggerDocs</span>: V1SwaggerDocs } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./v1/swagger"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3000</span>;

app.use(bodyParser.json());
app.use(<span class="hljs-string">"/api/v1/workouts"</span>, v1WorkoutRouter);

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`API is listening on port <span class="hljs-subst">${PORT}</span>`</span>);
  <span class="hljs-comment">/// *** ADD ***</span>
  V1SwaggerDocs(app, PORT);
});
</code></pre>
<p>Now you should see inside your terminal where your development server is running:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-28-um-20.23.51-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And when you visit localhost:3000/api/v1/docs, you should see our docs page already:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-28-um-20.25.00-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>I'm amazed every time again how nicely this works. Now, the basic structure is setup and we can start to implement the docs for our endpoints. Let's go!</p>
<p>When you take a look at <strong>options.apis</strong> in our swagger.js file, you will see that we've included the path to our workout routes and to the workout file inside our database folder. This is the most important thing in the setup that will make the whole magic happen.</p>
<p>Having those files defined inside our swagger options will allow us to use comments that are referencing OpenAPI and having syntax like in yaml files, that are necessary to setup our docs.</p>
<p>Now we're ready to create docs for our first endpoint! Let's jump right into it.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/v1/routes/workoutRoutes.js</span>
...

<span class="hljs-comment">/**
 * <span class="hljs-doctag">@openapi</span>
 * /api/v1/workouts:
 *   get:
 *     tags:
 *       - Workouts
 *     responses:
 *       200:
 *         description: OK
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status:
 *                   type: string
 *                   example: OK
 *                 data:
 *                   type: array 
 *                   items: 
 *                     type: object
 */</span>
router.get(<span class="hljs-string">"/"</span>, cache(<span class="hljs-string">"2 minutes"</span>), workoutController.getAllWorkouts);

...
</code></pre>
<p>This is basically the whole magic to add an endpoint to our swagger docs. You can look up all the specifications to describe an endpoint in their <a target="_blank" href="https://swagger.io/docs/specification/about/">great docs</a>.</p>
<p>When you reload your docs page, you should see the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-07.21.51-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This should look very familiar if you've already worked with API's that have OpenAPI documentation. This is the view where all our endpoints will be listed and you can extend each one to get more information about it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-07.41.46-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>When you take a close look at our response, you'll see that we haven't defined the correct return value because we're just saying that our "data" property will be an array of empty objects.</p>
<p>That's where schemas come into play.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/databse/Workout.js</span>
...

<span class="hljs-comment">/**
 * <span class="hljs-doctag">@openapi</span>
 * components:
 *   schemas:
 *     Workout:
 *       type: object
 *       properties:
 *         id: 
 *           type: string
 *           example: 61dbae02-c147-4e28-863c-db7bd402b2d6
 *         name: 
 *           type: string
 *           example: Tommy V  
 *         mode:
 *           type: string
 *           example: For Time
 *         equipment:
 *           type: array
 *           items:
 *             type: string
 *           example: ["barbell", "rope"]
 *         exercises:
 *           type: array
 *           items:
 *             type: string
 *           example: ["21 thrusters", "12 rope climbs, 15 ft", "15 thrusters", "9 rope climbs, 15 ft", "9 thrusters", "6 rope climbs, 15 ft"]
 *         createdAt:
 *           type: string
 *           example: 4/20/2022, 2:21:56 PM
 *         updatedAt: 
 *           type: string
 *           example: 4/20/2022, 2:21:56 PM
 *         trainerTips:
 *           type: array
 *           items:
 *             type: string
 *           example: ["Split the 21 thrusters as needed", "Try to do the 9 and 6 thrusters unbroken", "RX Weights: 115lb/75lb"]
 */</span>

...
</code></pre>
<p>In the example above we've created our first schema. Typically this definition will be inside your schema or model file where you've defined your database models.</p>
<p>As you can see it's also pretty straightforward. We've defined all the properties that make up a workout including the type and an example.</p>
<p>You can visit our docs page again and we'll receive another section holding our schemas.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-07.29.49-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This schema can be referenced now in our response of our endpoint.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/v1/routes/workoutRoutes.js</span>
...

<span class="hljs-comment">/**
 * <span class="hljs-doctag">@openapi</span>
 * /api/v1/workouts:
 *   get:
 *     tags:
 *       - Workouts
 *     responses:
 *       200:
 *         description: OK
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status:
 *                   type: string
 *                   example: OK
 *                 data:
 *                   type: array 
 *                   items: 
 *                     $ref: "#/components/schemas/Workout"
 */</span>
router.get(<span class="hljs-string">"/"</span>, cache(<span class="hljs-string">"2 minutes"</span>), workoutController.getAllWorkouts);

...
</code></pre>
<p>Take close look at the bottom of our comment under "items". We're using "$ref" to create a reference and are referencing the path to our schema we've defined inside our workout file.</p>
<p>Now we're able to show a full Workout in our response.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-07.44.12-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Pretty cool, right? You might think "typing these comments out by hand can be a tedious task". </p>
<p>This might be true, but think of this way. Those comments that are inside your codebase are also a great documentation for yourself as the API developer, too. You don't have to visit the docs all the time when you want to know the documentation of a specific endpoint. You can just look it up at one place inside your source code. </p>
<p>Documenting endpoints also helps you to understand them better and "forces" you to think of anything you might have forgotten to implement.</p>
<p>As you can see I've forgotten something indeed. The possible error responses and query parameters are still missing!</p>
<p>Let's fix that:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In src/v1/routes/workoutRoutes.js</span>
...

<span class="hljs-comment">/**
 * <span class="hljs-doctag">@openapi</span>
 * /api/v1/workouts:
 *   get:
 *     tags:
 *       - Workouts
 *     parameters:
 *       - in: query
 *         name: mode
 *         schema:
 *           type: string
 *         description: The mode of a workout
 *     responses:
 *       200:
 *         description: OK
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status:
 *                   type: string
 *                   example: OK
 *                 data:
 *                   type: array 
 *                   items: 
 *                     $ref: "#/components/schemas/Workout"
 *       5XX:
 *         description: FAILED
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status: 
 *                   type: string
 *                   example: FAILED
 *                 data:
 *                   type: object
 *                   properties:
 *                     error:
 *                       type: string 
 *                       example: "Some error message"
 */</span>
router.get(<span class="hljs-string">"/"</span>, cache(<span class="hljs-string">"2 minutes"</span>),  workoutController.getAllWorkouts);

...
</code></pre>
<p>When you look at the top of our comment under "tags", you can see that I've added another key called "parameters", where I've defined our query parameter for filtering.</p>
<p>Our docs are now displaying it properly:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-08.03.00-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And to document a possible error case we're only throwing a 5XX error at this point. So under "responses" you can see that I've also defined another documentation for that.</p>
<p>On our docs page it looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-08.04.44-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Amazing! We've just created the full documentation for one endpoint. I'd highly recommend that you implement the rest of the endpoints on your own to get your own hands dirty with it. You'll learn a lot in the process!</p>
<p>As you might have seen, documenting your API must not always be a headache. I think the tools I introduced you to reduce your overall effort, and setting it all up is pretty straightforward.</p>
<p>So we can concentrate on the important thing, the documentation itself. In my opinion, the documentation of swagger/OpenAPI is very good and there are a lot of great examples out there on the internet.</p>
<p>Not having a documentation because of too much "extra" work shouldn't be reason anymore.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Puuh, that was quite a fun ride. I really enjoyed writing this article for you and learned a lot as well.</p>
<p>There might be best practices that are important while others might not seem to apply to your current situation. That's fine, because as I've said earlier, it's the responsibility of every engineer to pick out the best practices that can be applied to their current situation.</p>
<p>I tried my best to merge all those best practices I've made so far together while building our own API along the way. It made this a lot of fun for me!</p>
<p>I'd love to receive feedback of any kind. If there's anything you'd like to tell me (good or bad), don't hesitate to reach out:</p>
<p>Here's <a target="_blank" href="https://www.instagram.com/jean_marc.dev/">my Instagram</a> (you can also follow my journey of being a software developer)</p>
<p>See you next time!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Multiplayer Tabletop Game Simulator with Vue, Phaser, Node, Express, and Socket.IO ]]>
                </title>
                <description>
                    <![CDATA[ By M. S. Farzan Putting together all of the pieces of a full stack JavaScript application can be a complex endeavor.   In this tutorial, we're going to build a multiplayer tabletop game simulator using Vue, Phaser, Node/Express, and Socket.IO to lear... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-multiplayer-tabletop-game-simulator/</link>
                <guid isPermaLink="false">66d851eba2a6d73be8613877</guid>
                
                    <category>
                        <![CDATA[ ES6 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GameDev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ phaser 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SocketIO ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 13 Jul 2020 23:31:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/07/How-to-Tabletop-Game-Simulator---Thumb.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By M. S. Farzan</p>
<p>Putting together all of the pieces of a full stack JavaScript application can be a complex endeavor.  </p>
<p>In this tutorial, we're going to build a multiplayer tabletop game simulator using <a target="_blank" href="https://vuejs.org/">Vue</a>, <a target="_blank" href="http://phaser.io/">Phaser</a>, <a target="_blank" href="https://nodejs.org/">Node</a>/<a target="_blank" href="https://expressjs.com/">Express</a>, and <a target="_blank" href="https://socket.io/">Socket.IO</a> to learn several concepts that will be useful in any full stack app.</p>
<p>You can follow along with this video tutorial as well (1 hour 16 minute watch):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/laNi0fdF_DU" 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>
<p>All of the project files for this tutorial are available on <a target="_blank" href="https://github.com/sominator/tabletop-project">GitHub</a>.</p>
<h2 id="heading-project-overview">Project Overview</h2>
<p>Our project will feature a Phaser game instance that will allow us to create tokens and cards on screen, and move them around on a digital game board.</p>
<p>The Phaser instance will be wrapped in a Vue component that will handle things like multiplayer chat and commands.  Together, Phaser and Vue will comprise our front end (referred to from here on as the "client"), and we'll use Socket.IO to communicate with other players and tie together the front and back ends of our app.</p>
<p>The back end (referred to from here on as the "server") will be a simple Express server that receives Socket.IO events from the client and acts accordingly.  The whole application will run on Node as its runtime.</p>
<p>You don't need to be an expert in any of the above frameworks to complete this project, but it would be a good idea to have a solid foundation in basic JavaScript and HTML/CSS before trying to tackle the specifics. You can also follow along with my series on <a target="_blank" href="https://www.freecodecamp.org/news/learn-javascript-by-making-digital-tabletop-games-and-web-apps/">Learning JavaScript by Making Digital Tabletop Games and Web Apps</a>.  </p>
<p>You'll also want to make sure that you have Node and <a target="_blank" href="https://github.com/">Git</a> installed, along with your favorite code editor and a command line interface (you can follow my tutorial on setting up an IDE <a target="_blank" href="https://www.freecodecamp.org/news/how-to-set-up-an-integrated-development-environment-ide/">here</a> if you need help).</p>
<p>Let's get started!</p>
<h2 id="heading-part-1-client-basics">Part 1: Client Basics</h2>
<p>We'll begin building our client by installing the <a target="_blank" href="https://cli.vuejs.org/">Vue CLI</a>, which will help us with some tooling and allow us to make changes to our files without having to reload our web browser.</p>
<p>In a command line, type in the following to install the Vue CLI globally:</p>
<pre><code class="lang-cli">npm install -g @vue/cli
</code></pre>
<p>Navigate to a desired directory and create a new folder for our project:</p>
<pre><code class="lang-cli">mkdir tabletop-project
cd tabletop-project
</code></pre>
<p>Now we can use the Vue CLI to template a front end project for us:</p>
<pre><code class="lang-cli">vue create client
</code></pre>
<p>You can just hit "enter" at the ensuing prompts unless you have specific preferences.</p>
<p>The Vue CLI has helpfully templated a front end project for us, which we can view in our code editor:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/1.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's navigate to our new client folder in our CLI and run the template app:</p>
<pre><code class="lang-cli">cd client
npm run serve
</code></pre>
<p>After a little work, the Vue CLI should begin displaying our app in a web browser at the default http://localhost:8080:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/2.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Cool!  We have the basic structure of our client.  Let's break it by creating two new components in the /components folder, called Game.vue and Chat.vue (you can go ahead and delete HelloWorld.vue and anything in the assets folder if you're obsessed with tidiness like I am).</p>
<p>Replace the code in App.vue with the following:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"game"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Game</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> <span class="hljs-attr">id</span>=<span class="hljs-string">"border"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"input"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Chat</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">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">import</span> Chat <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Chat.vue'</span>;
    <span class="hljs-keyword">import</span> Game <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Game.vue'</span>;

    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        <span class="hljs-attr">name</span>: <span class="hljs-string">'App'</span>,
        <span class="hljs-attr">components</span>: {
            Chat,
            Game
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    <span class="hljs-selector-id">#app</span> {
        <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Trebuchet MS'</span>;
        <span class="hljs-attribute">text-align</span>: left;
        <span class="hljs-attribute">background-color</span>: black;
        <span class="hljs-attribute">color</span>: cyan;
        <span class="hljs-attribute">display</span>: flex;
    }
    <span class="hljs-selector-id">#game</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">50vw</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
    }
    <span class="hljs-selector-id">#input</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">50vw</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
    }
    <span class="hljs-selector-id">#border</span> {
        <span class="hljs-attribute">border-right</span>: <span class="hljs-number">2px</span> solid cyan;
    }
    <span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">1000px</span>) {
        <span class="hljs-selector-id">#app</span> {
            <span class="hljs-attribute">flex-direction</span>: column;
        }
        <span class="hljs-selector-id">#game</span> {
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
            <span class="hljs-attribute">height</span>: <span class="hljs-number">50vh</span>;
        }
        <span class="hljs-selector-id">#input</span> {
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
            <span class="hljs-attribute">height</span>: <span class="hljs-number">50vh</span>;
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>As you can see, a Vue component ordinarily has three sections: Template, Script, and Style, which contain any HTML, JavaScript, and CSS for that component, respectively.  We've just imported our Game and Chat components here and added a little styling to give it a cyberpunk feel when it's all up and running.</p>
<p>That's actually all that we need to do to set up our App.vue component, which will house everything else in our client.  Before we can actually do anything with it, we'll need to get our server working!</p>
<h2 id="heading-part-2-server-basics">Part 2: Server Basics</h2>
<p>At our root directory (tabletop-project, above /client), initialize a new project in a new command line interface by typing:</p>
<pre><code class="lang-cli">npm init
</code></pre>
<p>Like with our client, you can go ahead and press "enter" at the prompts unless there are specifics that you'd like to designate at this time.</p>
<p>We'll need to install Express and Socket.IO, along with <a target="_blank" href="https://nodemon.io/">Nodemon</a> to watch our server files for us and reboot as necessary:</p>
<pre><code class="lang-cli">npm install --save express socket.io nodemon
</code></pre>
<p>Let's open up the new package.json file in that root directory and add a "start" command in the "scripts" section:</p>
<pre><code class="lang-javascript">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"nodemon server.js"</span>
  },
</code></pre>
<p>Create a new file called server.js in this directory, and enter the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> server = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)();
<span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>).createServer(server);
<span class="hljs-keyword">const</span> io = <span class="hljs-built_in">require</span>(<span class="hljs-string">'socket.io'</span>)(http);

io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">socket</span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user connected: '</span> + socket.id);

    socket.on(<span class="hljs-string">'send'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">text</span>) </span>{
        <span class="hljs-keyword">let</span> newText = <span class="hljs-string">"&lt;"</span> + socket.id + <span class="hljs-string">"&gt; "</span> + text;
        io.emit(<span class="hljs-string">'receive'</span>, newText);
    });

    socket.on(<span class="hljs-string">'disconnect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user disconnected: '</span> + socket.id);
    });
});

http.listen(<span class="hljs-number">3000</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server started!'</span>);
});
</code></pre>
<p>Excellent!  Our simple server will now listen at http://localhost:3000, and use Socket.IO to log to the console when a user connects and disconnects, with their socket ID.</p>
<p>When the server receives a "send" event from a client, it will create a new text string that includes the socket ID of the client that emitted the event, and emit its own "receive" event to all clients with the text that it received, interpolated with the socket ID.</p>
<p>We can test the server by returning to our command line and starting it up :</p>
<pre><code class="lang-cli">npm run start
</code></pre>
<p>The command console should now display:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/3-4.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Cool! Let's return to the Chat component of our client to start building out our front end functionality.</p>
<h2 id="heading-part-3-chat">Part 3: Chat</h2>
<p>Let's open a separate command line interface and navigate to the /client directory. Within that directory, install the client version of Socket.IO:</p>
<pre><code class="lang-cli">npm install --save socket.io-client
</code></pre>
<p>In /client/src/components/Chat.vue, add the following code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"output"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>STRUCT<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(text, index) in textOutput"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span>&gt;</span>{{text}}<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> <span class="hljs-attr">id</span>=<span class="hljs-string">"input"</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">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"textInput"</span> <span class="hljs-attr">:placeholder</span>=<span class="hljs-string">"textInput"</span> /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Send"</span> <span class="hljs-attr">v-on:click</span>=<span class="hljs-string">"submitText"</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>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">import</span> io <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>;
    <span class="hljs-keyword">let</span> socket = io(<span class="hljs-string">'http://localhost:3000'</span>);

    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        <span class="hljs-attr">name</span>: <span class="hljs-string">'Chat'</span>,
        <span class="hljs-attr">data</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-attr">textInput</span>: <span class="hljs-literal">null</span>,
                <span class="hljs-attr">textOutput</span>: []
            }
        },
        <span class="hljs-attr">methods</span>: {
            <span class="hljs-attr">submitText</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
                event.preventDefault();
                socket.emit(<span class="hljs-string">'send'</span>, <span class="hljs-built_in">this</span>.textInput);
            }
        },
        <span class="hljs-attr">created</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            socket.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function">() =&gt;</span> {
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected!'</span>);
            });
            socket.on(<span class="hljs-string">'receive'</span>, <span class="hljs-function">(<span class="hljs-params">text</span>) =&gt;</span> {
                <span class="hljs-built_in">this</span>.textOutput.push(text);
                <span class="hljs-built_in">this</span>.textInput = <span class="hljs-literal">null</span>;
            });
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
    <span class="hljs-selector-id">#container</span> {
        <span class="hljs-attribute">text-align</span>: left;
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">flex-direction</span>: column;
        <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">1vw</span>;
        <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
    }
    <span class="hljs-selector-tag">h1</span> {
        <span class="hljs-attribute">text-align</span>: center;
    }
    <span class="hljs-selector-class">.hotpink</span> {
        <span class="hljs-attribute">color</span>: hotpink;
    }
    <span class="hljs-selector-id">#input</span> {
        <span class="hljs-attribute">position</span>: fixed;
        <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">95vh</span>;
    }
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=text]</span> {
        <span class="hljs-attribute">height</span>: <span class="hljs-number">20px</span>;
        <span class="hljs-attribute">width</span>:  <span class="hljs-number">40vw</span>;
        <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid cyan;
        <span class="hljs-attribute">background-color</span>: black;
        <span class="hljs-attribute">color</span>: hotpink;
        <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">1em</span>;
    }
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=submit]</span>{
        <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
        <span class="hljs-attribute">width</span>: <span class="hljs-number">5vw</span>;
        <span class="hljs-attribute">background-color</span>: black;
        <span class="hljs-attribute">color</span>: cyan;
        <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid cyan;
        <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">2vw</span>;
    }
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=submit]</span><span class="hljs-selector-pseudo">:focus</span>{
        <span class="hljs-attribute">outline</span>: none;
    }
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=submit]</span><span class="hljs-selector-pseudo">:hover</span>{
        <span class="hljs-attribute">color</span>: hotpink;
    }
    <span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">1000px</span>) {
        <span class="hljs-selector-id">#container</span> {
            <span class="hljs-attribute">border-left</span>: none;
            <span class="hljs-attribute">border-top</span>: <span class="hljs-number">2px</span> solid cyan;
            <span class="hljs-attribute">min-height</span>: <span class="hljs-number">50vh</span>;
        }
        <span class="hljs-selector-id">#input</span> {
            <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">43vh</span>;
        }
        <span class="hljs-selector-id">#output</span> {
            <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">10vw</span>;
        }
        <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=text]</span> {
            <span class="hljs-attribute">width</span>: <span class="hljs-number">60vw</span>;
        }
        <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=submit]</span> {
            <span class="hljs-attribute">min-width</span>: <span class="hljs-number">10vw</span>;
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>Let's examine the above from bottom to top before moving forward.  Between the </p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ REST API Tutorial – REST Client, REST Service, and API Calls Explained With Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ By Vaibhav Kandwal Ever wondered how login/signup on a website works on the back-end? Or how when you search for "cute kitties" on YouTube, you get a bunch of results and are able to stream off of a remote machine? In this beginner friendly guide, I ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/rest-api-tutorial-rest-client-rest-service-and-api-calls-explained-with-code-examples/</link>
                <guid isPermaLink="false">66d45dd78812486a37369c6d</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 22 Apr 2020 19:05:27 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9b84740569d1a4ca2c3f.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Vaibhav Kandwal</p>
<p>Ever wondered how login/signup on a website works on the back-end? Or how when you search for "cute kitties" on YouTube, you get a bunch of results and are able to stream off of a remote machine?</p>
<p>In this beginner friendly guide, I will walk you through the process of setting up a RESTful API. We'll declassify some of the jargon and have a look at how we can code a server in NodeJS. Let's dive a bit deeper into JavaScript!</p>
<h2 id="heading-get-that-jargon-away">Get that jargon away</h2>
<p>So, what is REST? According to Wikipedia:</p>
<blockquote>
<p><strong>Representational state transfer</strong> (<strong>REST</strong>) is a software architectural style that defines a set of constraints to be used for creating Web services. RESTful Web services allow the requesting systems to access and manipulate textual representations of Web resources by using a uniform and predefined set of stateless operations</p>
</blockquote>
<p>Let's demystify what that means (hopefully you got the full form). REST is basically a set of rules for communication between a client and server. There are a few constraints on the definition of REST:</p>
<ol>
<li><strong>Client-Server Architecture</strong>: the user interface of the website/app should be separated from the data request/storage, so each part can be scaled individually.</li>
<li><strong>Statelessness</strong>: the communication should have no client context stored on server. This means each request to the server should be made with all the required data and no assumptions should be made if the server has any data from previous requests.</li>
<li><strong>Layered system</strong>: client should not be able to tell if it is communicating directly with the server or some intermediary. These intermediary servers (be it proxy or load balancers) allow for scalability and security of the underlying server.</li>
</ol>
<p>Okay, so now that you know what RESTful services are, here are some of the terms used in the heading:</p>
<ol>
<li><strong>REST Client</strong>: code or an app that can access these REST services. You are using one right now! Yes, the browser can act as an uncontrolled REST client (the website handles the browser requests). The browser, for a long time, used an in-built function called XMLHttpRequest for all REST requests. But, this was succeeded by <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">FetchAPI</a>, a modern, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promise</a> based approach to requests. Others examples are code libraries like <a target="_blank" href="https://github.com/axios/axios">axios</a>, <a target="_blank" href="https://github.com/visionmedia/superagent">superagent</a> and <a target="_blank" href="https://github.com/sindresorhus/got">got</a> or some dedicated apps like <a target="_blank" href="https://www.postman.com/">Postman</a> (or an online version, <a target="_blank" href="https://postwoman.io/">postwoman</a>!), or a command line tool like <a target="_blank" href="https://curl.haxx.se/">cURL</a>!.</li>
<li><strong>REST Service</strong>: the server. There are many popular libraries that make creation of these servers a breeze, like <a target="_blank" href="https://expressjs.com/">ExpressJS</a> for NodeJS and <a target="_blank" href="https://www.djangoproject.com/">Django</a> for Python.</li>
<li><strong>REST API</strong>: this defines the endpoint and methods allowed to access/submit data to the server. We will talk about this in great detail below. Other alternatives to this are: GraphQL, JSON-Pure and oData.</li>
</ol>
<h2 id="heading-so-tell-me-now-how-does-rest-look">So tell me now, how does REST look?</h2>
<p>In very broad terms, you ask the server for a certain data or ask it to save some data, and the server responds to the requests.</p>
<p>In programming terms, there is an endpoint (a URL) that the server is waiting to get a request. We connect to that endpoint and send in some data about us (remember, REST is stateless, no data about the request is stored) and the server responds with the correct response.</p>
<p>Words are boring, let me give you a demonstration. I will be using Postman to show you the request and response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/image-162.png" alt="Image" width="600" height="400" loading="lazy">
<em>postman: setting up request</em></p>
<p>The returned data is in JSON (JavaScript Object Notation) and can be accessed directly.</p>
<p>Here, <code>https://official-joke-api.appspot.com/random_joke</code> is called an endpoint of an API. There will be a server listening on that endpoint for requests like the one we made.</p>
<h2 id="heading-anatomy-of-rest">Anatomy of REST:</h2>
<p>Alright, so now we know that data can be requested by the client and the server will respond appropriately. Let's look deeper into how a request is formed.</p>
<ol>
<li><strong>Endpoint</strong>: I have already told you about this. For a refresher, it is the URL where the REST Server is listening.</li>
<li><strong>Method</strong>: Earlier, I wrote that you can either request data or modify it, but how will the server know what kind of operation the client wants to perform? REST implements multiple 'methods' for different types of request, the following are most popular:  </li>
<li><strong>GET</strong>: Get resource from the server.  </li>
<li><strong>POST</strong>: Create resource to the server.  </li>
<li><strong>PATCH</strong> or <strong>PUT</strong>: Update existing resource on the server.  </li>
<li><p><strong>DELETE</strong>: Delete existing resource from the server.  </p>
</li>
<li><p><strong>Headers</strong>: The additional details provided for communication between client and server (remember, REST is stateless). Some of the common headers are:<br><strong>Request:</strong>  </p>
</li>
<li><em>host</em>: the IP of client (or from where request originated)  </li>
<li><em>accept-language</em>: language understandable by the client  </li>
<li><em>user-agent</em>: data about client, operating system and vendor<br><strong>Response</strong>:  </li>
<li><em>status</em>: the status of request or HTTP code.  </li>
<li><em>content-type</em>: type of resource sent by server.  </li>
<li><em>set-cookie</em>: sets cookies by server</li>
<li><strong>Data</strong>: (also called body or message) contains info you want to send to the server.</li>
</ol>
<h2 id="heading-enough-with-the-details-show-me-the-code">Enough with the details – show me the code.</h2>
<p>Let's begin coding a REST Service in Node. We will be implementing all the things we learnt above. We will also be using ES6+ to write our service in.</p>
<p>Make sure you have Node.JS installed and <code>node</code> and <code>npm</code> are available in your path. I will be using Node 12.16.2 and NPM 6.14.4.</p>
<p>Create a directory <code>rest-service-node</code> and cd into it:</p>
<pre><code class="lang-shell">mkdir rest-service-node
cd rest-service-node
</code></pre>
<p>Initialize the node project:</p>
<pre><code class="lang-shell">npm init -y
</code></pre>
<p>The <code>-y</code> flag skips all the questions. If you want to fill in the whole questionnaire, just run <code>npm init</code>.</p>
<p> Let's install some packages. We will be using the ExpressJS framework for developing the REST Server. Run the following command to install it:</p>
<pre><code class="lang-shell">npm install --save express body-parser
</code></pre>
<p>What's <code>body-parser</code> there for? Express, by default, is incapable of handling data sent via POST request as JSON. <code>body-parser</code> allows Express to overcome this.</p>
<p>Create a file called <code>server.js</code> and add the following 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> bodyParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"body-parser"</span>);

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

app.use(bodyParser.json());

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 is running on port 5000.`</span>);
});
</code></pre>
<p>The first two lines are importing Express and body-parser. </p>
<p>Third line initializes the Express server and sets it to a variable called <code>app</code>. </p>
<p>The line, <code>app.use(bodyParser.json());</code> initializes the body-parser plugin.</p>
<p>Finally, we are setting our server to listen on port <code>5000</code> for requests.</p>
<h3 id="heading-getting-data-from-the-rest-server">Getting data from the REST Server:</h3>
<p>To get data from a server, we need a <code>GET</code> request. Add the following code before <code>app.listen</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> sayHi = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Hi!"</span>);
};

app.get(<span class="hljs-string">"/"</span>, sayHi);
</code></pre>
<p> We have created a function <code>sayHi</code> which takes two parameters <code>req</code> and <code>res</code> (I will explain later) and sends a 'Hi!' as response. </p>
<p><code>app.get()</code> takes two parameters, the route path and function to call when the path is requested by the client. So, the last line translates to: Hey server, listen for requests on the '/' (think homepage) and call the <code>sayHi</code> function if a request is made.</p>
<p><code>app.get</code> also gives us a <code>request</code> object containing all the data sent by the client and a <code>response</code> object which contains all the methods with which we can respond to the client. Though these are accessible as function parameters, the general naming convention suggests we name them <code>res</code> for <code>response</code> and <code>req</code> for <code>request</code>.</p>
<p>Enough chatter. Let's fire up the server! Run the following server:</p>
<pre><code class="lang-shell">node server.js
</code></pre>
<p>If everything is successful, you should see a message on console saying: <em>Server is running on port 5000.</em></p>
<p><em>Note: You can change the port to whatever number you want.</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/image-160.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Open up your browser and navigate to <code>http://localhost:5000/</code> and you should see something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/image-161.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>There you go! Your first <code>GET</code> request was successful!</p>
<h3 id="heading-sending-data-to-rest-server">Sending data to REST Server:</h3>
<p>As we have discussed earlier, let's setup how we can implement a <code>POST</code> request into our server. We will be sending in two numbers and the server will return the sum of the numbers. Add this new method below the <code>app.get</code> :</p>
<pre><code class="lang-js">app.post(<span class="hljs-string">"/add"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { a, b } = req.body;
  res.send(<span class="hljs-string">`The sum is: <span class="hljs-subst">${a + b}</span>`</span>);
});
</code></pre>
<p>Here, we will be sending the data in JSON format, like this:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"a"</span>:<span class="hljs-number">5</span>,
    <span class="hljs-attr">"b"</span>:<span class="hljs-number">10</span>
}
</code></pre>
<p>Let's get over the code:</p>
<p>On line 1, we are invoking the .<code>post()</code> method of ExpressJS, which allows the server to listen for <code>POST</code> requests. This function takes in the same parameters as the <code>.get()</code> method. The route that we are passing is <code>/add</code>, so one can access the endpoint as <code>http://your-ip-address:port/add</code> or in our case <code>localhost:5000/add</code>. We are inlining our function instead of writing a function elsewhere. </p>
<p>On line 2, we have used a bit of ES6 syntax, namely, object destructuring. Whatever data we send via the request gets stored and is available in the <code>body</code> of the <code>req</code> object. So essentially, we could've replaced line 2 with something like:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> num1 = req.body.a;
<span class="hljs-keyword">const</span> num2 = req.body.b;
</code></pre>
<p>On line 3, we are using the <code>send()</code> function of the <code>res</code> object to send the result of the sum. Again, we are using template literals from ES6. Now to test it (using Postman):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/image-163.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>So we have sent the data 5 and 10 as <code>a</code> and <code>b</code> using them as the body. Postman attaches this data to the request and sends it. When the server receives the request, it can parse the data from <code>req.body</code> , as we did in the code above. The result is shown below.</p>
<p>Alright, the final 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> bodyParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"body-parser"</span>);

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

app.use(bodyParser.json());

<span class="hljs-keyword">const</span> sayHi = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Hi!"</span>);
};

app.get(<span class="hljs-string">"/"</span>, sayHi);

app.post(<span class="hljs-string">"/add"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { a, b } = req.body;
  res.send(<span class="hljs-string">`The sum is: <span class="hljs-subst">${a + b}</span>`</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 is running on port 5000.`</span>);
});
</code></pre>
<h2 id="heading-rest-client">REST Client:</h2>
<p>Okay, we have created a server, but how do we access it from our website or webapp? Here the REST client libraries will come in handy. </p>
<p>We will be building a webpage which will contain a form, where you can enter two numbers and we will display the result. Let's start.</p>
<p>First, let's change the <code>server.js</code> a bit:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">"path"</span>);
<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> bodyParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"body-parser"</span>);

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

app.use(bodyParser.json());

app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.sendFile(path.join(__dirname, <span class="hljs-string">"index.html"</span>));
});

app.post(<span class="hljs-string">"/add"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { a, b } = req.body;
  res.send({
    <span class="hljs-attr">result</span>: <span class="hljs-built_in">parseInt</span>(a) + <span class="hljs-built_in">parseInt</span>(b)
  });
});

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 is running on port 5000.`</span>);
});
</code></pre>
<p>We imported a new package <code>path</code>, which is provided by Node, to manipulate path cross-platform. Next we changed the <code>GET</code> request on '/' and use another function available in <code>res</code>, ie. <code>sendFile</code>, which allows us to send any type of file as response. So, whenever a person tries to navigate to '/', they will get our <code>index.html</code> page.</p>
<p>Finally, we changed our <code>app.post</code> function to return the sum as JSON and convert both <code>a</code> and <code>b</code> to integers.</p>
<p>Let's create an html page, I will call it <code>index.html</code>, with some basic styling:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<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">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>REST Client<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    * {
      <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
      <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
      <span class="hljs-attribute">box-sizing</span>: border-box;
    }
    <span class="hljs-selector-class">.container</span> {
      <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
      <span class="hljs-attribute">font-family</span>: -apple-system, BlinkMacSystemFont, <span class="hljs-string">"Segoe UI"</span>, Roboto, Helvetica, Arial, sans-serif, <span class="hljs-string">"Apple Color Emoji"</span>, <span class="hljs-string">"Segoe UI Emoji"</span>, <span class="hljs-string">"Segoe UI Symbol"</span>;
      <span class="hljs-attribute">display</span>: flex;
      <span class="hljs-attribute">flex-direction</span>: column;
      <span class="hljs-attribute">justify-content</span>: center;
      <span class="hljs-attribute">align-items</span>: center;
    }
    <span class="hljs-selector-tag">form</span> {
      <span class="hljs-attribute">display</span>: flex;
      <span class="hljs-attribute">flex-direction</span>: column;
      <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">20px</span>;
    }
    <span class="hljs-selector-tag">label</span>,
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"submit"</span>]</span> {
      <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">20px</span>;
    }
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</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">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Simple POST Form<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</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">label</span>&gt;</span>Number 1:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"num1"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Number 2:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"num2"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Add"</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">class</span>=<span class="hljs-string">"result"</span>&gt;</span>Click Add!<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">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Let's add a <code>script</code> tag just before the closing body tag, so we don't need to maintain a <code>.js</code> file. We will begin by listening for the <code>submit</code> event and call a function accordingly:</p>
<pre><code class="lang-js">&lt;script&gt;
    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"submit"</span>, sendData);
&lt;/script&gt;
</code></pre>
<p>First we need to prevent page refresh when the 'Add' button is clicked. This can be done using the <code>preventDefault()</code> function. Then, we will get the value of the inputs at that instant:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendData</span>(<span class="hljs-params">e</span>) </span>{
    e.preventDefault();
    <span class="hljs-keyword">const</span> a = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#num1"</span>).value;
    <span class="hljs-keyword">const</span> b = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#num2"</span>).value;
}
</code></pre>
<p>Now we will make the call to the server with both these values <code>a</code> and <code>b</code>. We will be using the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>, built-in to every browser for this. </p>
<p>Fetch takes in two inputs, the URL endpoint and a JSON request object and returns a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a>. Explaining them here will be out-of-bounds here, so I'll leave that for you.</p>
<p>Continue inside the <code>sendData()</code> function:</p>
<pre><code class="lang-js">fetch(<span class="hljs-string">"/add"</span>, {
        <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
        <span class="hljs-attr">headers</span>: {
            <span class="hljs-attr">Accept</span>: <span class="hljs-string">"application/json"</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({
            <span class="hljs-attr">a</span>: <span class="hljs-built_in">parseInt</span>(a),
            <span class="hljs-attr">b</span>: <span class="hljs-built_in">parseInt</span>(b)
        })
    })
    .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json())
    .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
        <span class="hljs-keyword">const</span> {
            result
        } = data;
        <span class="hljs-built_in">document</span>.querySelector(
            <span class="hljs-string">".result"</span>
        ).innerText = <span class="hljs-string">`The sum is: <span class="hljs-subst">${result}</span>`</span>;
    })
    .catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
</code></pre>
<p>First we are passing the relative URL of the endpoint as the first parameter to <code>fetch</code>. Next, we are passing an object which contains the method we want Fetch to use for the request, which is <code>POST</code> in this case.</p>
<p>We are also passing <code>headers</code>, which will provide information about the type of data we are sending (<code>content-type</code>) and the type of data we accept as response (<code>accept</code>).</p>
<p>Next we pass <code>body</code>. Remember we typed the data as JSON while using Postman? We're doing kind of a similar thing here. Since express deals with string as input and processes it according to content-type provided, we need to convert our JSON payload into string. We do that with <code>JSON.stringify()</code>. We're being a little extra cautious and parsing the input into integers, so it doesn't mess up our server (since we haven't implemented any data-type checking).</p>
<p>Finally, if the promise (returned by fetch) resolves, we will get that response and convert it into JSON. After that, we will get the result from the <code>data</code> key returned by the response. Then we are simply displaying the result on the screen.</p>
<p>At the end, if the promise is rejected, we will display the error message on the console.</p>
<p>Here's the final code for <code>index.html</code>:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<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">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>REST Client<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    * {
      <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
      <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
      <span class="hljs-attribute">box-sizing</span>: border-box;
    }
    <span class="hljs-selector-class">.container</span> {
      <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
      <span class="hljs-attribute">font-family</span>: -apple-system, BlinkMacSystemFont, <span class="hljs-string">"Segoe UI"</span>, Roboto, Helvetica, Arial, sans-serif, <span class="hljs-string">"Apple Color Emoji"</span>, <span class="hljs-string">"Segoe UI Emoji"</span>, <span class="hljs-string">"Segoe UI Symbol"</span>;
      <span class="hljs-attribute">display</span>: flex;
      <span class="hljs-attribute">flex-direction</span>: column;
      <span class="hljs-attribute">justify-content</span>: center;
      <span class="hljs-attribute">align-items</span>: center;
    }
    <span class="hljs-selector-tag">form</span> {
      <span class="hljs-attribute">display</span>: flex;
      <span class="hljs-attribute">flex-direction</span>: column;
      <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">20px</span>;
    }
    <span class="hljs-selector-tag">label</span>,
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"submit"</span>]</span> {
      <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">20px</span>;
    }
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</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">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Simple POST Form<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</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">label</span>&gt;</span>Number 1:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"num1"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Number 2:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"num2"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Add"</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">class</span>=<span class="hljs-string">"result"</span>&gt;</span>Click Add!<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">script</span>&gt;</span><span class="javascript">
      <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"submit"</span>, sendData);
      <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendData</span>(<span class="hljs-params">e</span>) </span>{
        e.preventDefault();
        <span class="hljs-keyword">const</span> a = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#num1"</span>).value;
        <span class="hljs-keyword">const</span> b = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#num2"</span>).value;

        fetch(<span class="hljs-string">"/add"</span>, {
          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
          <span class="hljs-attr">headers</span>: {
            <span class="hljs-attr">Accept</span>: <span class="hljs-string">"application/json"</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({
            <span class="hljs-attr">a</span>: <span class="hljs-built_in">parseInt</span>(a),
            <span class="hljs-attr">b</span>: <span class="hljs-built_in">parseInt</span>(b)
          })
        })
          .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json())
          .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
            <span class="hljs-keyword">const</span> { result } = data;
            <span class="hljs-built_in">document</span>.querySelector(
              <span class="hljs-string">".result"</span>
            ).innerText = <span class="hljs-string">`The sum is: <span class="hljs-subst">${result}</span>`</span>;
          })
          .catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
      }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</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>
</code></pre>
<p>I have spun up a <a target="_blank" href="https://habitual-serious-boater.glitch.me/">little app on glitch</a> for you to test.</p>
<h2 id="heading-conclusion">Conclusion:</h2>
<p>So in this post, we learnt about REST architecture and the anatomy of REST requests. We worked our way through by creating a simple REST Server that serves <code>GET</code> and <code>POST</code> requests and built a simple webpage that uses a REST Client to display the sum of two numbers. </p>
<p>You can extend this for the remaining types of requests and even implement a full featured <a target="_blank" href="https://www.freecodecamp.org/news/building-a-simple-crud-application-with-express-and-mongodb-63f80f3eb1cd/">back-end CRUD app</a>. </p>
<p>I hope you have learned something from this. If you have any questions, feel free to reach out to me over twitter! Happy Coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Multiplayer Card Game with Phaser 3, Express, and Socket.IO ]]>
                </title>
                <description>
                    <![CDATA[ By M. S. Farzan I'm a tabletop game developer, and am continually looking for ways to digitize game experiences.  In this tutorial, we're going to build a multiplayer card game using Phaser 3, Express, and Socket.IO. In terms of prerequisites, you'll... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-multiplayer-card-game-with-phaser-3-express-and-socket-io/</link>
                <guid isPermaLink="false">66d851e78da7a7c34f4c9223</guid>
                
                    <category>
                        <![CDATA[ ES6 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GameDev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ phaser 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SocketIO ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 25 Mar 2020 20:57:51 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/03/Client-2-2.PNG" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By M. S. Farzan</p>
<p>I'm a <a target="_blank" href="https://www.nightpathpub.com/entromancy">tabletop game</a> developer, and am continually looking for ways to digitize game experiences.  In this tutorial, we're going to build a multiplayer card game using <a target="_blank" href="http://phaser.io/">Phaser 3</a>, <a target="_blank" href="https://expressjs.com/">Express</a>, and <a target="_blank" href="https://socket.io/">Socket.IO</a>.</p>
<p>In terms of prerequisites, you'll want to make sure that you have <a target="_blank" href="https://nodejs.org/en/">Node</a>/<a target="_blank" href="https://www.npmjs.com/">NPM</a> and <a target="_blank" href="https://github.com/">Git</a> installed and configured on your machine.  Some experience with JavaScript would be helpful, and you may want to run through the <a target="_blank" href="http://phaser.io/tutorials/making-your-first-phaser-3-game">basic Phaser tutorial</a> before tackling this one.</p>
<p>Major kudos to Scott Westover for <a target="_blank" href="https://gamedevacademy.org/create-a-basic-multiplayer-game-in-phaser-3-with-socket-io-part-1/">his tutorial on the topic</a>, Kal_Torak and the Phaser community for answering all my questions, and my good friend Mike for helping me conceptualize the architecture of this project.</p>
<p>Note: we'll be using assets and colors from my tabletop card game, <em><a target="_blank" href="https://www.nightpathpub.com/hacker-battles">Entromancy: Hacker Battles</a></em>.  If you prefer, you can use your own images (or even <a target="_blank" href="http://phaser.io/examples/v3/view/game-objects/shapes/rectangle">Phaser rectangles</a>) and colors, and you can access the entire project code on <a target="_blank" href="https://github.com/sominator/multiplayer-card-project">GitHub</a>.</p>
<p>If you'd prefer a more visual tutorial, you can also follow along with the companion video to this article:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/fEwAgKBgoJM" 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>
<p>Let's get started!</p>
<h2 id="heading-the-game">The Game</h2>
<p>Our simple card game will feature a Phaser client that will handle most of the game logic and doing things like dealing cards, providing drag-and-drop functionality, and so on.</p>
<p>On the back end, we'll spin up an Express server that will utilize Socket.IO to communicate between clients and make it so that when one player plays a card, it shows up in another player's client, and vice-versa.</p>
<p>Our goal for this project is to create a basic framework for a multiplayer card game that you can build upon and adjust to suit your own game's logic.</p>
<p>First, let's tackle the client!</p>
<h2 id="heading-the-client">The Client</h2>
<p>To scaffold our client, we're going to clone the semi-official Phaser 3 Webpack Project Template on <a target="_blank" href="https://github.com/photonstorm/phaser3-project-template">GitHub</a>.</p>
<p>Open your favorite command line interface and create a new folder:</p>
<pre><code class="lang-cli">mkdir multiplayer-card-project
cd multiplayer-card-project
</code></pre>
<p>Clone the git project:</p>
<pre><code class="lang-cli">git clone https://github.com/photonstorm/phaser3-project-template.git
</code></pre>
<p>This command will download the template in a folder called "phaser3-project-template" within /multiplayer-card-project.  If you want to follow along with our tutorial's file structure, go ahead and change that template folder's name to "client."</p>
<p>Navigate into that new directory and install all dependencies:</p>
<pre><code class="lang-cli">cd client
npm install
</code></pre>
<p>Your project folder structure should look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/File-Structure-1-4.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Before we muck with the files, let's go back to our CLI and enter the following command in the /client folder:</p>
<pre><code class="lang-cli">npm start
</code></pre>
<p>Our Phaser template utilizes Webpack to spin up a local server that in turn serves up a simple game app in our browser (usually at http://localhost:8080).  Neat!</p>
<p>Let's open our project in your favorite code editor and make some changes to fit our card game.  Delete everything in /client/src/assets and replace them with the card images from <a target="_blank" href="https://github.com/sominator/multiplayer-card-project/tree/master/client/src/assets">GitHub</a>.</p>
<p>In the /client/src directory, add a folder called "scenes" and another called "helpers."</p>
<p>In /client/src/scenes, add an empty file called "game.js".</p>
<p>In /client/src/helpers, add three empty files: "card.js", "dealer.js", and "zone.js".</p>
<p>Your project structure should now look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/File-Structure-2.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Cool!  Your client might be throwing you errors because we deleted some things, but not to worry.  Open /src/index.js, which is the main entry point to our front end app. Enter the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Phaser <span class="hljs-keyword">from</span> <span class="hljs-string">"phaser"</span>;
<span class="hljs-keyword">import</span> Game <span class="hljs-keyword">from</span> <span class="hljs-string">"./scenes/game"</span>;

<span class="hljs-keyword">const</span> config = {
    <span class="hljs-attr">type</span>: Phaser.AUTO,
    <span class="hljs-attr">parent</span>: <span class="hljs-string">"phaser-example"</span>,
    <span class="hljs-attr">width</span>: <span class="hljs-number">1280</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">780</span>,
    <span class="hljs-attr">scene</span>: [
        Game
    ]
};

<span class="hljs-keyword">const</span> game = <span class="hljs-keyword">new</span> Phaser.Game(config);
</code></pre>
<p>All we've done here is restructure the boilerplate to utilize Phaser's "scene" system so that we can separate our game scenes rather than try to cram everything in one file.  Scenes can be useful if you're creating multiple game worlds, building things like instruction screens, or generally trying to keep things tidy.</p>
<p>Let's move to /src/scenes/game.js and write some code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Game</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Phaser</span>.<span class="hljs-title">Scene</span> </span>{
    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-built_in">super</span>({
            <span class="hljs-attr">key</span>: <span class="hljs-string">'Game'</span>
        });
    }

    preload() {
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'cyanCardFront'</span>, <span class="hljs-string">'src/assets/CyanCardFront.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'cyanCardBack'</span>, <span class="hljs-string">'src/assets/CyanCardBack.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'magentaCardFront'</span>, <span class="hljs-string">'src/assets/MagentaCardFront.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'magentaCardBack'</span>, <span class="hljs-string">'src/assets/MagentaCardBack.png'</span>);
    }

    create() {
        <span class="hljs-built_in">this</span>.dealText = <span class="hljs-built_in">this</span>.add.text(<span class="hljs-number">75</span>, <span class="hljs-number">350</span>, [<span class="hljs-string">'DEAL CARDS'</span>]).setFontSize(<span class="hljs-number">18</span>).setFontFamily(<span class="hljs-string">'Trebuchet MS'</span>).setColor(<span class="hljs-string">'#00ffff'</span>).setInteractive();
    }

    update() {

    }
}
</code></pre>
<p>We're taking advantage of <a target="_blank" href="https://www.freecodecamp.org/news/how-to-use-github-and-es6-features-to-create-and-structure-your-code/">ES6 classes</a> to create a new Game scene, which incorporates preload(), create() and update() functions.</p>
<p>preload() is used to...well...preload any assets that we'll be using for our game.</p>
<p>create() is run when the game starts up, and where we'll be establishing much of our user interface and game logic.</p>
<p>update() is called once per frame, and we won't be making use of it in our tutorial (but it may be useful in your own game depending on its requirements).</p>
<p>Within the create() function, we've created a bit of text that says "DEAL CARDS" and set it to be interactive:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Deal-Cards.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Very cool.  Let's create a bit of placeholder code to understand how we want this whole thing to work once it's up and running.  Add the following to your create() function:</p>
<pre><code class="lang-javascript">        <span class="hljs-keyword">let</span> self = <span class="hljs-built_in">this</span>;

        <span class="hljs-built_in">this</span>.card = <span class="hljs-built_in">this</span>.add.image(<span class="hljs-number">300</span>, <span class="hljs-number">300</span>, <span class="hljs-string">'cyanCardFront'</span>).setScale(<span class="hljs-number">0.3</span>, <span class="hljs-number">0.3</span>).setInteractive();
        <span class="hljs-built_in">this</span>.input.setDraggable(<span class="hljs-built_in">this</span>.card);

        <span class="hljs-built_in">this</span>.dealCards = <span class="hljs-function">() =&gt;</span> {

        }

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerdown'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealCards();
        })

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerover'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealText.setColor(<span class="hljs-string">'#ff69b4'</span>);
        })

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerout'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealText.setColor(<span class="hljs-string">'#00ffff'</span>);
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'drag'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dragX, dragY</span>) </span>{
            gameObject.x = dragX;
            gameObject.y = dragY;
        })
</code></pre>
<p>We've added a lot of structure, but not much has happened.  Now, when our mouse hovers over the "DEAL CARDS" text, it's highlighted in cyberpunk hot pink, and there's a random card on our screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Card.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We've placed the image at the (x, y) coordinates of (300, 300), set its scale to be a bit smaller, and made it interactive and draggable.  We've also added a little bit of logic to determine what should happen when dragged: it should follow the (x, y) coordinates of our mouse.</p>
<p>We've also created an empty dealCards() function that will be called when we click on our "DEAL CARDS" text.  Additionally, we've saved "this" - meaning the scene in which we're currently working - into a variable called "self" so that we can use it throughout our functions without worrying about scope.</p>
<p>Our Game scene is going to get messy fast if we don't start moving things around, so let's delete the code block that begins with "this.card" and move to /src/helpers/card.js to write:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Card</span> </span>{
    <span class="hljs-keyword">constructor</span>(scene) {
        <span class="hljs-built_in">this</span>.render = <span class="hljs-function">(<span class="hljs-params">x, y, sprite</span>) =&gt;</span> {
            <span class="hljs-keyword">let</span> card = scene.add.image(x, y, sprite).setScale(<span class="hljs-number">0.3</span>, <span class="hljs-number">0.3</span>).setInteractive();
            scene.input.setDraggable(card);
            <span class="hljs-keyword">return</span> card;
        }
    }
}
</code></pre>
<p>We've created a new class that accepts a scene as a parameter, and features a render() function that accepts (x, y) coordinates and a sprite.  Now, we can call this function from elsewhere and pass it the necessary parameters to create cards.</p>
<p>Let's import the card at the top of our Game scene:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Card <span class="hljs-keyword">from</span> <span class="hljs-string">'../helpers/card'</span>;
</code></pre>
<p> And enter the following code within our empty dealCards() function:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.dealCards = <span class="hljs-function">() =&gt;</span> {
            <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">let</span> playerCard = <span class="hljs-keyword">new</span> Card(<span class="hljs-built_in">this</span>);
                playerCard.render(<span class="hljs-number">475</span> + (i * <span class="hljs-number">100</span>), <span class="hljs-number">650</span>, <span class="hljs-string">'cyanCardFront'</span>);
            }
        }
</code></pre>
<p>When we click on the "DEAL CARDS" button, we now iterate through a for loop that creates cards and renders them sequentially on screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Cards.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>NICE.  We can drag those cards around the screen, but it might be nice to limit where they can be dropped to support our game logic.</p>
<p>Let's move over to /src/helpers/zone.js and add a new class:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Zone</span> </span>{
    <span class="hljs-keyword">constructor</span>(scene) {
        <span class="hljs-built_in">this</span>.renderZone = <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">let</span> dropZone = scene.add.zone(<span class="hljs-number">700</span>, <span class="hljs-number">375</span>, <span class="hljs-number">900</span>, <span class="hljs-number">250</span>).setRectangleDropZone(<span class="hljs-number">900</span>, <span class="hljs-number">250</span>);
            dropZone.setData({ <span class="hljs-attr">cards</span>: <span class="hljs-number">0</span> });
            <span class="hljs-keyword">return</span> dropZone;
        };
        <span class="hljs-built_in">this</span>.renderOutline = <span class="hljs-function">(<span class="hljs-params">dropZone</span>) =&gt;</span> {
            <span class="hljs-keyword">let</span> dropZoneOutline = scene.add.graphics();
            dropZoneOutline.lineStyle(<span class="hljs-number">4</span>, <span class="hljs-number">0xff69b4</span>);
            dropZoneOutline.strokeRect(dropZone.x - dropZone.input.hitArea.width / <span class="hljs-number">2</span>, dropZone.y - dropZone.input.hitArea.height / <span class="hljs-number">2</span>, dropZone.input.hitArea.width, dropZone.input.hitArea.height)
        }
    }
}
</code></pre>
<p>Phaser has built-in dropzones that allow us to dictate where game objects can be dropped, and we've set up one here and provided it with an outline.  We've also added a tiny bit of data called "cards" to the dropzone that we'll use later.</p>
<p>Let's import our new zone into the Game scene:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Zone <span class="hljs-keyword">from</span> <span class="hljs-string">'../helpers/zone'</span>;
</code></pre>
<p> And call it in within the create() function:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.zone = <span class="hljs-keyword">new</span> Zone(<span class="hljs-built_in">this</span>);
        <span class="hljs-built_in">this</span>.dropZone = <span class="hljs-built_in">this</span>.zone.renderZone();
        <span class="hljs-built_in">this</span>.outline = <span class="hljs-built_in">this</span>.zone.renderOutline(<span class="hljs-built_in">this</span>.dropZone);
</code></pre>
<p>Not too shabby!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Zone.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We need to add a bit of logic to determine how cards should be dropped into the zone.  Let's do that below the "this.input.on('drag')" function:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'dragstart'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject</span>) </span>{
            gameObject.setTint(<span class="hljs-number">0xff69b4</span>);
            self.children.bringToTop(gameObject);
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'dragend'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dropped</span>) </span>{
            gameObject.setTint();
            <span class="hljs-keyword">if</span> (!dropped) {
                gameObject.x = gameObject.input.dragStartX;
                gameObject.y = gameObject.input.dragStartY;
            }
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'drop'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dropZone</span>) </span>{
            dropZone.data.values.cards++;
            gameObject.x = (dropZone.x - <span class="hljs-number">350</span>) + (dropZone.data.values.cards * <span class="hljs-number">50</span>);
            gameObject.y = dropZone.y;
            gameObject.disableInteractive();
        })
</code></pre>
<p>Starting at the bottom of the code, when a card is dropped, we increment the "cards" data value on the dropzone, and assign the (x, y) coordinates of the card to the dropzone based on how many cards are already on it.  We also disable interactivity on cards after they're dropped so that they can't be retracted:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Zone-Dropped.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We've also made it so that our cards have a different tint when dragged, and if they're not dropped over the dropzone, they'll return to their starting positions.</p>
<p>Although our client isn't quite complete, we've done as much as we can before implementing the back end.  We can now deal cards, drag them around the screen, and drop them in a dropzone. But to move forward, we'll need to set up a server than can coordinate our multiplayer functionality.</p>
<h2 id="heading-the-server">The Server</h2>
<p>Let's open up a new command line at our root directory (above /client) and type:</p>
<pre><code class="lang-cli">npm init
npm install --save express socket.io nodemon
</code></pre>
<p>We've initialized a new package.json and installed Express, Socket.IO, and <a target="_blank" href="https://nodemon.io/">Nodemon</a> (which will watch our server and restart it upon changes).</p>
<p>In our code editor, let's change the "scripts" section of our package.json to say:</p>
<pre><code class="lang-javascript">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"nodemon server.js"</span>
  },
</code></pre>
<p>Excellent.  We're ready to put our server together!  Create an empty file called "server.js" in our root directory and enter the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> server = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)();
<span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>).createServer(server);
<span class="hljs-keyword">const</span> io = <span class="hljs-built_in">require</span>(<span class="hljs-string">'socket.io'</span>)(http);

io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">socket</span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user connected: '</span> + socket.id);

    socket.on(<span class="hljs-string">'disconnect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user disconnected: '</span> + socket.id);
    });
});

http.listen(<span class="hljs-number">3000</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server started!'</span>);
});
</code></pre>
<p>We're importing Express and Socket.IO, asking for the server to listen on port 3000. When a client connects to or disconnects from that port, we'll log the event to the console with the client's socket id.</p>
<p>Open a new command line interface and start the server:</p>
<pre><code class="lang-cli">npm run start
</code></pre>
<p>Our server should now be running on localhost:3000, and Nodemon will watch our back end files for any changes.  Not much else will happen except for the console log that the "Server started!"</p>
<p>In our other open command line interface, let's navigate back to our /client directory and install the client version of Socket.IO:</p>
<pre><code class="lang-cli">cd client
npm install --save socket.io-client
</code></pre>
<p>We can now import it in our Game scene:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> io <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>;
</code></pre>
<p>Great!  We've just about wired up our front and back ends.  All we need to do is write some code in the create() function:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.socket = io(<span class="hljs-string">'http://localhost:3000'</span>);

        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected!'</span>);
        });
</code></pre>
<p>We're initializing a new "socket" variable that points to our local port 3000 and logs to the browser console upon connection.</p>
<p>Open and close a couple of browsers at http://localhost:8080 (where our Phaser client is being served) and you should see the following in your command line interface:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Console.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>YAY.  Let's start adding logic to our server.js file that will serve the needs of our card game.  Replace the existing code with the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> server = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)();
<span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>).createServer(server);
<span class="hljs-keyword">const</span> io = <span class="hljs-built_in">require</span>(<span class="hljs-string">'socket.io'</span>)(http);
<span class="hljs-keyword">let</span> players = [];

io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">socket</span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user connected: '</span> + socket.id);

    players.push(socket.id);

    <span class="hljs-keyword">if</span> (players.length === <span class="hljs-number">1</span>) {
        io.emit(<span class="hljs-string">'isPlayerA'</span>);
    };

    socket.on(<span class="hljs-string">'dealCards'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        io.emit(<span class="hljs-string">'dealCards'</span>);
    });

    socket.on(<span class="hljs-string">'cardPlayed'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">gameObject, isPlayerA</span>) </span>{
        io.emit(<span class="hljs-string">'cardPlayed'</span>, gameObject, isPlayerA);
    });

    socket.on(<span class="hljs-string">'disconnect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user disconnected: '</span> + socket.id);
        players = players.filter(<span class="hljs-function"><span class="hljs-params">player</span> =&gt;</span> player !== socket.id);
    });
});

http.listen(<span class="hljs-number">3000</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server started!'</span>);
});
</code></pre>
<p>We've initialized an empty array called "players" and add a socket id to it every time a client connects to the server, while also deleting the socket id upon disconnection.</p>
<p>If a client is the first to connect to the server, we ask Socket.IO to "<a target="_blank" href="https://socket.io/get-started/chat/#Emitting-events">emit</a>" an event that they're going to be Player A.  Subsequently, when the server receives an event called "dealCards" or "cardPlayed", it should emit back to the clients that they should update accordingly.</p>
<p>Believe it or not, that's all the code we need to get our server working!  Let's turn our attention back to the Game scene.  Right at the top of the create() function, type the following:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.isPlayerA = <span class="hljs-literal">false</span>;
        <span class="hljs-built_in">this</span>.opponentCards = [];
</code></pre>
<p>Under the code block that starts with "this.socket.on(connect)", write:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'isPlayerA'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.isPlayerA = <span class="hljs-literal">true</span>;
        })
</code></pre>
<p>Now, if our client is the first to connect to the server, the server will emit an event that tells the client that it will be Player A.  The client socket receives that event and turns our "isPlayerA" boolean from false to true.</p>
<p>Note: from this point forward, you may need to reload your browser page (set to http://localhost:8080), rather than having Webpack do it automatically for you, for the client to correctly disconnect from and reconnect to the server.</p>
<p>We need to reconfigure our dealCards() logic to support the multiplayer aspect of our game, given that we want the client to deal us a certain set of cards that may be different from our opponent's.  Additionally, we want to render the backs of our opponent's cards on our screen, and vice versa.</p>
<p>We'll move to the empty /src/helpers/dealer.js file, import card.js, and create a new class:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Card <span class="hljs-keyword">from</span> <span class="hljs-string">'./card'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dealer</span> </span>{
    <span class="hljs-keyword">constructor</span>(scene) {
        <span class="hljs-built_in">this</span>.dealCards = <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">let</span> playerSprite;
            <span class="hljs-keyword">let</span> opponentSprite;
            <span class="hljs-keyword">if</span> (scene.isPlayerA) {
                playerSprite = <span class="hljs-string">'cyanCardFront'</span>;
                opponentSprite = <span class="hljs-string">'magentaCardBack'</span>;
            } <span class="hljs-keyword">else</span> {
                playerSprite = <span class="hljs-string">'magentaCardFront'</span>;
                opponentSprite = <span class="hljs-string">'cyanCardBack'</span>;
            };
            <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">let</span> playerCard = <span class="hljs-keyword">new</span> Card(scene);
                playerCard.render(<span class="hljs-number">475</span> + (i * <span class="hljs-number">100</span>), <span class="hljs-number">650</span>, playerSprite);

                <span class="hljs-keyword">let</span> opponentCard = <span class="hljs-keyword">new</span> Card(scene);
                scene.opponentCards.push(opponentCard.render(<span class="hljs-number">475</span> + (i * <span class="hljs-number">100</span>), <span class="hljs-number">125</span>, opponentSprite).disableInteractive());
            }
        }
    }
}
</code></pre>
<p>With this new class, we're checking whether the client is Player A, and determining what sprites should be used in either case.</p>
<p>Then, we deal cards to our client, while rendering the backs of our opponent's cards at the top the screen and adding them to the opponentCards array that we initialized in our Game scene.</p>
<p>In /src/scenes/game.js, import the Dealer:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Dealer <span class="hljs-keyword">from</span> <span class="hljs-string">'../helpers/dealer'</span>;
</code></pre>
<p>Then replace our dealCards() function with:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.dealer = <span class="hljs-keyword">new</span> Dealer(<span class="hljs-built_in">this</span>);
</code></pre>
<p>Under code block that begins with "this.socket.on('isPlayerA')", add the following:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'dealCards'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealer.dealCards();
            self.dealText.disableInteractive();
        })
</code></pre>
<p>We also need to update our dealText function to match these changes:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerdown'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.socket.emit(<span class="hljs-string">"dealCards"</span>);
        })
</code></pre>
<p>Phew!  We've created a new Dealer class that will handle dealing cards to us and rendering our opponent's cards to the screen.  When the client socket receives the "dealcards" event from the server, it will call the dealCards() function from this new class, and disable the dealText so that we can't just keep generating cards for no reason.</p>
<p>Finally, we've changed the dealText functionality so that when it's pressed, the client emits an event to the server that we want to deal cards, which ties everything together.</p>
<p>Fire up two separate browsers pointed to http://localhost:8080 and hit "DEAL CARDS" on one of them.  You should see different sprites on either screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Client-1.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Client-2.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Note again that if you're having issues with this step, you may have to close one of your browsers and reload the first one to ensure that both clients have disconnected from the server, which should be logged to your command line console.</p>
<p>We still need to figure out how to render our dropped cards in our opponent's client, and vice-versa.  We can do all of that in our game scene!  Update the code block that begins with "this.input.on('drop')" with one line at the end:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'drop'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dropZone</span>) </span>{
            dropZone.data.values.cards++;
            gameObject.x = (dropZone.x - <span class="hljs-number">350</span>) + (dropZone.data.values.cards * <span class="hljs-number">50</span>);
            gameObject.y = dropZone.y;
            gameObject.disableInteractive();
            self.socket.emit(<span class="hljs-string">'cardPlayed'</span>, gameObject, self.isPlayerA);
        })
</code></pre>
<p>When a card is dropped in our client, the socket will emit an event called "cardPlayed", passing the details of the game object and the client's isPlayerA boolean (which could be true or false, depending on whether the client was the first to connect to the server).</p>
<p>Recall that, in our server code, Socket.IO simply receives the "cardPlayed" event and emits the same event back up to all of the clients, passing the same information about the game object and isPlayerA from the client that initiated the event<em>.</em></p>
<p>Let's write what should happen when a client receives a "cardPlayed" event from the server, below the "this.socket.on('dealCards')" code block:</p>
<pre><code class="lang-javascript">         <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'cardPlayed'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">gameObject, isPlayerA</span>) </span>{
            <span class="hljs-keyword">if</span> (isPlayerA !== self.isPlayerA) {
                <span class="hljs-keyword">let</span> sprite = gameObject.textureKey;
                self.opponentCards.shift().destroy();
                self.dropZone.data.values.cards++;
                <span class="hljs-keyword">let</span> card = <span class="hljs-keyword">new</span> Card(self);
                card.render(((self.dropZone.x - <span class="hljs-number">350</span>) + (self.dropZone.data.values.cards * <span class="hljs-number">50</span>)), (self.dropZone.y), sprite).disableInteractive();
            }
        })
</code></pre>
<p>The code block first compares the isPlayerA boolean it receives from the server against the client's own isPlayerA, which is a check to determine whether the client that is receiving the event is the same one that generated it.</p>
<p>Let's think that through a bit further, as it exposes a key component to how our client - server relationship works, using Socket.IO as the connector.</p>
<p>Suppose that Client A connects to the server first, and is told through the "isPlayerA" event that it should change its isPlayerA boolean to <strong>true</strong>.  That's going to determine what kind of cards it generates when a user clicks "DEAL CARDS" through that client.</p>
<p>If Client B connects to the server second, it's never told to alter its isPlayerA boolean, which stays <strong>false</strong>.  That will also determine what kind of cards it generates.</p>
<p>When Client A drops a card, it emits a "cardPlayed" event to the server, passing information about the card that was dropped, and its isPlayerA boolean, which is <strong>true</strong>.  The server then relays all that information back up to all clients with its own "cardPlayed" event.</p>
<p>Client A receives that event from the server, and notes that the isPlayerA boolean from the server is <strong>true</strong>, which means that the event was generated by Client A itself. Nothing special happens.</p>
<p>Client B receives the same event from the server, and notes that the isPlayerA boolean from the server is <strong>true</strong>, although Client B's own isPlayerA is <strong>false</strong>.  Because of this difference, it executes the rest of the code block.  </p>
<p>The ensuing code stores the "texturekey" - basically, the image - of the game object that it receives from the server into a variable called "sprite". It destroys one of the opponent card backs that are rendered at the top of the screen, and increments the "cards" data value in the dropzone so that we can keep placing cards from left to right.  </p>
<p>The code then generates a new card in the dropzone that uses the sprite variable to create the same card that was dropped in the other client (if you had data attached to that game object, you could use a similar approach to attach it here as well).</p>
<p>Your final /src/scenes/game.js code should look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> io <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>;
<span class="hljs-keyword">import</span> Card <span class="hljs-keyword">from</span> <span class="hljs-string">'../helpers/card'</span>;
<span class="hljs-keyword">import</span> Dealer <span class="hljs-keyword">from</span> <span class="hljs-string">"../helpers/dealer"</span>;
<span class="hljs-keyword">import</span> Zone <span class="hljs-keyword">from</span> <span class="hljs-string">'../helpers/zone'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Game</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Phaser</span>.<span class="hljs-title">Scene</span> </span>{
    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-built_in">super</span>({
            <span class="hljs-attr">key</span>: <span class="hljs-string">'Game'</span>
        });
    }

    preload() {
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'cyanCardFront'</span>, <span class="hljs-string">'src/assets/CyanCardFront.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'cyanCardBack'</span>, <span class="hljs-string">'src/assets/CyanCardBack.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'magentaCardFront'</span>, <span class="hljs-string">'src/assets/magentaCardFront.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'magentaCardBack'</span>, <span class="hljs-string">'src/assets/magentaCardBack.png'</span>);
    }

    create() {
        <span class="hljs-built_in">this</span>.isPlayerA = <span class="hljs-literal">false</span>;
        <span class="hljs-built_in">this</span>.opponentCards = [];

        <span class="hljs-built_in">this</span>.zone = <span class="hljs-keyword">new</span> Zone(<span class="hljs-built_in">this</span>);
        <span class="hljs-built_in">this</span>.dropZone = <span class="hljs-built_in">this</span>.zone.renderZone();
        <span class="hljs-built_in">this</span>.outline = <span class="hljs-built_in">this</span>.zone.renderOutline(<span class="hljs-built_in">this</span>.dropZone);

        <span class="hljs-built_in">this</span>.dealer = <span class="hljs-keyword">new</span> Dealer(<span class="hljs-built_in">this</span>);

        <span class="hljs-keyword">let</span> self = <span class="hljs-built_in">this</span>;

        <span class="hljs-built_in">this</span>.socket = io(<span class="hljs-string">'http://localhost:3000'</span>);

        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected!'</span>);
        });

        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'isPlayerA'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.isPlayerA = <span class="hljs-literal">true</span>;
        })

        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'dealCards'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealer.dealCards();
            self.dealText.disableInteractive();
        })

        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'cardPlayed'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">gameObject, isPlayerA</span>) </span>{
            <span class="hljs-keyword">if</span> (isPlayerA !== self.isPlayerA) {
                <span class="hljs-keyword">let</span> sprite = gameObject.textureKey;
                self.opponentCards.shift().destroy();
                self.dropZone.data.values.cards++;
                <span class="hljs-keyword">let</span> card = <span class="hljs-keyword">new</span> Card(self);
                card.render(((self.dropZone.x - <span class="hljs-number">350</span>) + (self.dropZone.data.values.cards * <span class="hljs-number">50</span>)), (self.dropZone.y), sprite).disableInteractive();
            }
        })

        <span class="hljs-built_in">this</span>.dealText = <span class="hljs-built_in">this</span>.add.text(<span class="hljs-number">75</span>, <span class="hljs-number">350</span>, [<span class="hljs-string">'DEAL CARDS'</span>]).setFontSize(<span class="hljs-number">18</span>).setFontFamily(<span class="hljs-string">'Trebuchet MS'</span>).setColor(<span class="hljs-string">'#00ffff'</span>).setInteractive();

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerdown'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.socket.emit(<span class="hljs-string">"dealCards"</span>);
        })

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerover'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealText.setColor(<span class="hljs-string">'#ff69b4'</span>);
        })

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerout'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealText.setColor(<span class="hljs-string">'#00ffff'</span>);
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'drag'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dragX, dragY</span>) </span>{
            gameObject.x = dragX;
            gameObject.y = dragY;
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'dragstart'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject</span>) </span>{
            gameObject.setTint(<span class="hljs-number">0xff69b4</span>);
            self.children.bringToTop(gameObject);
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'dragend'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dropped</span>) </span>{
            gameObject.setTint();
            <span class="hljs-keyword">if</span> (!dropped) {
                gameObject.x = gameObject.input.dragStartX;
                gameObject.y = gameObject.input.dragStartY;
            }
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'drop'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dropZone</span>) </span>{
            dropZone.data.values.cards++;
            gameObject.x = (dropZone.x - <span class="hljs-number">350</span>) + (dropZone.data.values.cards * <span class="hljs-number">50</span>);
            gameObject.y = dropZone.y;
            gameObject.disableInteractive();
            self.socket.emit(<span class="hljs-string">'cardPlayed'</span>, gameObject, self.isPlayerA);
        })
    }

    update() {

    }
}
</code></pre>
<p>Save everything, open two browsers, and hit "DEAL CARDS".  When you drag and drop a card in one client, it should appear in the dropzone of the other, while also deleting a card back, signifying that a card has been played:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Card-Played-1.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Card-Played-2.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>That's it!  You should now have a functional template for your multiplayer card game, which you can use to add your own cards, art, and game logic.</p>
<p>One first step could be to add to your Dealer class by making it shuffle an array of cards and return a random one (hint: check out <a target="_blank" href="https://photonstorm.github.io/phaser3-docs/Phaser.Math.RandomDataGenerator.html#shuffle__anchor">Phaser.Math.RND.shuffle([array])</a>).</p>
<p>Happy coding!</p>
<p>If you enjoyed this article, please consider <a target="_blank" href="https://www.nightpathpub.com/">checking out my games and books</a>, <a target="_blank" href="https://www.youtube.com/msfarzan?sub_confirmation=1">subscribing to my YouTube channel</a>, or <a target="_blank" href="https://discord.gg/RF6k3nB">joining the <em>Entromancy</em> Discord</a>.</p>
<p>M. S. Farzan, Ph.D. has written and worked for high-profile video game companies and editorial websites such as Electronic Arts, Perfect World Entertainment, Modus Games, and MMORPG.com, and has served as the Community Manager for games like <em>Dungeons &amp; Dragons Neverwinter</em> and <em>Mass Effect: Andromeda</em>. He is the Creative Director and Lead Game Designer of <em><a target="_blank" href="https://www.nightpathpub.com/rpg">Entromancy: A Cyberpunk Fantasy RPG</a></em> and author of <em><a target="_blank" href="http://nightpathpub.com/books">The Nightpath Trilogy</a></em>. Find M. S. Farzan on Twitter <a target="_blank" href="https://twitter.com/sominator">@sominator</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to deploy your app to the web using Express.js and Heroku ]]>
                </title>
                <description>
                    <![CDATA[ By Peter Gleeson If you are new to the world of web development, you will spend a lot of time learning how to build static sites with HTML, CSS and JavaScript. You might then start learning how to use popular frameworks such as React, VueJS or Angula... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-deploy-your-site-using-express-and-heroku/</link>
                <guid isPermaLink="false">66d4609f230dff016690585b</guid>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Heroku ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ npm ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Applications ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 02 Mar 2020 11:55:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9c56740569d1a4ca317c.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Peter Gleeson</p>
<p>If you are new to the world of web development, you will spend a lot of time learning how to build static sites with HTML, CSS and JavaScript.</p>
<p>You might then start learning how to use popular frameworks such as <a target="_blank" href="https://reactjs.org/">React</a>, <a target="_blank" href="https://vuejs.org/">VueJS</a> or <a target="_blank" href="https://angular.io/">Angular</a>.</p>
<p>But after trying out a few new ideas and running some sites locally, you might wonder how to actually deploy your site or app. And as it turns out, it can sometimes be difficult to know where to start.</p>
<p>Personally, I find running an Express server hosted on Heroku one of the simplest ways to get going. This article will show you how to do this.</p>
<p><a target="_blank" href="https://www.heroku.com/">Heroku</a> is a cloud platform which supports a number of different programming languages and frameworks.</p>
<p>This is not a sponsored post - there are of course many other solutions available, such as:</p>
<ul>
<li><a target="_blank" href="https://www.digitalocean.com/">Digital Ocean</a></li>
<li><a target="_blank" href="https://aws.amazon.com/">Amazon Web Services</a></li>
<li><a target="_blank" href="https://azure.microsoft.com/en-gb/">Azure</a></li>
<li><a target="_blank" href="https://cloud.google.com/">Google Cloud Platform</a></li>
<li><a target="_blank" href="https://www.netlify.com/">Netlify</a></li>
<li><a target="_blank" href="https://zeit.co/">ZEIT Now</a></li>
</ul>
<p>Check them all out and see which suits your needs best.</p>
<p>Personally, I found Heroku the quickest and easiest to start using "out of the box". The free tier is somewhat limited in terms of resources. However, I can confidently recommend it for testing purposes.</p>
<p>This example will host a simple site using an Express server. Here are the high-level steps:</p>
<ol>
<li>Setting up with Heroku, Git, npm</li>
<li>Create an Express.js server</li>
<li>Create static files</li>
<li>Deploy to Heroku</li>
</ol>
<p>It should take about 25 minutes in total (or longer if you want to spend more time on the static files).</p>
<p>This article assumes you already know:</p>
<ul>
<li>Some HTML, CSS and JavaScript basics</li>
<li>Basic command line usage</li>
<li>Beginner-level Git for version control</li>
</ul>
<p>You can find all the code in <a target="_blank" href="https://github.com/pg0408/lorem-ipsum-demo">this repository</a>.</p>
<h3 id="heading-setting-up">Setting up</h3>
<p>The first step in any project is to set up all the tools you know you'll need.</p>
<p>You'll need to have:</p>
<ul>
<li>Node and npm installed on your local machine (read how to do this <a target="_blank" href="https://nodejs.org/en/download/">here</a>)</li>
<li>Git installed (read <a target="_blank" href="https://www.atlassian.com/git/tutorials/install-git">this guide</a>)</li>
<li>The Heroku CLI installed (<a target="_blank" href="https://devcenter.heroku.com/articles/heroku-cli#download-and-install">here's how to do it</a>)</li>
</ul>
<p><strong>1. Create a new directory and initialise a Git repository</strong></p>
<p>From the command line, create a new project directory and move into it.</p>
<pre><code>$ mkdir lorem-ipsum-demo
$ cd lorem-ipsum-demo
</code></pre><p>Now you are in the project folder, initialise a new Git repository.</p>
<p>⚠️This step is important because <a target="_blank" href="https://devcenter.heroku.com/articles/how-heroku-works#deploying-applications">Heroku relies on Git</a> for deploying code from your local machine to its cloud servers ⚠️</p>
<pre><code>$ git init
</code></pre><p>As a final step, you can create a README.md file to edit at a later stage.</p>
<pre><code>$ echo <span class="hljs-string">"Edit me later"</span> &gt; README.md
</code></pre><p><strong>2. Login to the Heroku CLI and create a new project</strong></p>
<p>You can login to Heroku using the Heroku CLI (command line interface). You will need to have a free Heroku account to do this.</p>
<p>There are two options here. The default is for Heroku to let you login through the web browser. Adding the <code>-i</code> flag lets you login through the command line.</p>
<pre><code>$ heroku login -i
</code></pre><p>Now, you can create a new Heroku project. I called mine <code>lorem-ipsum-demo</code>.</p>
<pre><code>$ heroku create lorem-ipsum-demo
</code></pre><p>Naming your project:</p>
<ul>
<li>Heroku will generate a random name for your project if you don't specify one in the command.</li>
<li>The name will form part of the URL you can use to access your project, so choose one you like. </li>
<li>This also means that you need to choose a unique project name that no one else has used.</li>
<li>It is possible to rename your project later (so don't worry too much about getting the perfect name right now).</li>
</ul>
<p><strong>3. Initialise a new npm project and install Express.js</strong></p>
<p>Next, you can initialise a new npm project by creating a package.json file. Use the command below to do this.</p>
<p>⚠️This step is crucial. Heroku relies on you providing a package.json file to know this is a Node.js project when it builds your app ⚠️</p>
<pre><code>$ npm init -y
</code></pre><p>Next, <a target="_blank" href="https://expressjs.com/en/starter/installing.html">install Express</a>. Express is a widely used server framework for NodeJS.</p>
<pre><code>$ npm install express --save
</code></pre><p>Finally, you are ready to start coding!</p>
<h3 id="heading-writing-a-simple-express-server">Writing a simple Express server</h3>
<p>The next step is to create a file called <code>app.js</code>, which runs an Express server locally.</p>
<pre><code>$ touch app.js
</code></pre><p>This file will be the entry point for the app when it is ready. That means, the one command needed to launch the app will be:</p>
<pre><code>$ node app.js
</code></pre><p>But first, you need to write some code in the file.</p>
<p><strong>4. Edit the contents of app.js</strong></p>
<p>Open <code>app.js</code> in your favourite editor. Write the code shown below and click save.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// create an express app</span>
<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">// use the express-static middleware</span>
app.use(express.static(<span class="hljs-string">"public"</span>))

<span class="hljs-comment">// define the first route</span>
app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req, res</span>) </span>{
  res.send(<span class="hljs-string">"&lt;h1&gt;Hello World!&lt;/h1&gt;"</span>)
})

<span class="hljs-comment">// start the server listening for requests</span>
app.listen(process.env.PORT || <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 is running..."</span>));
</code></pre>
<p>The comments should help indicate what is happening. But let's quickly break the code down to understand it further:</p>
<ul>
<li>The first two lines simply require the Express module and create an instance of an Express app.</li>
<li>The next line requires the use of the <code>express.static</code> middleware. This lets you serve static files (such as HTML, CSS and JavaScript) from the directory you specify. In this case, the files will be served from a folder called <code>public</code>.</li>
<li>The next line uses <code>app.get()</code> to define a URL route. Any URL requests to the root URL will be responded to with a simple HTML message.</li>
<li>The final part starts the server. It either looks to see which port Heroku will use, or defaults to 3000 if you are running locally.</li>
</ul>
<p>⚠️The use of <code>process.env.PORT || 3000</code> in the last line is important for deploying your app successfully ⚠️</p>
<p>If you save <code>app.js</code> and start the server with:</p>
<pre><code>$ node app.js
</code></pre><p>You can visit <a target="_blank" href="http://localhost:3000/">localhost:3000</a> in your browser and see for yourself the server is running.</p>
<h3 id="heading-create-your-static-files">Create your static files</h3>
<p>The next step is to create your static files. These are the HTML, CSS and JavaScript files you will serve up whenever a user visits your project.</p>
<p>Remember in <code>app.js</code> you told the <code>express.static</code> middleware to serve static files from the <code>public</code> directory.</p>
<p>The first step is of course to create such a directory and the files it will contain.</p>
<pre><code>$ mkdir public
$ cd public
$ touch index.html styles.css script.js
</code></pre><p><strong>5. Edit the HTML file</strong></p>
<p>Open <code>index.html</code> in your preferred text editor. This will be the basic structure of the page you will serve to your visitors.</p>
<p>The example below creates a simple landing page for a <a target="_blank" href="https://en.wikipedia.org/wiki/Lorem_ipsum">Lorem Ipsum</a> generator, but you can be as creative as you like here.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css?family=Alegreya|Source+Sans+Pro&amp;display=swap"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/css"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"styles.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</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">h1</span>&gt;</span>Lorem Ipsum generator<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>How many paragraphs do you want to generate?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"quantity"</span> <span class="hljs-attr">min</span>=<span class="hljs-string">"1"</span> <span class="hljs-attr">max</span>=<span class="hljs-string">"20"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"1"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"generate"</span>&gt;</span>Generate<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">id</span>=<span class="hljs-string">"copy"</span>&gt;</span>Copy!<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"lorem"</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">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"script.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</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>
</code></pre>
<p><strong>6. Edit the CSS file</strong></p>
<p>Next up is editing the CSS file <code>styles.css</code>. Make sure this is linked in your HTML file.</p>
<p>The CSS below is for the Lorem Ipsum example. But again, feel free to be as creative as you want.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Alegreya'</span> ;
}

<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Source Sans Pro'</span> ;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">25%</span>;
    <span class="hljs-attribute">text-align</span>: justify;
    <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.7</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
}

<span class="hljs-selector-tag">input</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
    <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-tag">button</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-selector-id">#generate</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#09f</span>;
}

<span class="hljs-selector-id">#copy</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0c6</span>;
}
</code></pre>
<p><strong>7. Edit the JavaScript file</strong></p>
<p>Finally, you might want to edit the JavaScript file <code>script.js</code>. This will let you make your page more interactive.</p>
<p>The code below defines two basic functions for the Lorem Ipsum generator. Yes, I used <a target="_blank" href="https://jquery.com/">JQuery</a> - it's quick and easy to work with.</p>
<pre><code class="lang-javascript">$(<span class="hljs-string">"#generate"</span>).click(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">var</span> lorem = $(<span class="hljs-string">"#lorem"</span>);
    lorem.html(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">var</span> quantity = $(<span class="hljs-string">"#quantity"</span>)[<span class="hljs-number">0</span>].valueAsNumber;
    <span class="hljs-keyword">var</span> data = [<span class="hljs-string">"Lorem ipsum"</span>, <span class="hljs-string">"quia dolor sit"</span>, <span class="hljs-string">"amet"</span>, <span class="hljs-string">"consectetur"</span>];
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; quantity; i++){
        lorem.append(<span class="hljs-string">"&lt;p&gt;"</span>+data[i]+<span class="hljs-string">"&lt;/p&gt;"</span>);
    }
})

$(<span class="hljs-string">"#copy"</span>).click(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> range = <span class="hljs-built_in">document</span>.createRange();
    range.selectNode($(<span class="hljs-string">"#lorem"</span>)[<span class="hljs-number">0</span>]);
    <span class="hljs-built_in">window</span>.getSelection().removeAllRanges();
    <span class="hljs-built_in">window</span>.getSelection().addRange(range);
    <span class="hljs-built_in">document</span>.execCommand(<span class="hljs-string">"copy"</span>);
    <span class="hljs-built_in">window</span>.getSelection().removeAllRanges();
    }
)
</code></pre>
<p>Note that here, the <code>data</code> list is truncated to make it easier to show. In the actual app, it is a much longer list of full paragraphs. You can see the entire file in the repo, or look <a target="_blank" href="http://www.thelatinlibrary.com/cicero/fin1.shtml">here for the original source</a>.</p>
<h3 id="heading-deploying-your-app">Deploying your app</h3>
<p>After writing your static code and checking it all works as expected, you can get ready to deploy to Heroku.</p>
<p>However, there are a couple more things to do.</p>
<p><strong>8. Create a Procfile</strong></p>
<p>Heroku will need a Procfile to know how to run your app.</p>
<p>A Procfile is a "process file" which tells Heroku which command to run in order to manage a given process. In this case, the command will tell Heroku how to start your server listening on the web.</p>
<p>Use the command below to create the file.</p>
<p>⚠️This is an important step, because without a Procfile, Heroku cannot put your server online. ⚠️</p>
<pre><code>$ echo <span class="hljs-string">"web: node app.js"</span> &gt; Procfile
</code></pre><p>Notice that the Procfile has no file extension (e.g., ".txt", ".json"). </p>
<p>Also, see how the command <code>node app.js</code> is the same one used locally to run your server.</p>
<p><strong>9. Add and commit files to Git</strong></p>
<p>Remember you initiated a Git repository when setting up. Perhaps you have been adding and committing files as you have gone.</p>
<p>Before you deploy to Heroku, make sure to add all the relevant files and commit them.</p>
<pre><code>$ git add .
$ git commit -m <span class="hljs-string">"ready to deploy"</span>
</code></pre><p>The final step is to push to your Heroku master branch.</p>
<pre><code>$ git push heroku master
</code></pre><p>You should see the command line print out a load of information as Heroku builds and deploys your app.</p>
<p>The line to look for is: <code>Verifying deploy... done.</code></p>
<p>This shows that your build was successful.</p>
<p>Now you can open the browser and visit your-project-name.herokuapp.com. Your app will be hosted on the web for all to visit!</p>
<h3 id="heading-quick-recap">Quick recap</h3>
<p>Below are the steps to follow to deploy a simple Express app to Heroku:</p>
<ol>
<li>Create a new directory and initialise a Git repository</li>
<li>Login to the Heroku CLI and create a new project</li>
<li>Initialise a new npm project and install Express.js</li>
<li>Edit the contents of app.js</li>
<li>Edit the static HTML, CSS and JavaScript files</li>
<li>Create a Procfile</li>
<li>Add and commit to Git, then push to your Heroku master branch</li>
</ol>
<h3 id="heading-things-to-check-if-your-app-is-not-working">Things to check if your app is not working</h3>
<p>Sometimes, despite best intentions, tutorials on the Internet don't work exactly as you expected.</p>
<p>The steps below should help debug some common errors you might encounter:</p>
<ul>
<li>Did you initialise a Git repo in your project folder? Check if you ran <code>git init</code> earlier. Heroku relies on Git to deploy code from your local machine.</li>
<li>Did you create a package.json file? Check if you ran <code>npm init -y</code> earlier. Heroku requires a package.json file to recognise this is a Node.js project.</li>
<li>Is the server running? Make sure your Procfile uses the correct file name to start the server. Check you have <code>web: node app.js</code> and not <code>web: node index.js</code>.</li>
<li>Does Heroku know which port to listen on? Check you used <code>app.listen(process.env.PORT || 3000)</code> in your app.js file.</li>
<li>Do your static files have any errors in them? Check them by running locally and seeing if there are any bugs.</li>
</ul>
<p>Thanks for reading - if you made it this far, you might want to <a target="_blank" href="http://lorem-ipsum-demo.herokuapp.com/">checkout the finished version</a> of the demo project.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ ⚡ How to Add a GraphQL Server to a RESTful Express.js API in 2 Minutes ]]>
                </title>
                <description>
                    <![CDATA[ By Khalil Stemmler You can get a lot done in 2 minutes, like microwaving popcorn, sending a text message, eating a cupcake, and hooking up a GraphQL server. Yup. If you have an old Express.js RESTful API lying around or you're interested in increment... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/add-a-graphql-server-to-a-restful-express-js-api-in-2-minutes/</link>
                <guid isPermaLink="false">66d45f64a326133d124409f3</guid>
                
                    <category>
                        <![CDATA[ Apollo GraphQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GraphQL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 22 Jan 2020 21:34:31 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/01/ghgojj3wde2074i3n9bu.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Khalil Stemmler</p>
<p>You can get a lot done in 2 minutes, like microwaving popcorn, sending a text message, eating a cupcake, and <strong>hooking up a GraphQL server</strong>.</p>
<p>Yup. If you have an old Express.js RESTful API lying around or you're interested in incrementally adopting GraphQL, we only need 2 minutes to hook it up with a fresh new GraphQL Server.</p>
<p>Ready? Set. Go!</p>
<p>Let's say that your server looked something like the following.</p>
<pre><code class="lang-typescript"><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> { apiRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'./router'</span>;

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> port = process.env.PORT || <span class="hljs-number">5000</span>;

<span class="hljs-comment">// Existing routes for our Express.js app</span>
app.use(<span class="hljs-string">'/api/v1'</span>, apiRouter);

app.listen(port, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`[App]: Listening on port <span class="hljs-subst">${port}</span>`</span>))
</code></pre>
<p>At the root of your project, <code>npm install</code> <a target="_blank" href="https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-express">apollo-server-express</a> as a dependency.</p>
<pre><code>npm install apollo-server-express --save
</code></pre><p>Go to where your Express app is defined and import <code>ApolloServer</code> and <code>gql</code> from <code>apollo-server-express</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ApolloServer, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">'apollo-server-express'</span>
</code></pre>
<p>Next, create an instance of an <code>ApolloServer</code> with the <em>simplest possible</em> GraphQL <strong>type definitions</strong> and <strong>resolvers</strong>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> server = <span class="hljs-keyword">new</span> ApolloServer({
  typeDefs: gql<span class="hljs-string">`
    type Query {
      hello: String
    }
  `</span>,
  resolvers: {
    Query: {
      hello: <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'Hello world!'</span>,
    },
  }
})
</code></pre>
<p>Lastly, use <code>ApolloServer</code>'s <a target="_blank" href="https://www.apollographql.com/docs/apollo-server/api/apollo-server/?utm_source=devto&amp;utm_medium=blog_post&amp;utm_campaign=add_graphl_server_express_2_mins#apolloserverapplymiddleware">applyMiddleware</a> method to pass in our Express.js server.</p>
<pre><code class="lang-typescript">server.applyMiddleware({ app })
</code></pre>
<p>Boom. That's it!</p>
<p>Your code should look something like this.</p>
<pre><code class="lang-typescript"><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> { v1Router } <span class="hljs-keyword">from</span> <span class="hljs-string">'./api/v1'</span>;
<span class="hljs-keyword">import</span> { ApolloServer, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">'apollo-server-express'</span>

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> port = process.env.PORT || <span class="hljs-number">5000</span>;

<span class="hljs-keyword">const</span> server = <span class="hljs-keyword">new</span> ApolloServer({
  typeDefs: gql<span class="hljs-string">`
    type Query {
      hello: String
    }
  `</span>,
  resolvers: {
    Query: {
      hello: <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'Hello world!'</span>,
    },
  }
})

server.applyMiddleware({ app })

app.use(<span class="hljs-string">'/api/v1'</span>, v1Router);

app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`[App]: Listening on port <span class="hljs-subst">${port}</span>`</span>)
})
</code></pre>
<p>If you navigate to <code>localhost:5000/graphql</code>, you should be able to see your GraphQL schema in the GraphQL playground.</p>
<p><img src="https://thepracticaldev.s3.amazonaws.com/i/wd4tiobfydytzdtamlef.png" alt="Alt Text" width="1328" height="982" loading="lazy"></p>
<p>Note: If you want to change the URL that the GraphQL endpoint sits at from <code>/graphql</code> to something else, you can pass in a <code>path</code> option to <code>server.applyMiddleware()</code> with the URL you want, like <code>path: '/specialUrl'</code>. Check out the <a target="_blank" href="https://www.apollographql.com/docs/apollo-server/api/apollo-server/?utm_source=devto&amp;utm_medium=blog_post&amp;utm_campaign=add_graphl_server_express_2_mins#apolloserverapplymiddleware">docs</a> for full API usage.</p>
<p>How simple was that? Is your popcorn finished? ?</p>
<h2 id="heading-summary">Summary</h2>
<p>Here's what we did.</p>
<ol>
<li>Install <code>apollo-server-express</code></li>
<li>Create a <code>new ApolloServer</code></li>
<li>Connect your GraphQL Server with <code>server.applyMiddleware</code></li>
</ol>
<p>I personally really love the fact that Apollo Server is non-intrusive and can be tacked on any project as an alternative way to communicate between services and applications.</p>
<h2 id="heading-where-to-go-from-here">Where to go from here</h2>
<p>If you're new to Apollo and GraphQL, a great way to learn is to actually build something in real life. For that reason, I highly recommend checking out the <a target="_blank" href="https://www.apollographql.com/docs/tutorial/introduction?utm_source=freecodecamp&amp;utm_medium=blog_post&amp;utm_campaign=add_graphl_server_express_2_mins">Apollo Fullstack Tutorial (you can also learn in TypeScript now ?)</a>.</p>
<p>I'm <a target="_blank" href="https://twitter.com/stemmlerjs">Khalil Stemmler</a>, a Developer Advocate at Apollo GraphQL. I teach advanced TypeScript, GraphQL, and Node.js best practices for large-scale applications. Feel free to ping me on <a target="_blank" href="https://twitter.com/stemmlerjs">Twitter</a> if you need help with anything Apollo, TypeScript, or architecture-related. Cheers ?</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
