<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ node - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ node - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 20 May 2026 15:59:45 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/node/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ JavaScript Tutorial – How to Set Up a Front End Development Project ]]>
                </title>
                <description>
                    <![CDATA[ Let’s say you plan to build a website. Before you start, you want to set up a few tools to make your life easier. But which tools should you have? The JavaScript ecosystem is changing so fast that it can be overwhelming to pick the best tools to use.... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-set-up-a-front-end-development-project/</link>
                <guid isPermaLink="false">66c4c80d6e4b60b5b844529e</guid>
                
                    <category>
                        <![CDATA[ eslint ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Front-end Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Prettier ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Hunor Márton Borbély ]]>
                </dc:creator>
                <pubDate>Wed, 12 Feb 2025 21:44:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739318785959/23632d35-1d5a-4797-8c7d-fbad6c80a879.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Let’s say you plan to build a website. Before you start, you want to set up a few tools to make your life easier. But which tools should you have?</p>
<p>The JavaScript ecosystem is changing so fast that it can be overwhelming to pick the best tools to use. To solve this problem, in this article, I’m going to walk you through how to set up a front-end project from scratch.</p>
<p>We'll cover things like must-have editor extensions, adding JavaScript libraries to your project, why you'll use Node.js even if you want to do front-end development, and setting up an application bundler that will generate a live preview as you code in your browser.</p>
<p>You can also <a target="_blank" href="https://www.youtube.com/watch?v=BiBjuphZQxA">watch this article as a video</a> on YouTube. Let's dive in.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-how-to-choose-a-code-editor">How to Choose a Code Editor</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-auto-format-your-code-in-vs-code">How to Auto-format Your Code in VS Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-do-you-need-node-for-a-front-end-project">Why Do You Need Node for a Front-End Project?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-run-your-project">How to Run Your Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-libraries-to-your-javascript-project">How to Add Libraries to Your JavaScript Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-get-coding-tips-while-you-code">How to Get Coding Tips While You Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-initialize-a-project-with-vite">Initialize a Project with Vite</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ol>
<h2 id="heading-how-to-choose-a-code-editor"><strong>How to Choose a Code Editor</strong></h2>
<p>Let’s start with the foundations. As a web developer, you mostly edit text, so you need a good editor. So which one should you use?</p>
<p>Picking an editor is highly based on personal preference, as most editors have very similar features.</p>
<p>If you don’t have a personal preference, I highly recommend <a target="_blank" href="https://vscode.dev/">VS Code</a>. Lately, it has become the de facto standard editor for web development.</p>
<p><a target="_blank" href="https://survey.stackoverflow.co/2024/technology#1-integrated-development-environment"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738945424232/9f41d802-e672-4cd7-ada3-5e8d54000446.png" alt="VS Code is by far the most used editor" class="image--center mx-auto" width="3840" height="2160" loading="lazy"></a></p>
<p>One of the greatest features of all the mainstream editors is that you can add extensions to them. Let’s walk through two extensions that are must-haves.</p>
<h2 id="heading-how-to-auto-format-your-code-in-vs-code"><strong>How to Auto-format Your Code in VS Code</strong></h2>
<p>Prettier is an extension that makes your code more readable and more consistent.</p>
<p>Let’s say you copy-pasted some code, and it’s hard to read. The tabulation is off, a line is too long, and so on. Then you just save the file, and magically, everything looks as it should be.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738948709710/c64a427d-b868-4704-87db-338ebf079c67.png" alt="Prettier formats the code based on best practices" class="image--center mx-auto" width="2280" height="1280" loading="lazy"></p>
<p>This is what Prettier does. It formats the code based on best practices. It doesn't just fix tabulation and wrap the lines. It also adds parentheses to improve code readability, makes sure you are consistent with quotation marks, and many more.</p>
<p>To make it work in VS Code, we must first install the Prettier extension. To do so, go to the extensions panel in VS Code, search for Prettier, and then install it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738955063143/7e8378e5-cf70-4527-9951-b822a745f4bf.png" alt="To install Prettier, go to the Extensions panel, search for Prettier, and install it" class="image--center mx-auto" width="2260" height="1280" loading="lazy"></p>
<p>Installing this extension doesn't format your files automatically on save by default. The default behavior is that once you install this extension, you can right-click within a file and select <strong>Format Document</strong>. You can also select part of a file and choose <strong>Format Selection</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738955102891/2e55eaa7-ec2a-4aca-ad79-b1df82d31e5c.png" alt="Right-click within a file and select Format Document to format it" class="image--center mx-auto" width="2260" height="1280" loading="lazy"></p>
<p>The first time you do this, you need to select the default formatter. VS Code already has a formatter, but it isn’t as powerful as Prettier. Now that you have two formatters, you have to let VS Code know that you want to use Prettier for formatting in the future.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738955119781/d0ef8bc3-54d0-4428-9731-c8857171f3e7.png" alt="The first time, you need to select the default formatter" class="image--center mx-auto" width="2260" height="1280" loading="lazy"></p>
<p>If you wish to auto-format your files when you save them, you need to change the settings. Go to Settings in your VS Code preferences and search for the <strong>Format on Save</strong> option. By default, this is false, so make sure that you tick this checkbox. With this, Prettier formats your files every time you save them. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738955201893/fd3fbec6-5265-4c9b-adab-c1a9d524a635.png" alt="Set the Format On Save option in Settings" class="image--center mx-auto" width="2260" height="1280" loading="lazy"></p>
<p>Formatting can be controversial, though. I highly recommend the default settings, especially for beginners. But if you prefer a different style, you can customize things.</p>
<p>You can indicate with comments to <a target="_blank" href="https://prettier.io/docs/en/ignore.html">ignore specific lines</a> and create a config file to list your preferences.</p>
<p>In the root folder of your project, you can create a file called <strong>.prettierrc</strong> and add a few options. A typical option could be if you prefer single quotes instead of double quotes in your files. Or if you don't want to have semi-colons at the end of your lines.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738955259640/d430386f-de2a-49f3-b252-aee4a9bc1089.png" alt="Adding a custom Prettier configuration" class="image--center mx-auto" width="2260" height="1280" loading="lazy"></p>
<p>With this configuration, you will have a different format once you save your files.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"singleQuote"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"semi"</span>: <span class="hljs-literal">false</span>
}
</code></pre>
<p>There are many more options, of course. If you want to dig deeper, check out <a target="_blank" href="https://prettier.io/docs/en/configuration.html">Prettier's documentation</a><a target="_blank" href="https://prettier.io/docs/en/configuration.html">.</a></p>
<h2 id="heading-why-do-you-need-node-for-a-front-end-project"><strong>Why Do You Need Node for a Front-End Project?</strong></h2>
<p>Before we get to the second must-have extension, we need to set up a few other things. First, we need to talk about Node.js. What is Node, and why do you need it even if you work as a front-end developer?</p>
<p>Node is often associated with backend development, but that's not its only job. Node is a JavaScript runtime – this means it runs JavaScript files outside of the browser.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738949060189/11f39633-76a1-4c38-92ef-88846ffdeb8f.png" alt="You can run JavaScript as part of a website in your browser" class="image--center mx-auto" width="2200" height="1220" loading="lazy"></p>
<p>There are two ways of running JavaScript code. You can either have it as part of a website and run the entire website in a browser, or run only the Javascript file with a runtime like Node.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738949071655/68552f47-63ba-4cfc-9ba0-abb9218a4857.png" alt="You can run JavaScript on its own with Node" class="image--center mx-auto" width="2200" height="1220" loading="lazy"></p>
<p>In the example below, we have a very simple Javascript file that prints "Hello World" to the console. If we have Node installed, we can go to the terminal, navigate to the folder where this file is, and then run it with Node like this. You can see that the file was executed, and the result is in the console.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738947073105/9b56af05-e925-4cd1-9475-b3e49898dd39.png" alt="Node can run JavaScript files on their own" class="image--center mx-auto" width="1280" height="720" loading="lazy"></p>
<p>That's what Node really is: a tool that runs JavaScript files on their own.</p>
<p>JavaScript mostly behaves the same way in both environments. But there are also differences in what JavaScript can do in a browser vs when it runs with Node.</p>
<p>For instance, when running in the browser, JavaScript can access and modify HTML elements. That's the main point of having JavaScript in the first place.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738949133299/b1c6d0a6-ba11-4659-a51e-b72e4bbfde68.png" alt="In the browser, JavaScript can access and modify your HTML elements" class="image--center mx-auto" width="2200" height="1220" loading="lazy"></p>
<p>In Node, there's no HTML file. JavaScript runs on its own. On the other hand, in Node, JavaScript has access to your file system and can read and write your files.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738949113586/e8702a9c-91bf-4096-8768-cf06e4e41082.png" alt="With Node, JavaScript can access and modify your File system" class="image--center mx-auto" width="2200" height="1220" loading="lazy"></p>
<p>For instance, you can run scripts on your machine to initialize a project. We are going to do that. You can run checks on your files and automatically correct the mistakes. Or you can run your test files.</p>
<p>In short, Node lets you run some tools that make your life much easier as a developer.</p>
<p>To install Node, go to <a target="_blank" href="http://nodejs.org">nodejs.org</a> and install it. If you are unsure if you already have Node, you can also go to your terminal and run <strong>node -v</strong> to check. If you get a version number, you have Node.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738949153110/c9e63db3-d52b-4122-a31c-6b871ed2e4b5.png" alt="The website of Node.js" class="image--center mx-auto" width="2200" height="1220" loading="lazy"></p>
<p>So, why do people associate Node primarily with backend development? If the backend code is in JavaScript, the servers must run it somehow without a browser. So yes, if you are a backend developer using JavaScript, then you're most probably going to use Node. But Node is much more than that.</p>
<h2 id="heading-how-to-run-your-project"><strong>How to Run Your Project</strong></h2>
<p>Now that we have Node, we can use a live server to see our site live in the browser as we develop it. Without this, you need to manually refresh the browser window every time you make a change.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738949223269/97bc1d15-4ab6-4204-88d6-257fa471f95d.png" alt="A bundler creates a package that you can run in the browser" class="image--center mx-auto" width="2248" height="1220" loading="lazy"></p>
<p>These tools are called bundlers because they take all your files and turn them into a neat package you can run in the browser. So why do you need them?</p>
<ul>
<li><p>They update your site live in the browser with hot reloading. When you save a file, you immediately see the result in your browser.</p>
</li>
<li><p>As web development tools have evolved, the browser won't understand your files when you use anything more advanced. For instance, are you using React? Then, you're using the JSX syntax – the one that looks like HTML. The JSX syntax is not part of JavaScript. You need a tool to convert it into plain JavaScript. Otherwise, it won't run in your browser. Or are you using TypeScript? You also need to turn that into JavaScript. Or, if you're using SCSS or any other CSS dialect, you need to convert it to plain CSS.</p>
</li>
<li><p>If you import libraries using the JavaScript module system, you need a live server to avoid CORS issues in your browser.</p>
</li>
</ul>
<p>This is what bundlers do. They make sure that you can use modern-day tooling while you're developing your application, and they can also create a final production build that you can publish on the internet.</p>
<p>How do you pick a bundler? There are several options, and essentially, they all do the same thing. The difference between them is in their performance, configuration options, and ease of use.</p>
<p>The most used bundler is still <a target="_blank" href="https://webpack.js.org/">webpack</a>, one of the earliest bundlers in the field. But the one that seems to have taken over the throne and gained more and more popularity is <a target="_blank" href="https://vite.dev/">Vite</a>. Here's a chart from the latest edition of the State of JavaScript survey.</p>
<p><a target="_blank" href="https://2024.stateofjs.com/en-US/libraries/#all_tools_experience"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738947476843/195adbd5-5aba-427e-9b00-c507542235d2.png" alt="The sentiment towards WebPack and Vite" class="image--center mx-auto" width="1540" height="900" loading="lazy"></a></p>
<p>This chart shows that while most developers have used Webpack, they don’t necessarily love it. At the same time, Vite's popularity is rising while still maintaining a positive sentiment.</p>
<p>If you haven't checked out the <a target="_blank" href="https://stateofjs.com/en-US">State of JavaScript</a> survey before, I highly recommend going through it. It gives you an excellent overview of the latest trends with JavaScript. You can learn which tools and libraries people love to use and which they will abandon soon. If you feel overwhelmed by all the changes in the JavaScript ecosystem, the results of this survey can be a great guide.</p>
<p>Once we have a folder for our project, let's navigate to it using our terminal. The easiest way to do this is to open the folder in VS Code and then use the built-in terminal. VS Code will open the terminal with the correct folder.</p>
<p>Then, you can run the project in the terminal with the following command. npx is a command line tool that comes with Node. This is one of the reasons we installed Node: to be able to run commands like this.</p>
<pre><code class="lang-bash">npx vite
</code></pre>
<p>The first time you run this script, it will ask you to install Vite. Say yes. Then, it will show you the URL of a local server, which you can open in a browser to view your project.</p>
<pre><code class="lang-bash">  VITE v6.1.0  ready <span class="hljs-keyword">in</span> 162 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show <span class="hljs-built_in">help</span>
</code></pre>
<p>Now, if you update a file and save the changes, the new version appears in the browser immediately. It generates a live preview of your site until you stop the script or close the terminal. You can keep it running while you're developing your site.</p>
<p>Once you have finished, you can press <strong>Ctrl+C</strong> to stop the script. If it gets desynchronized or you break it with an error, restart it by pressing <strong>Ctrl+C</strong> to stop it and rerunning the same script. So that's how you run a project with Vite.</p>
<h2 id="heading-how-to-add-libraries-to-your-javascript-project"><strong>How to Add Libraries to Your JavaScript Project</strong></h2>
<p>Now that we have Node, we can also use npm or Note Package Manager to add libraries to our project. npm is another tool included with Node. So how does it work?</p>
<p>First, I will walk you through setting things up step by step the manual way so it's clear how the different parts come together. Then, I will show you how to automate most of these steps.</p>
<p>Navigate to your current folder in the terminal and run the following command to initialize the project. This command initializes a package.json file with some metadata.</p>
<pre><code class="lang-bash">npm init --yes
</code></pre>
<p>At this point, this file is not very interesting. It contains the project name, description, version number, and so on. You can change these values.</p>
<p>Now, we can add libraries to our package with the npm install command. In a <a target="_blank" href="https://www.freecodecamp.org/news/render-3d-objects-in-browser-drawing-a-box-with-threejs/">previous article</a>, we used Three.js to render 3D boxes in the browser.</p>
<p>So, as an example, let's install <a target="_blank" href="https://threejs.org/">Three.js</a>. Go to your terminal again, make sure you are in the correct folder, and run the following command:</p>
<pre><code class="lang-bash">npm install three
</code></pre>
<p>This command will install Three.js. But how do you know that the keyword is three here, not Three.js?</p>
<p>When you don’t know the package name, you can just google npm and the name of the library you need. Or, if you don't even know the library name, you can also just search for an npm 3D library and see what Google comes up with.</p>
<p>We can go through each package one by one and pick one based on their capabilities and other info. These packages mostly come with descriptions and quick examples to give you an idea of what the library can do for you.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738949563130/ce677d97-20c4-48ed-a168-b99eb01c84d4.png" alt="How to pick a library to use" class="image--center mx-auto" width="2260" height="1260" loading="lazy"></p>
<p>Another indicator you might want to look for is the weekly downloads and the date of the last update to ensure you select an actively maintained library that people still use.</p>
<p>Once you find the package you are looking for, you can see the command to install it at the top right corner: <code>npm i three</code>. The <code>i</code> here is just shorthand for install. Another way to learn how to install Three.js is to go to its official documentation and check the <a target="_blank" href="https://threejs.org/docs/index.html#manual/en/introduction/Installation">installation guide</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738952468171/7a54e0bb-d88d-428b-911c-cf7a71676562.png" alt="The package.json file after initializing the project and installing Three.js" class="image--center mx-auto" width="2260" height="1260" loading="lazy"></p>
<p>When we install a package, three things happen:</p>
<ul>
<li><p>It adds the latest version of Three.js in our package.json file as a project dependency.</p>
</li>
<li><p>It also creates a package-lock file, which NPM uses to keep track of the dependencies. You should never edit the dependency section of your package.json file or the package-lock file manually. Instead, you should always use commands like npm install and uninstall to add, remove, or update packages.</p>
</li>
<li><p>Finally, the node_modules folder gets created. This folder contains the source code of Three.js. When we import Three.js in our project, it looks for it in this folder. The content of this folder is also something that you should never change. You can look into it if you're interested in the source code of the library that you're using, but you shouldn't change it.</p>
</li>
</ul>
<p>If something goes wrong and you have an error with your dependencies that you can't figure out, then you can always safely delete the node_modules folder and the package-lock file and reinstall your dependencies based on the package.json file. This is not something that you should do, but you can always go back to having a clean slate.</p>
<p>Now that we have installed Three.js, we can create a simple website that displays a 3D box. It's a simple HTML file and a JavaScript file with the code for the 3D box. The key here is that we import Three.js with the import statement in the JavaScript file. This import will use the package that we just installed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738952825715/9828ea05-e75a-4fdf-b1a3-39bd3aa8e380.png" alt="Using Three.js in a sample project" class="image--center mx-auto" width="2546" height="1444" loading="lazy"></p>
<p>Then, we can run the project with Vite. Using imports means that we use the module system now. Running a project with the module syntax can be a bit tricky, as the browser gives you CORS errors by default. However, as we are using Vite to run our project, it works seamlessly without any questions. That’s one of the reasons we use Vite.</p>
<p>If you want to learn more about building 3D games with Three.js, check out my <a target="_blank" href="https://www.freecodecamp.org/news/three-js-tutorial/">earlier article</a> on building a minimalistic car in the browser.</p>
<h2 id="heading-how-to-get-coding-tips-while-you-code"><strong>How to Get Coding Tips While You Code</strong></h2>
<p>The second must-have editor extension is ESLint. While Prettier formatted the code, ESLint gives you coding tips.</p>
<p>It helps you catch basic mistakes and avoid patterns that can cause bugs or be misleading when you try to understand the code.</p>
<p>Here’s a simple example where you declare a variable, but then you have a typo, and you try to use another variable that doesn't exist. ESLint will highlight this for you. It will give you an error both at the variable declaration, saying that you created a variable you don't use, and add the usage, saying that you're trying to use a variable that is not declared. With ESLint, it's easy to spot that you made a typo.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738953388793/c081f406-f964-4c4c-95ef-83cdc8e403df.png" alt="c081f406-f964-4c4c-95ef-83cdc8e403df" class="image--center mx-auto" width="1928" height="1244" loading="lazy"></p>
<p>ESLint, of course, is much more complex than just being able to catch simple errors. There are also less obvious use cases where you might not understand why ESLint is complaining. Then, you can always click the link in the error popup for more details explaining why this pattern is harmful and what you can do to avoid it.</p>
<p>So how can we use ESLint in our projects? This time, we need to have an extension and a configuration. First, as we did with Prettier, we must install the ESLint extension. Go to your extensions, search for ESLint, and install it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738953594259/a6f02e96-069d-4463-8322-86a23c523df3.png" alt="To install ESLint go to the Extensions panel, search for ESLint, and install it" class="image--center mx-auto" width="2260" height="1280" loading="lazy"></p>
<p>We also need to set up ESLint for our project. Before we do that, we need to make sure that the project already has a package.json file. If you don't already have a package.json file, we first have to run <code>npm init --yes</code> to initialize the project. Then, we can generate an ESLint config with the following command:</p>
<pre><code class="lang-bash">npm init @eslint/config@latest
</code></pre>
<p>This script will ask you a few questions. Based on your answers, it will customize the configuration and the rules to check. For most cases, you can use the default option.</p>
<ul>
<li><p>The first time, it will ask for permission to install ESLint. Say yes.</p>
</li>
<li><p>Then, it will ask you whether to use ESLint only for syntax checks or to find problems as well. Choose the second option to get the most help from ESLint.</p>
</li>
<li><p>Then select that you’ll use it with JavaScript modules. Modern web development projects use the JavaScript module system. We use JavaScript modules if we have imports and exports in our code.</p>
</li>
<li><p>Then, it will ask what framework we are using. If we select a framework, it will add framework-specific rules to our project. For instance, using it with React will force us to define the prop types. If we don't use a front-end framework, just vanilla JavaScript, then select "None of these".</p>
</li>
<li><p>Then, it will ask if the project is using TypeScript. Choose based on your preference.</p>
</li>
<li><p>It asks where you run the code. As we have a front-end project, select "Browser".</p>
</li>
<li><p>Then, it will ask if you want to install the additional dependencies that are required for the rules based on your selections. Select yes.</p>
</li>
<li><p>It will also ask what package manager we’re using. We haven't talked a lot about this, but there are multiple package managers that we can use. Select the default: npm.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738953735596/a69f62ac-b5b4-459e-8e78-6956442adfe4.png" alt="Installing ESLint" class="image--center mx-auto" width="2640" height="1624" loading="lazy"></p>
<p>These were a lot of questions. Let's see what happened after we ran this command.</p>
<p>After this step, we have ESLint and some other dependencies based on the answers in the package.json file as development dependencies. Development dependency means that ESLint won't be part of your website's final code, but we need it during development.</p>
<p>ESLint also became part of our node_modules folder, and there are many more packages here now. This is because a dependency can have other dependencies, and the dependencies of the dependencies will also be part of the node_modules folder.</p>
<p>ESLint also created a config file that sets up the rules based on your answers. We will see how to customize the rules.</p>
<p>Now that ESLint is working, you should also see errors in the code once something is off. If you go to your JavaScript file and try to use an undeclared variable, ESLint will highlight the issue.</p>
<p>ESLint is also highly customizable. For instance, we might not want to mark an unused variable as an error. First, we go to the error popup and select the identifier of this type of error. Then, we go to the ESLint config and override this error as follows. Here, we can reduce the severity to a warning or completely turn off this rule.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738953834462/387e36f3-81ee-461c-ae02-3ca614c7b765.png" alt="Turning off ESLint rules in the config" class="image--center mx-auto" width="2640" height="1624" loading="lazy"></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> globals <span class="hljs-keyword">from</span> <span class="hljs-string">"globals"</span>;
<span class="hljs-keyword">import</span> pluginJs <span class="hljs-keyword">from</span> <span class="hljs-string">"@eslint/js"</span>;


<span class="hljs-comment">/** @type {import('eslint').Linter.Config[]} */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> [
  {<span class="hljs-attr">languageOptions</span>: { <span class="hljs-attr">globals</span>: globals.browser }},
  pluginJs.configs.recommended,
  {
    <span class="hljs-attr">rules</span>: {
      <span class="hljs-string">"no-unused-vars"</span>: <span class="hljs-string">"off"</span>, <span class="hljs-comment">// Turn off the No Unused Variables rule</span>
    }
  }
];
</code></pre>
<p>But if you're a beginner, I recommend following the rules that ESLint has by default. Sometimes, it might be annoying to fix all the seemingly harmless issues, but all these rules are based on industry best practices, so it's good to follow them. For more details, check out <a target="_blank" href="https://eslint.org/docs/latest/use/configure/rules">ESLint's documentation</a>.</p>
<h2 id="heading-initialize-a-project-with-vite">Initialize a Project with Vite</h2>
<p>We walked through the step-by-step process of setting up a project. We used <strong>npm init</strong> to initialize the project, manually set up ESLint, and ran our project with Vite. Vite can also initialize the project with a sample application and all the necessary files, which is especially handy when we set up a React project. </p>
<p>Let's see how to set up a vanilla JavaScript and a React project. Let's navigate to a folder in the terminal that will contain our project. We don't need to create a project folder this time because the script will make it for us. Then, run the following command to initialize a project:</p>
<pre><code class="lang-bash">npm create vite@latest
</code></pre>
<p>This command asks you a few questions.</p>
<ul>
<li><p>First, it will ask you for the project name, which will also be the name of the folder created as the project root.</p>
</li>
<li><p>Then, it will ask what framework you use. If you don't use any framework and want plain old JavaScript, choose "Vanilla." If you use React, choose React.</p>
</li>
<li><p>Then, it will ask you if you want to use TypeScript or JavaScript. Here, the default is TypeScript. If you're a beginner in web development, choose JavaScript. If you are more confident with your skills, then go with TypeScript. TypeScript is more complicated, but it has become the industry standard in web development, and most jobs require you to know it. As a beginner, you can go with JavaScript.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738953943915/884e22b0-f096-4338-a392-588b032834f4.png" alt="Creating a project with Vite" class="image--center mx-auto" width="1364" height="966" loading="lazy"></p>
<p>Now, we can navigate to the new folder created and check out what we have here. If you choose a vanilla JavaScript project, you can see it generated a simple application with HTML, CSS, and some JavaScript files. You can change or even delete these. You'll need an HTML file as an entry point, but you can replace the rest.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738954107608/0234f409-6f78-4039-b5d1-133c8cd09530.png" alt="Vite can create a sample application with an HTML, CSS, and JavaScript file" class="image--center mx-auto" width="2624" height="1822" loading="lazy"></p>
<p>We can run this project with <strong>npx vite</strong> as we did before, but there’s a better way. For a real project, we want to add Vite as a development dependency to ensure consistency with the version we are using.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"my-project"</span>,
  <span class="hljs-attr">"private"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"0.0.0"</span>,
  <span class="hljs-attr">"type"</span>: <span class="hljs-string">"module"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"vite"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"vite build"</span>,
    <span class="hljs-attr">"preview"</span>: <span class="hljs-string">"vite preview"</span>
  },
  <span class="hljs-attr">"devDependencies"</span>: {
    <span class="hljs-attr">"vite"</span>: <span class="hljs-string">"^6.1.0"</span>
  }
}
</code></pre>
<p>The package.json file shows that Vite has been added as a development dependency. To use this hardcoded version, we first have to install it via <code>npm install</code>. This command installs all the dependencies listed in the package.json file.</p>
<pre><code class="lang-bash">npm install
</code></pre>
<p>This package.json file now also has a scripts section. This section can define scripts to run your app locally, create a production build, or test your application. You can run them with <strong>npm run</strong>. So, for instance, to run the application, you can open the terminal with the correct folder and run the following command.</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>This runs the script labeled as “dev” in the scripts section, which will run the Vite version we just installed with <strong>npm install</strong>.</p>
<p>Vite does not install ESLint when you create a vanilla project, but you can always install it manually, as we did before with <strong>npm init @eslint/config@latest</strong>.</p>
<p>If you choose React as a framework when we initialize the project, we will have a couple more files. For instance, we have an ESLint config with the recommended React settings. We also have a Vite config that enables us to use React and a sample application that we can run.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738954174340/26c5a9a5-b983-4ed7-8e43-fbab4400e08b.png" alt="Vite can also create a React project for you" class="image--center mx-auto" width="2624" height="1822" loading="lazy"></p>
<p>To run this app, we need to install the dependencies. So, let's go to the terminal and run <code>npm install</code>. This will install all the dependencies, including React. Then, we can run this app with <code>npm run dev</code>, and we will have a working React application.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this article, we set up and run a front-end project with Vite. We also covered how to find and add dependencies, how to have consistent and automatic formatting with Prettier, and how to avoid bugs with ESLint.</p>
<p>What happens once you finish developing your app? How do you upload it to the web and share it with the world? That's the topic of a future article.</p>
<h3 id="heading-subscribe-for-more-tutorials-on-web-development"><strong>Subscribe for more tutorials on Web Development:</strong></h3>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/BiBjuphZQxA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Deploy Your Node.js App on Azure ]]>
                </title>
                <description>
                    <![CDATA[ The advent of cloud computing marked a turning point in the field of technology. It provides easier access for users across the globe to web and mobile applications and services.  Modern-day computing services also provide a wide range of features wh... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-deploy-node-js-app-on-azure/</link>
                <guid isPermaLink="false">66bb58c75a83db22bea9843b</guid>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Hosting ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwatobi ]]>
                </dc:creator>
                <pubDate>Wed, 17 Jul 2024 11:56:43 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/awsP.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The advent of cloud computing marked a turning point in the field of technology. It provides easier access for users across the globe to web and mobile applications and services. </p>
<p>Modern-day computing services also provide a wide range of features which make web apps easier to use and more efficient. So it's important for developers to have a basic understanding of how the cloud works.</p>
<p>This article is a beginner's guide to deploying backend applications to the cloud. We'll use the Azure platform as our cloud infrastructure and Node.js/Express for the backend web application. Before we go on, here are a few requirements:</p>
<ul>
<li>Basic understanding of cloud computing (you can check out <a target="_blank" href="https://dev.to/oluwatobi2001/introduction-to-cloud-computing-the-models-benefits-risks-implementation-and-popular-tools-2loh">this article</a> to learn more about that).</li>
<li>Knowledge of JavaScript.</li>
<li>VS Code.</li>
</ul>
<p>With that, let's get started.</p>
<h2 id="heading-introduction-to-azure">Introduction to Azure</h2>
<p>Azure is a cloud computing platform developed by Microsoft that acts as a server for deploying and hosting web applications, databases, file storage, and so on. </p>
<p>Compared to other cloud computing services, it is quite beginner-friendly and has an actively growing user base. Let’s explore the Azure portal.</p>
<h2 id="heading-how-to-set-up-azure-account">How to Set Up Azure Account</h2>
<p>Signing up on the Azure platform is the first step to hosting your application.   First, navigate to <a target="_blank" href="https://azure.microsoft.com/en-us/get-started/azure-portal">the website</a> and complete the signup process.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-36.png" alt="Image" width="600" height="400" loading="lazy">
<em>Azure sign in page</em></p>
<p>After signing up, you'll have access to the management console of the Azure application where all our activities can be carried out.</p>
<p>Before we go on, here are some of the services we'll be getting familiar with on this platform.</p>
<ul>
<li>Azure Resource groups</li>
<li>Azure app services</li>
<li>Storage accounts</li>
<li>SQL databases</li>
<li>Virtual networks</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/serc3.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Azure services</em></p>
<p>Congratulations on successfully creating your Azure account.</p>
<h2 id="heading-deployment-options-on-azure">Deployment Options on Azure</h2>
<p>As a cloud computing platform, Azure boasts of its wide versatility. Depending on your skill level or preference, you can deploy web applications to Azure via the following options:</p>
<ul>
<li>Azure CLI</li>
<li>Azure Virtual machines</li>
<li>Azure Functions</li>
<li>Azure Kubernetes Service</li>
<li>Azure Storage.</li>
<li>Azure DevOps</li>
<li>Azure portal service</li>
</ul>
<p>We'll utilize the Azure portal service for this tutorial and use its VS Code integration to deploy a simple Node.js application to the Azure cloud.</p>
<h2 id="heading-how-to-set-up-the-backend-application">How to Set Up the Backend Application</h2>
<p>We'll create our web application using Node.js via the command line and Visual Studio Code.</p>
<p>Firstly, navigate to the folder where your app will be created and initialize a Node project by executing <code>npm init</code></p>
<p>Next, initialize the app by installing the <code>Express</code> framework. This can be done via <code>npm i express</code>. </p>
<p>Go on and paste the sample code for this tutorial:</p>
<pre><code><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> app = express();

app.use(express.json());

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

app.listen(process.env.PORT || <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 "</span> + (process.env.PORT || <span class="hljs-number">5000</span>));
});
</code></pre><p>The code above outputs <code>Hello World</code> whenever it is executed.</p>
<h2 id="heading-application-deployment">Application Deployment</h2>
<p>The backend code we wrote in the preceding paragraph will be deployed to Azure via the use of Azure’s VS Code extension.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/webVs.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>VS Code homepage</em></p>
<p>Navigate to the Extensions tab, search for Azure App Services and install the extension. On successful installation, an Azure widget will appear on your taskbar where you can sign in to the Azure cloud.  </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/azure-app-service.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Extensions marketplace</em></p>
<p>Subsequently, we'll be creating a cloud-based web application in which our Node.js code will later be deployed.</p>
<p>On the Azure resources tab, clicking the <code>plus</code> icon will display a drop-down menu where various development options can be seen. We'll be clicking on the Azure app services option.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/res-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Azure drop down menu</em></p>
<p>After clicking that, a prompt will pop up asking for a unique name for the cloud application. In my case, I went with newApp777.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/newa7.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>creating a web application</em></p>
<p>However, you can use any other name you so wish. Subsequently, you will need to select the backend language of your choice. Any version of Node.js will be compatible with our application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/newStack.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>web stacks available</em></p>
<p>Also, the F1 service option will be used for this tutorial. However, you can pick anyone you so desire.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/newTier.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Various Azure tiers</em></p>
<p>On successful completion, your application will be created on the Azure portal.</p>
<p>Now to the crux of the matter. Let's install our Node.js code on this web application. </p>
<p>We'll click on the code folder which provides us with options to automatically deploy our code to an Azure web app service.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-35.png" alt="Image" width="600" height="400" loading="lazy">
<em>Deployment dropdown menu</em></p>
<p>As soon as this is done, the list of the cloud servers on your Azure account will be shown. You can then select the new app we just created.  </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/sear.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>app deployment</em></p>
<p>Your backend code should then be deployed on the NewApp cloud server we created. On successful completion, you'll receive a success message with a link to your cloud application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/pro.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>command prompt interface</em></p>
<p>Congratulations, you have successfully hosted your first web application. Navigate <a target="_blank" href="https://newapp777.azurewebsites.net/">here</a> to see the hosted application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/wevpage.PNG" alt="Azure app" width="600" height="400" loading="lazy">
<em>The application webpage</em></p>
<h2 id="heading-additional-information">Additional Information</h2>
<p>So far, we have covered the basics of deploying an application via the use of VS code extensions on Azure portal services. As you progress in the field of cloud computing, other interesting fields can also be explored such as:</p>
<ul>
<li>App monitoring with Azure Monitor.</li>
<li>Azure app networking essentials.</li>
<li>Azure MySQL database integration.</li>
<li>Node JS serverless functions deployment.</li>
</ul>
<p>You can also interact with me on my blog and check out my other articles <a target="_blank" href="https://linktr.ee/tobilyn77">here</a>. Till next time, keep on coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How To Use Node Version Manager In Your React Projects ]]>
                </title>
                <description>
                    <![CDATA[ In this guide,  you'll learn how to effectively manage multiple Node versions for different projects using Node Version Manager (NVM). Whether you're developing React, Angular, Vue.js, or Node applications, you can always use NVM to set up the projec... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-nvm-in-react-projects/</link>
                <guid isPermaLink="false">66bc4d1ecd8a65d579e3a966</guid>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Matéu.sh ]]>
                </dc:creator>
                <pubDate>Wed, 21 Feb 2024 13:51:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/React---NVM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this guide,  you'll learn how to effectively manage multiple Node versions for different projects using Node Version Manager (NVM). Whether you're developing React, Angular, Vue.js, or Node applications, you can always use NVM to set up the project and tailor it down to a specific Node version.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we start, you need to have some <a target="_blank" href="https://www.freecodecamp.org/news/command-line-commands-cli-tutorial/">basic command line knowledge</a>. Nothing sophisticated, but make sure you've used it before reading this article otherwise you might feel a bit lost.</p>
<h2 id="heading-what-is-nvm">What Is NVM?</h2>
<p>Node Version Manager (NVM) is a command-line utility that enables you to manage multiple installations of Node.js and easily switch between them. </p>
<p>Whether you need to work on projects requiring different Node.js versions or want to experiment with the latest releases without affecting your existing setups, NVM provides an easy way to do so.</p>
<h2 id="heading-why-do-you-need-multiple-node-version">Why Do You Need Multiple Node Version?</h2>
<p>Nowadays, companies often build their application in the microservice architecture. This means that applications tend to be divided into many smaller services, where every service has its dedicated role. </p>
<p>It might sound like an over-engineering but there are a few benefits from this approach. In some cases, companies decide to build their applications using micro services to reach high availability and allow deployments without downtime. In the end, they can deploy one service at a time. </p>
<p>This approach also has downsides related to complexity and managing multiple projects. Imagine that your application is divided into many micro services, where the first one was built over 5 years ago. </p>
<p>The service is likely running on a legacy version of Node.js. In an ideal world, you would have to upgrade Node version to the newest version but it isn't always possible. In the end, the users' satisfaction comes first, and if they need new features, their needs must be fulfilled first. </p>
<p>Sometimes, a new feature might require you to introduce a new micro service. In this case, you should always try to use the newest Node version available. I will show you how to install multiple Node versions on your machine.</p>
<h2 id="heading-but-i-am-a-front-end-developer">But I Am a Front End Developer</h2>
<p>You'll still need NVM as a front end developer.</p>
<p>Nowadays, every JavaScript library and framework requires Node runtime and that's why you should manage Node versions for the frontend projects as well. The example project we will be using in this article is built in React 18 &amp; Next.js.</p>
<p>Let's get started.</p>
<h2 id="heading-how-to-install-nvm-on-linux-and-mac">How to Install NVM on Linux and Mac</h2>
<p>Installation on Linux and Mac is ultra simple. </p>
<p>Just open your terminal and run the following command:</p>
<pre><code class="lang-sh">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
</code></pre>
<p>This script will configure NVM on your machine and you will be able to use immediately. Nothing else is required. </p>
<p>Just try to run <code>nvm</code> command in your terminal, and you should see the following output: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-19-at-21.57.31.png" alt="Image" width="600" height="400" loading="lazy">
<em>nvm command output</em></p>
<p>If you see something like <code>nvm: command not found</code> then you can run these commands:</p>
<pre><code class="lang-sh"><span class="hljs-built_in">source</span> ~/.bashrc
<span class="hljs-built_in">source</span> ~/.zshrc
</code></pre>
<p>It's expected that one of them fails. This commands will reload you bash / zsh profile and enable NVM in your command prompt. </p>
<h2 id="heading-how-to-install-nvm-on-windows">How to Install NVM on Windows</h2>
<p>You can easily install NVM on Windows – just <a target="_blank" href="https://github.com/coreybutler/nvm-windows/releases">open the nvm-windows repository on GitHub</a>, scroll down to the <strong>Assets</strong> section, and download the <code>nvm-setup.exe</code> file.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-19-at-22.04.05.png" alt="Image" width="600" height="400" loading="lazy">
<em>NVM Windows repository</em></p>
<p>Now the installer file will be downloaded. Once the download is completed, double-click on the <code>nvm-setup.exe</code> file and follow the instructions:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/nvm-installer.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>NVM for Windows Installer by <a target="_blank" href="https://github.com/coreybutler">Corey Butler</a></em></p>
<p>After the installation, open PowerShell and run <code>nvm</code> command, you should see the following output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/nvm-1.1.8-screenshot.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>NVM in PowerShell by <a target="_blank" href="https://github.com/coreybutler">Corey Butler</a></em></p>
<p>If <code>nvm</code> command returns <code>command not found</code> you should restart your computer to refresh your user settings.</p>
<h2 id="heading-how-to-set-node-version-for-your-project">How to Set Node Version For Your Project</h2>
<p>Now, we are reaching the root of this guide – setting dedicated Node version for your project. </p>
<p>First, create a <strong>.nvmrc</strong> file in your project root folder and specify the expected Node version. </p>
<p>It is <code>20.10.0</code> in my case:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-19-at-22.24.11.png" alt="Image" width="600" height="400" loading="lazy">
<em>Node version in .nvmrc file</em></p>
<p>Now open your terminal and navigate to your project and run the <code>nvm use</code> command. NVM will automatically load the expected Node version by your project. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-19-at-22.27.04.png" alt="Image" width="600" height="400" loading="lazy">
<em>nvm use command</em></p>
<p>If you don't have the expected version on your machine, you'll be prompted to install it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-19-at-22.28.46.png" alt="Image" width="600" height="400" loading="lazy">
<em>prompt to install node version</em></p>
<p>In this case, you need to install required Node version by running <code>nvm install x.y.z</code>. Replace <code>x.y.z</code> with the expected Node version. It was <code>20.10.0</code>, in my case.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Working on multiple projects can be a hassle, especially when they require different Node versions. However, with NVM, changing the Node version is as quick as blinking an eye. </p>
<p>You should always use it, whether you're working alone on your personal project or with multiple colleagues on a large enterprise application.</p>
<p>If this article helped you, please share it on your social media or give me a <a target="_blank" href="https://twitter.com/msokola">shout-out on Twitter</a>. Thank you!</p>
<h2 id="heading-learn-react-18-amp-nextjs"><strong>Learn React 18 &amp; Next.js</strong></h2>
<p>This article is a part of my React and Next.js course on Udemy. I will help you to get started with React and Next.js by creating a 2048 Game with awesome animations. I believe creating games makes learning more fun, and you'll have something cool to show your friends.</p>
<p>👇👇👇👇</p>
<h3 id="heading-enroll-to-my-course-on-udemyhttpswwwudemycomcourse2048-in-react-and-nextjsreferralcodeac3fd6336bab9c402106"><strong>🧑‍🎓</strong> Enroll to <strong>my <a target="_blank" href="https://www.udemy.com/course/2048-in-react-and-nextjs/?referralCode=AC3FD6336BAB9C402106">course on Udemy</a></strong></h3>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Install Node.js on Ubuntu – Node Linux Installation Guide ]]>
                </title>
                <description>
                    <![CDATA[ If you are a web developer working on the frontend or the backend, you'll want to have Node.js installed on your system.  But if you use the typical sudo apt install nodejs command, it may install a very old version of Node which can be troublesome f... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-install-node-js-on-ubuntu/</link>
                <guid isPermaLink="false">66b902ede26f442bbe4b2770</guid>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ubuntu ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Md. Fahim Bin Amin ]]>
                </dc:creator>
                <pubDate>Fri, 20 Oct 2023 19:29:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/programming-development-technology-work-at-night-2022-01-19-00-14-46-utc-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you are a web developer working on the frontend or the backend, you'll want to have <strong>Node.js</strong> installed on your system. </p>
<p>But if you use the typical <code>sudo apt install nodejs</code> command, it may install a very old version of Node which can be troublesome for you.</p>
<p>So you'll want to install a specific version, which requires a different command. This will install the LTS (Long-Term Support) version of Node which is useful for devs because it has a longer period for support. </p>
<p>Today, I am going to show you how you can install the latest LTS version of Node on your Ubuntu operating system. </p>
<p>This processes will work on any kind of Debian-based Linux operating system (Ubuntu, Mint, Zorin, Debian, Elementary OS, and so on). It'll work whether you are using that as your main operating system, secondary operating system on dual boot, WSL on Windows, or using in a virtual machine (VMware Workstation, VirtualBox, and so on).</p>
<h2 id="heading-video-tutorial">Video Tutorial</h2>
<p>I have also created a complete video to show you the process step-by-step. You can watch it here:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/g4Enhyn1o-4" 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>At the time of writing this article, the latest LTS version for Node is 18.18.2.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-141242.png" alt="Image" width="600" height="400" loading="lazy">
<em>Node download page showing current LTS version</em></p>
<p>When you install Node following the instructions in this article, it will install the latest LTS version of Nodejs automatically. So you'll be safe without any hassle if you simply follow this article and the accompanying video.</p>
<h2 id="heading-update-your-operating-system">Update Your Operating System</h2>
<p>First, you'll want to ensure that you have installed all the updates beforehand. I like to work in the terminal mostly, so I'll install the updates using the terminal directly. </p>
<p>For updating to the latest versions of all the relevant packages, use <code>sudo apt update</code> in the terminal. Use your password when it asks for that.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-104647.png" alt="Image" width="600" height="400" loading="lazy">
<em>Updating all relevant packages</em></p>
<p>Now use <code>sudo apt upgrade -y</code> to upgrade all the upgradable packages.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-120347.png" alt="Image" width="600" height="400" loading="lazy">
<em>Upgrading all relevant packages</em></p>
<h2 id="heading-install-curl">Install CURL</h2>
<p>We're using the <strong>Node Version Manager (NVM)</strong> here to install Node. There are various advantages when we install Node and npm using the NVM as it also allows us to manage multiple versions of Node.js on our system altogether. </p>
<p>First, you'll need to install <code>curl</code> if it's not installed on your system already. You can install curl by using the command below:</p>
<pre><code class="lang-bash">sudo apt install curl -y
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-122355.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing CURL</em></p>
<h2 id="heading-how-to-install-nodejs">How to Install Node.js</h2>
<p>Now you'll need to follow these steps in order to ensure that you've installed Node.js successfully on your system.</p>
<h3 id="heading-install-node-version-manager-nvm">Install Node Version Manager (NVM)</h3>
<p>Install the Node Version Manager (NVM) by using the following command:</p>
<pre><code class="lang-bash">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-122423.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing the Node Version Manager (NVM)</em></p>
<p>When you run this specific command, the curl downloads the NVM installation script from that specific URL. Afterward, bash executes the same script for installing NVM.</p>
<h3 id="heading-activate-nvm">Activate NVM</h3>
<p>Activate the NVM using the command below:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> ~/.bashrc
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-122517.png" alt="Image" width="600" height="400" loading="lazy">
<em>Activating the Node Version Manager (NVM)</em></p>
<h3 id="heading-install-the-latest-lts-version-of-node">Install the latest LTS version of Node</h3>
<p>Install the latest Long Term Support version of Node by using the command below:</p>
<pre><code class="lang-bash">nvm install --lts
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-122656.png" alt="Image" width="600" height="400" loading="lazy">
<em>Command for installing the latest LTS version of Node.js</em></p>
<p>It installs the latest version of the LTS release of Node by default. </p>
<h3 id="heading-make-the-default-lts-version-as-nvm">Make the default LTS version as NVM</h3>
<p>We have installed the latest LTS version of Node, but we also need to set the default version of NVM so that it gets used by default whenever we need it. You can use the command below to do that. Make sure to change the version to the exact LTS version you have installed on your system just now. </p>
<pre><code class="lang-bash">nvm <span class="hljs-built_in">alias</span> default 18.18.2
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-122842.png" alt="Image" width="600" height="400" loading="lazy">
<em>Selecting the appropriate Node version as the default version</em></p>
<p>If your LTS version is something like <code>24.1.2</code> then the command would be like below:</p>
<pre><code class="lang-bash">nvm <span class="hljs-built_in">alias</span> default 24.1.2
</code></pre>
<h3 id="heading-confirm-that-node-was-installed">Confirm that Node was installed</h3>
<p>Use the command below to check whether the default version is the exact version you just installed:</p>
<pre><code class="lang-bash">node -v npm -v
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-122937.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showing the current version of Node installed</em></p>
<h2 id="heading-how-to-set-up-the-nodejs-environment">How to Set Up the Node.js Environment</h2>
<p>After installing Node and NPM, you need to set up the Node environment by creating a new Node project.</p>
<p>Use the command below to create a new directory/folder where you want to test a simple "Hello World" type Node project.</p>
<pre><code class="lang-bash">mkdir my-node-project
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-123101.png" alt="Image" width="600" height="400" loading="lazy">
<em>Creating a new directory/folder to test a simple "Hello World" program on Node</em></p>
<p>Navigate to the <code>my-node-project</code> directory by using the command below:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-node-project
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-123148.png" alt="Image" width="600" height="400" loading="lazy">
<em>Changing the directory to enter into that newly created directory/folder</em></p>
<p>Initialize the new Node project like this:</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<p>This command will create a "package.json" file containing your project's metadata and dependencies. Here is the JSON output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-123304-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initializing npm in the folder</em></p>
<p>The JSON output is below:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"my-node-project"</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">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</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>
}
</code></pre>
<p>Now run the setup with the simple command. For this, I am going to create a new file called <code>app.js</code> using the <strong>nano</strong> text editor in the terminal.</p>
<pre><code class="lang-bash">sudo nano app.js
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-123550.png" alt="Image" width="600" height="400" loading="lazy">
<em>Opening app.js file in nano</em></p>
<p>Once the text editor opens, type the below code:</p>
<pre><code class="lang-bash">console.log(<span class="hljs-string">"Hello, Node.js from Ubuntu!"</span>);
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-123710.png" alt="Image" width="600" height="400" loading="lazy">
<em>Writing a simple console.log code in the app.js file using nano</em></p>
<p>Use <code>Ctrl</code>+ <code>O</code> to save the file. Use <code>Enter</code> to save the file as <code>app.js</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-123831.png" alt="Image" width="600" height="400" loading="lazy">
<em>Save the app.js file with the newly added line of code</em></p>
<p>Use <code>Ctrl</code> + <code>X</code> to return to the bash terminal again.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-123907.png" alt="Image" width="600" height="400" loading="lazy">
<em>Returning to the terminal again</em></p>
<p>Now, it is time to check the output and see whether it's working or not.</p>
<p>Use the command below:</p>
<pre><code class="lang-bash">node app.js
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-124010.png" alt="Image" width="600" height="400" loading="lazy">
<em>Running the app.js file using Node</em></p>
<p>It is working!</p>
<p>We have successfully installed the latest LTS release of Node on our Ubuntu/Debian-based Linux operating system.</p>
<p>Cheers! 🥂</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Thank you so much for reading the entire article till now.</p>
<p>If you have enjoyed the procedures step-by-step, then don't forget to let me know on <a target="_blank" href="https://twitter.com/Fahim_FBA">Twitter/X</a> or <a target="_blank" href="https://www.linkedin.com/in/fahimfba/">LinkedIn</a>.</p>
<p>You can follow me on <a target="_blank" href="https://github.com/FahimFBA">GitHub</a> as well if you are interested in open source. Make sure to check <a target="_blank" href="https://fahimbinamin.com/">my website</a> (<a target="_blank" href="https://fahimbinamin.com/">https://fahimbinamin.com/</a>) as well! </p>
<p>If you like to watch programming and technology-related videos, then you can check my <a target="_blank" href="https://www.youtube.com/@FahimAmin?sub_confirmation=1">YouTube channel</a>, too.</p>
<p>All the best for your programming and development journey. 😊</p>
<p>You can do it! Don't give up, never! ❤️</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Full Stack Project Tutorial – Create a Recipe App Using React, Node.js and PostgreSQL ]]>
                </title>
                <description>
                    <![CDATA[ In this in-depth tutorial, we'll build a full stack recipe app from scratch, using React, Node.js, Postgres and the Spoonacular API. We'll cover features such as: Building an API server in Node Integrating securely with a 3rd party API Interacting w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/full-stack-project-create-a-recipe-app-using-react-node-js/</link>
                <guid isPermaLink="false">66c8c8d4c4cede4e0083f737</guid>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgres ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chris Blakely ]]>
                </dc:creator>
                <pubDate>Thu, 19 Oct 2023 20:31:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/react-note-photo-gallery-app--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this in-depth tutorial, we'll build a full stack recipe app from scratch, using React, Node.js, Postgres and the Spoonacular API. We'll cover features such as:</p>
<ul>
<li>Building an API server in Node</li>
<li>Integrating securely with a 3rd party API</li>
<li>Interacting with a Postgres database using Prisma</li>
<li>Making API requests from React</li>
<li>Creating reusable components</li>
<li>Working with pagination</li>
<li>Working with UI elements such as tabs, image grids, modals and styling</li>
</ul>
<p>Let's dive in.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#try-it-yourself-first">GitHub Repositor</a>ies</li>
<li><a class="post-section-overview" href="#heading-video-tutorial">Video Tutorial</a></li>
<li><a class="post-section-overview" href="#heading-project-architecture">Project Architecture</a></li>
<li><a class="post-section-overview" href="#heading-how-to-setup-the-backend">How to Setup the Backend</a></li>
<li><a class="post-section-overview" href="#heading-how-to-setup-the-database-and-prisma">How to Setup the Database and Prisma</a></li>
<li><a class="post-section-overview" href="#heading-how-to-get-and-secure-a-spoonacular-api-key">How to Get and Secure a Spoonacular API Key</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-search-endpoint">How to Create the Search Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-setup-the-frontend">How to Setup the Frontend</a></li>
<li><a class="post-section-overview" href="#heading-how-to-call-the-search-api-and-display-results-on-the-frontend">How to Call the Search API and Display Results on the Frontend</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-search-input-and-recipe-card-component">How to Create the Search Input and Recipe Card Component</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-pagination-and-view-more-functionality">How to Build the Pagination and View More Functionality</a></li>
<li><a class="post-section-overview" href="#how-to-build-the-recipe-summary-and-build-more-component">How to Build the Recipe Summary Modal Component</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-endpoints-to-getcreatedelete-favorite-recipes">How to Create Endpoints to Get/Create/Delete Favorite Recipes</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-favorites-functionality-to-the-frontend">How to Add Favorites Functionality to the Frontend</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-cssstyling">How to Adding CSS/Styling</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Since we will be focusing on how to build a project, there are a few prerequisites that will be needed to get the most out of this tutorial:</p>
<ul>
<li>Some knowledge about web development concepts (frontend, backend, databases, API's, REST).</li>
<li>Some knowledge of JavaScript (variables, functions, objects, arrays, and so on).</li>
<li>Basic understanding on React (how to create components, add styles, work with state).</li>
<li>Basic understanding on Node.js/Express (working with APIs).</li>
</ul>
<h2 id="heading-github-repositories">GitHub Repositories</h2>
<h3 id="heading-completed-code">Completed Code</h3>
<p><a target="_blank" href="https://github.com/chrisblakely01/react-node-recipe-app">You can find the completed code on GitHub by clicking here,</a> or clone the repo:</p>
<pre><code>git clone git@github.com:chrisblakely01/react-node-recipe-app.git
</code></pre><h3 id="heading-starter-code">Starter Code</h3>
<p>If you want to save some time and skip the initial setup, <a target="_blank" href="https://github.com/chrisblakely01/react-node-recipe-app-starter">you can find the starter code here.</a> This has a skeleton frontend/backend project already setup, as well as the basic layout and CSS. Or clone the repo:</p>
<pre><code>git clone git@github.com:chrisblakely01/react-node-recipe-app-starter.git
</code></pre><h2 id="heading-video-tutorial">Video Tutorial</h2>
<p>If you'd like to learn from the video version as well, here it is:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/5wwaQ4GiSNU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-project-architecture">Project Architecture</h2>
<p>Here's a diagram that illustrates how the various components of our app will interact with each other:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/recipe-app-architecture.png" alt="recipe-app-architecture" width="600" height="400" loading="lazy">
<em>Diagram illustrating the various components of the app</em></p>
<p>We will have a React front end and a Node backend. These two will communicate through specific endpoints. We will establish five endpoints, all housed within our backend.</p>
<p>We can categorize these endpoints into two distinct groups. The first group will cater to recipe searches. It will invoke the recipe API and return the results based on a given search query. Our front end will initiate a call to our backend, which will then relay the search request to the recipe API. </p>
<p>We choose not to call the recipe API directly from our front end because it requires an API key—a form of authentication similar to a password. Exposing this key in our front end code could lead to unauthorized access if someone delves into the code through their browser to retrieve the API key.</p>
<p>It's a more secure practice to house the API key on our backend within environment variables. From there, we can call the recipe API and then transmit the response back to our front end. </p>
<p>This approach aligns with common practices in production environments. It also offers the flexibility to modify the data on the backend, if necessary, before sending it back to the front end. And it enhances performance, as the UI will not have to manage multiple API requests to and from the recipe API.</p>
<p>That's the essence of how our search functionality will operate. We'll also have several endpoints to add, create, and delete favorites. These favorites will be stored in our own database, providing a clear picture of what we aim to build.</p>
<h2 id="heading-how-to-setup-the-backend">How to Setup the Backend</h2>
<p>In this tutorial, we will walk through the process of building a full-stack recipe application. We'll set up the backend, create the frontend, and link it to a database. We will also connect to a recipe API using an API key. </p>
<p>If you prefer to skip the setup, a starter code is available on CodeCoyotes, which includes some basic setup and CSS. But you'll still need to create a database and obtain an API key.</p>
<p>Let’s start by setting up our workspace:</p>
<h3 id="heading-step-1-setup-your-workspace">Step 1: Setup Your Workspace</h3>
<p>Start by opening Visual Studio Code (or your preferred code editor). Create a new folder named <code>recipe-app</code> on your desktop or another location. Then drag this folder into the Visual Studio Code window to open it.</p>
<p>Your folder structure should now look like this:</p>
<pre><code class="lang-plaintext">recipe-app
</code></pre>
<h3 id="heading-step-2-setup-the-backend">Step 2: Setup the Backend</h3>
<p>In the <code>recipe-app</code> folder, create another folder named <code>backend</code>.</p>
<p>Navigate to <code>View -&gt; Terminal</code> in Visual Studio Code to open a terminal. Change your directory to the <code>backend</code> folder using the command <code>cd backend</code>.</p>
<p>Type <code>npm init</code> to initialize a new npm package, then hit Enter to move through the prompts. For the entry point, type <code>./src/index.ts</code> and hit Enter.</p>
<p>Your folder structure should now look like this:</p>
<pre><code class="lang-plaintext">recipe-app
|-- backend
    |-- package.json
</code></pre>
<h3 id="heading-step-3-install-the-dependencies">Step 3: Install the Dependencies</h3>
<p>First, install the necessary dependencies using the following command:</p>
<pre><code class="lang-bash">npm install express prisma @prisma/client cors
</code></pre>
<p>Now, install the development dependencies:</p>
<pre><code class="lang-bash">npm install --save-dev ts-node typescript nodemon @types/cors @types/express @types/node
</code></pre>
<p>Your folder structure should now look like this:</p>
<pre><code class="lang-plaintext">recipe-app
|-- backend
    |-- node_modules
    |-- package.json
    |-- package-lock.json
</code></pre>
<h3 id="heading-step-4-setup-your-backend-code">Step 4: Setup Your Backend Code</h3>
<p>In the <code>backend</code> folder, create a new folder named <code>src</code>. Inside <code>src</code>, create a file named <code>index.ts</code>.</p>
<p>Add the following code to <code>index.ts</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;
<span class="hljs-keyword">import</span> cors <span class="hljs-keyword">from</span> <span class="hljs-string">"cors"</span>;

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

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

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

app.listen(<span class="hljs-number">5000</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Server running on localhost:5000"</span>);
});
</code></pre>
<h3 id="heading-step-5-add-the-start-script">Step 5: Add the Start Script</h3>
<p>First, open <code>package.json</code> in the <code>backend</code> folder. In the <code>scripts</code> section, replace the <code>test</code> script with a <code>start</code> script as follows:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"npx nodemon ./src/index.ts"</span>
}
</code></pre>
<h3 id="heading-step-6-run-your-backend">Step 6: Run Your Backend</h3>
<p>In the terminal, ensure you are in the <code>backend</code> folder, then type <code>npm start</code> to run your backend server.</p>
<p>Then open a browser and go to <code>http://localhost:5000/api/recipe/search</code>. You should see a response with the message <code>success</code>.</p>
<p>Congratulations! You have successfully set up and run your backend server. In the next part of this tutorial, we will focus on setting up the frontend and connecting to a database.</p>
<h2 id="heading-how-to-setup-the-database-and-prisma">How to Setup the Database and Prisma</h2>
<p>In this section, we'll focus on setting up a Postgres database using ElephantSQL and integrating Prisma to interact with our database effortlessly. Let's jump right in!</p>
<h3 id="heading-step-1-set-up-the-elephantsql-database">Step 1: Set Up the ElephantSQL Database</h3>
<p>Start by navigating to <a target="_blank" href="https://www.elephantsql.com/">ElephantSQL</a>. Click on "Get a managed database today," followed by selecting the "Tiny Turtle" plan for a free instance.</p>
<p>Sign in or create an account to proceed to the "Create new instance" page.</p>
<p>Then enter a name for your database (for example, <code>recipe-app-db</code>), keep the plan on the free tier, and choose a region closest to you.</p>
<p>Click on "Review," verify the details, and then click on "Create instance."</p>
<h3 id="heading-step-2-retrieve-the-database-credentials">Step 2: Retrieve the Database Credentials</h3>
<p>Once your instance is created, click on it to view the details.</p>
<p>Locate and copy the URL under the "Details" section. This URL contains the credentials needed to connect to your database.</p>
<h3 id="heading-step-3-create-an-environment-file">Step 3: Create an Environment File</h3>
<p>Now, return to your code editor and open the <code>backend</code> folder.</p>
<p>Create a new file named <code>.env</code>. Inside the <code>.env</code> file, add the following line:</p>
<pre><code class="lang-plaintext">DATABASE_URL=&lt;Your-Copied-Database-URL&gt;
</code></pre>
<p>Replace <code>&lt;Your-Copied-Database-URL&gt;</code> with the URL you copied from ElephantSQL.</p>
<h3 id="heading-step-4-integrate-prisma">Step 4: Integrate Prisma</h3>
<p>Stop your server if it's running by pressing <code>Ctrl + C</code> (or <code>Cmd + C</code> on Mac) in the terminal.</p>
<p>In the terminal, ensure you are in the <code>backend</code> directory, and type the following command to initialize Prisma:</p>
<pre><code class="lang-bash">npx prisma init
</code></pre>
<p>This command will create a new folder named <code>prisma</code> with a file named <code>schema.prisma</code>.</p>
<h3 id="heading-step-5-verify-prisma-integration">Step 5: Verify Prisma Integration</h3>
<p>Now, open <code>prisma/schema.prisma</code> to ensure your <code>DATABASE_URL</code> has been detected correctly.</p>
<p>Start your server again with the command <code>npm start</code>. Then navigate to <code>http://localhost:5000/api/recipe/search</code> in your browser to ensure your API still works and returns the success message.</p>
<p>Your folder structure should now include the Prisma folder and look like this:</p>
<pre><code class="lang-plaintext">recipe-app
|-- backend
    |-- prisma
        |-- schema.prisma
    |-- .env
    |-- ...
</code></pre>
<h2 id="heading-how-to-get-and-secure-a-spoonacular-api-key">How to Get and Secure a Spoonacular API Key</h2>
<h3 id="heading-step-1-obtain-an-api-key-from-spoonacular">Step 1: Obtain an API Key from Spoonacular</h3>
<p>To do this, navigate to <a target="_blank" href="https://spoonacular.com/">Spoonacular</a> and click on "Start Now." Sign up for an account and proceed to the dashboard.</p>
<p>Within the dashboard, click on “Profile” on the left-hand side, and find the section related to API keys. Generate a new API key, and copy it to your clipboard.</p>
<h3 id="heading-step-2-store-the-api-key-securely">Step 2: Store the API Key Securely</h3>
<p>Now, return to your code editor and open the <code>.env</code> file in the <code>backend</code> folder.</p>
<p>Add a new environment variable to store your API key as follows:</p>
<pre><code class="lang-plaintext">API_KEY=&lt;Your-Copied-API-Key&gt;
</code></pre>
<p>Replace <code>&lt;Your-Copied-API-Key&gt;</code> with the API key you copied from Spoonacular.</p>
<h3 id="heading-step-3-install-and-setup-thunder-client">Step 3: Install and Setup Thunder Client</h3>
<p>In Visual Studio Code, navigate to the extensions tab (square icon on the sidebar), and search for Thunder Client.</p>
<p>Install Thunder Client by clicking on the Install button. Once installed, you will see a new icon (a purple thunderbolt) on the sidebar.</p>
<h3 id="heading-step-4-test-the-api-key-with-thunder-client">Step 4: Test the API Key with Thunder Client</h3>
<p>Now click on the Thunder Client icon, then click on “New Request.”</p>
<p>Copy the endpoint URL for searching recipes from Spoonacular's documentation. It should look something like this: <code>https://api.spoonacular.com/recipes/complexSearch</code>.</p>
<p>Paste this URL into the URL bar in Thunder Client.</p>
<p>Under the query tab, add two new parameters:</p>
<ul>
<li><code>apiKey</code> with the value of your API key.</li>
<li><code>query</code> with a value of <code>burgers</code> or any other term you wish to search for.</li>
</ul>
<p>Then hit "Send" to issue the request and observe the response. You should see a list of recipes related to the term you searched for, indicating that your API key and endpoint are working correctly.</p>
<h2 id="heading-how-to-create-the-search-endpoint">How to Create the Search Endpoint</h2>
<h3 id="heading-step-1-setup-a-new-file-for-recipe-api-logic">Step 1: Setup a New File for Recipe API Logic</h3>
<p>First, navigate to your <code>backend/src</code> folder and create a new file named <code>recipe-api.ts</code>.</p>
<p>In <code>recipe-api.ts</code>, initiate a constant to store your API key from the environment variables:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> API_KEY = process.env.API_KEY;
</code></pre>
<h3 id="heading-step-2-create-the-searchrecipes-function">Step 2: Create the searchRecipes Function</h3>
<p>In <code>recipe-api.ts</code>, define a new asynchronous function <code>searchRecipes</code> that takes in a <code>searchTerm</code> and a <code>page</code> as parameters:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> searchRecipes = <span class="hljs-keyword">async</span> (searchTerm: <span class="hljs-built_in">string</span>, page: <span class="hljs-built_in">number</span>) =&gt; {
  <span class="hljs-keyword">if</span> (!API_KEY) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"API key not found"</span>);
  }

  <span class="hljs-keyword">const</span> baseURL = <span class="hljs-string">"https://api.spoonacular.com/recipes/complexSearch"</span>;
  <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">new</span> URL(baseURL);

  <span class="hljs-keyword">const</span> queryParams = {
    apiKey: API_KEY,
    query: searchTerm,
    <span class="hljs-built_in">number</span>: <span class="hljs-number">10</span>,
    offset: (page - <span class="hljs-number">1</span>) * <span class="hljs-number">10</span>,
  };

  url.search = <span class="hljs-keyword">new</span> URLSearchParams(queryParams).toString();

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> searchResponse = <span class="hljs-keyword">await</span> fetch(url.toString());
    <span class="hljs-keyword">const</span> resultsJson = <span class="hljs-keyword">await</span> searchResponse.json();
    <span class="hljs-keyword">return</span> resultsJson;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
  }
};
</code></pre>
<h3 id="heading-step-3-import-and-use-searchrecipes-in-indexts">Step 3: Import and Use <code>searchRecipes</code> in index.ts</h3>
<p>Now, navigate back to <code>index.ts</code> in the <code>backend/src</code> folder.</p>
<p>Import the <code>searchRecipes</code> function from <code>recipe-api.ts</code> at the top of your file:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> RecipeAPI <span class="hljs-keyword">from</span> <span class="hljs-string">"./recipe-api"</span>;
</code></pre>
<p>Locate the endpoint where you wish to utilize the <code>searchRecipes</code> function, and modify it to call <code>searchRecipes</code> with the appropriate arguments, then return the results:</p>
<pre><code class="lang-typescript">app.get(<span class="hljs-string">"/api/recipe/search"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> searchTerm = req.query.searchTerm <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>;
  <span class="hljs-keyword">const</span> page = <span class="hljs-built_in">parseInt</span>(req.query.page <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>);

  <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> recipeAPI.searchRecipes(searchTerm, page);
  <span class="hljs-keyword">return</span> res.json(results);
});
</code></pre>
<h3 id="heading-step-4-test-your-endpoint">Step 4: Test Your Endpoint</h3>
<p>Now you can restart your server by stopping it (<code>Ctrl + C</code> or <code>Cmd + C</code> on Mac) and then running <code>npm start</code>.</p>
<p>Test your endpoint by sending a GET request with the appropriate query parameters. For example, navigate to <code>http://localhost:5000/api/recipe/search?searchTerm=burgers&amp;page=1</code> in your browser or use a REST client like Postman or Thunder Client.</p>
<p>You should now see a list of recipes returned in response to your request, indicating that your backend logic for calling the Recipe API and returning the results is functioning as expected.</p>
<h2 id="heading-how-to-setup-the-frontend">How to Setup the Frontend</h2>
<p>Before you get started on this section, make sure you're in the top-level directory of your project, which in this case is named <code>recipe-app</code>.</p>
<h3 id="heading-step-1-create-a-react-app-with-vite">Step 1: Create a React App with Vite</h3>
<p>Start by opening a terminal and ensuring you're in the top-level folder (<code>recipe-app</code>).</p>
<p>Then run the following command to install the latest version of Vite:</p>
<pre><code class="lang-bash">npm install vite@latest --save-dev
</code></pre>
<p>Now, initiate a new React project with Vite by running:</p>
<pre><code class="lang-bash">npx create-vite frontend --template react-ts
</code></pre>
<p>This command creates a new folder named <code>frontend</code>, sets it up as a React project, and specifies TypeScript as the language.</p>
<h3 id="heading-step-2-navigate-to-your-new-react-app">Step 2: Navigate to Your New React App</h3>
<p>Change your directory to the <code>frontend</code> folder:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> frontend
</code></pre>
<p>Then install any necessary dependencies:</p>
<pre><code class="lang-bash">npm install
</code></pre>
<h3 id="heading-step-3-start-the-development-server">Step 3: Start the Development Server</h3>
<p>You can start the development server with the following command:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Your default web browser should now open displaying the initial setup of your React app, which includes a counter example.</p>
<h3 id="heading-step-4-clean-up-and-personalize-your-react-app">Step 4: Clean Up and Personalize Your React App</h3>
<p>Now you can head back to your code editor and navigate to <code>frontend/src</code>. Delete the <code>index.css</code> file as it won't be needed.</p>
<p>In <code>main.tsx</code>, remove the import statement for <code>index.css</code>.</p>
<p>Now, open <code>App.tsx</code>. Here, you'll see code for a counter. Delete all the content inside <code>App.tsx</code>.</p>
<p>Let’s start fresh by adding the following code to <code>App.tsx</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/App.tsx</span>
<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Hello from Recipe App<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>Save <code>App.tsx</code> and check your browser to see the updated text: "Hello from Recipe App".</p>
<h3 id="heading-step-5-setup-your-stylesheet">Step 5: Setup Your Stylesheet</h3>
<p>Go to <code>src</code> and open <code>App.css</code>. Delete all the pre-filled styles but keep the <code>.root</code> class definition empty for now.</p>
<p>Add a <code>font-family</code> property to the <code>.root</code> class:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* src/App.css */</span>
<span class="hljs-selector-class">.root</span> {
  <span class="hljs-attribute">font-family</span>: Helvetica, Arial, sans-serif;
}
</code></pre>
<p>Then head back to <code>App.tsx</code> and import your stylesheet:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/App.tsx</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// ...</span>
};
</code></pre>
<p>Then save <code>App.tsx</code> and check your browser to see the updated font.</p>
<p>Now you have a clean slate to start building out the frontend of your recipe app with React and TypeScript, using Vite as your build tool. As you progress, you can now start adding components, routing, and state management to build out your application's UI and functionality.</p>
<h2 id="heading-how-to-call-the-search-api-and-display-results-on-the-frontend">How to Call the Search API and Display Results on the Frontend</h2>
<p>Now we are going to fetch data from an API and display the results on the UI. The API response is structured as follows:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"results"</span>: [
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">650235</span>,
      <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Loaded Turkey Burgers"</span>,
      <span class="hljs-attr">"image"</span>: <span class="hljs-string">"https://spoonacular.com/recipeImages/650235-312x231.jpg"</span>,
      <span class="hljs-attr">"imageType"</span>: <span class="hljs-string">"jpg"</span>
    }
    <span class="hljs-comment">// ... other recipes</span>
  ],
  <span class="hljs-attr">"offset"</span>: <span class="hljs-number">10</span>,
  <span class="hljs-attr">"number"</span>: <span class="hljs-number">10</span>,
  <span class="hljs-attr">"totalResults"</span>: <span class="hljs-number">50</span>
}
</code></pre>
<p>Each recipe object contains an <code>id</code>, <code>title</code>, <code>image</code>, and <code>imageType</code>. We will map through the <code>results</code> array and display each recipe on our UI.</p>
<h3 id="heading-step-1-setup-state">Step 1: Setup State</h3>
<p>In your <code>App.tsx</code>, setup state to store the <code>searchTerm</code> and <code>recipes</code>.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [searchTerm, setSearchTerm] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [recipes, setRecipes] = useState([]);

  <span class="hljs-comment">// ... rest of your component</span>
};
</code></pre>
<h3 id="heading-step-2-fetch-data-from-the-api">Step 2: Fetch Data from the API</h3>
<p>Create a new file <code>API.ts</code> and set up a function to make the API call.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/API.ts</span>
<span class="hljs-keyword">const</span> searchRecipes = <span class="hljs-keyword">async</span> (searchTerm: <span class="hljs-built_in">string</span>, page: <span class="hljs-built_in">number</span>) =&gt; {
  <span class="hljs-keyword">const</span> baseURL = <span class="hljs-keyword">new</span> URL(<span class="hljs-string">"http://localhost:5000/api/recipes/search"</span>);
  baseURL.searchParams.append(<span class="hljs-string">"searchTerm"</span>, searchTerm);
  baseURL.searchParams.append(<span class="hljs-string">"page"</span>, page.toString());

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(baseURL.toString());

  <span class="hljs-keyword">if</span> (!response.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP Error: <span class="hljs-subst">${response.status}</span>`</span>);
  }

  <span class="hljs-keyword">return</span> response.json();
};

<span class="hljs-keyword">export</span> { searchRecipes };
</code></pre>
<h3 id="heading-step-3-create-a-handler-function">Step 3: Create a Handler Function</h3>
<p>Back in <code>App.tsx</code>, import the <code>searchRecipes</code> function and create a handler function to be called when the form is submitted.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, FormEvent } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { searchRecipes } <span class="hljs-keyword">from</span> <span class="hljs-string">"./API"</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// ... previous state setup</span>

  <span class="hljs-keyword">const</span> handleSearchSubmit = <span class="hljs-keyword">async</span> (event: FormEvent) =&gt; {
    event.preventDefault();

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { results } = <span class="hljs-keyword">await</span> searchRecipes(searchTerm, <span class="hljs-number">1</span>);
      setRecipes(results);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
    }
  };

  <span class="hljs-comment">// ... rest of your component</span>
};
</code></pre>
<h3 id="heading-step-4-display-the-data">Step 4: Display the Data</h3>
<p>Display the recipes data in your component's return statement.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// ... previous code</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSearchSubmit}</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">form</span>&gt;</span>
      {recipes.map((recipe) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{recipe.id}</span>&gt;</span>
          Recipe Image Location: {recipe.image}
          <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
          Recipe Title: {recipe.title}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h3 id="heading-step-5-define-the-recipe-type">Step 5: Define the Recipe Type</h3>
<p>Define a <code>Recipe</code> interface in a new file named <code>types.ts</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/types.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Recipe {
  id: <span class="hljs-built_in">number</span>;
  title: <span class="hljs-built_in">string</span>;
  image: <span class="hljs-built_in">string</span>;
  imageType: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>Back in <code>App.tsx</code>, import the <code>Recipe</code> interface and use it to type your state and map function.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, FormEvent } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { searchRecipes } <span class="hljs-keyword">from</span> <span class="hljs-string">'./API'</span>;
<span class="hljs-keyword">import</span> { Recipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'./types'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [searchTerm, setSearchTerm] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [recipes, setRecipes] = useState&lt;Recipe[]&gt;([]);

  <span class="hljs-comment">// ... rest of your code</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {/* ... rest of your return statement */}
      {recipes.map((recipe: Recipe) =&gt; (
        {/* ... rest of your map function */}
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h3 id="heading-step-6-test-your-setup">Step 6: Test Your Setup</h3>
<p>Now, start both your frontend and backend servers. Open your browser, navigate to your app, and try submitting a search. You should see the recipes data displayed on the screen.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># In one terminal</span>
<span class="hljs-built_in">cd</span> frontend
npm run dev

<span class="hljs-comment"># In another terminal</span>
<span class="hljs-built_in">cd</span> backend
npm start
</code></pre>
<p>This setup should now fetch and display recipe data based on the hardcoded <code>searchTerm</code> of "burgers". In a real-world scenario, you'd replace the hardcoded <code>searchTerm</code> with a dynamic value from a user input field.</p>
<h2 id="heading-how-to-create-the-search-input-and-recipe-card-component">How to Create the Search Input and Recipe Card Component</h2>
<h3 id="heading-step-1-setup-your-project">Step 1: Setup Your Project</h3>
<p>Start by setting up a new React project or navigate to your existing project directory.</p>
<pre><code class="lang-bash">npx create-react-app recipe-search-ui
<span class="hljs-built_in">cd</span> recipe-search-ui
</code></pre>
<h3 id="heading-step-2-create-state-hooks-for-user-input-and-data">Step 2: Create State Hooks for User Input and Data</h3>
<p>In your <code>src</code> folder, create a new file named <code>App.tsx</code> and import the necessary dependencies:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, FormEvent } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</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">const</span> [searchTerm, setSearchTerm] = useState &lt; string &gt; <span class="hljs-string">""</span>;
  <span class="hljs-keyword">const</span> [recipes, setRecipes] = useState &lt; <span class="hljs-built_in">Array</span> &lt; any &gt;&gt; [];

  <span class="hljs-comment">// ... rest of the code</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here, we have set up two state hooks: one for capturing the user's search term and another for holding the recipe data returned from the backend.</p>
<h3 id="heading-step-3-build-a-form-to-capture-user-input">Step 3: Build a Form to Capture User Input</h3>
<p>Within the <code>App</code> component, build a form with an input field and a submit button. We'll also create a function to handle the form submission, which will trigger the API call.</p>
<pre><code class="lang-jsx"><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-comment">// ... rest of the code</span>

  <span class="hljs-keyword">const</span> handleSearchSubmit = <span class="hljs-keyword">async</span> (event: FormEvent) =&gt; {
    event.preventDefault();
    <span class="hljs-comment">// ... API call logic</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSearchSubmit}</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">required</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter a search term"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{searchTerm}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setSearchTerm(event.target.value)}
        /&gt;
        <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">form</span>&gt;</span>
      {/* ... rest of the code */}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Now, users can enter their search term, and upon form submission, <code>handleSearchSubmit</code> will be triggered.</p>
<h3 id="heading-step-4-fetch-recipe-data-from-the-backend">Step 4: Fetch Recipe Data from the Backend</h3>
<p>In the <code>handleSearchSubmit</code> function, use the <code>fetch</code> API to send a request to your backend, capture the returned data, and update the <code>recipes</code> state.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> handleSearchSubmit = <span class="hljs-keyword">async</span> (event: FormEvent) =&gt; {
  event.preventDefault();
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
      <span class="hljs-string">`http://localhost:5000/api/recipes/search?searchTerm=<span class="hljs-subst">${searchTerm}</span>`</span>
    );
    <span class="hljs-keyword">if</span> (!response.ok) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP error! status: <span class="hljs-subst">${response.status}</span>`</span>);
    }
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
    setRecipes(data.results);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
  }
};
</code></pre>
<h3 id="heading-step-5-display-recipe-data">Step 5: Display Recipe Data</h3>
<p>Create a new folder named <code>components</code> in your <code>src</code> directory. Inside this folder, create a file named <code>RecipeCard.tsx</code>. This component will display individual recipe data.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Recipe } <span class="hljs-keyword">from</span> <span class="hljs-string">"../types"</span>;

interface Props {
  <span class="hljs-attr">recipe</span>: Recipe;
}

<span class="hljs-keyword">const</span> RecipeCard = <span class="hljs-function">(<span class="hljs-params">{ recipe }: Props</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"recipe-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{recipe.image}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">img</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"recipe-card-title"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{recipe.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> RecipeCard;
</code></pre>
<p>Now, go back to <code>App.tsx</code> and import <code>RecipeCard</code>. Map over the <code>recipes</code> state to display each recipe using the <code>RecipeCard</code> component.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> RecipeCard <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/RecipeCard"</span>;

<span class="hljs-comment">// ... rest of the code</span>

<span class="hljs-keyword">return</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    {/* ... rest of the code */}
    {recipes.map((recipe) =&gt; (
      <span class="hljs-tag">&lt;<span class="hljs-name">RecipeCard</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{recipe.id}</span> <span class="hljs-attr">recipe</span>=<span class="hljs-string">{recipe}</span> /&gt;</span>
    ))}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);
</code></pre>
<p>Now, when you submit a search term, the UI will display a list of recipe cards containing the images and titles of the recipes returned from the backend.</p>
<h3 id="heading-step-6-test-your-ui">Step 6: Test Your UI</h3>
<p>Run your React app, enter a search term such as "pasta" or "burgers", and submit the form. You should see a list of recipe cards displaying the relevant recipes from the backend.</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>Navigate to <code>http://localhost:3000</code> in your browser and try out your new recipe search UI!</p>
<h2 id="heading-how-to-build-the-pagination-and-view-more-functionality">How to Build the Pagination and View More Functionality</h2>
<h3 id="heading-step-1-backend-pagination">Step 1: Backend Pagination</h3>
<p>We added a <code>page</code> query parameter in the search endpoint. The <code>page</code> value is used to calculate the offset for the recipe data fetched from the database or external API.</p>
<h3 id="heading-step-2-add-view-more-button-to-the-ui">Step 2: Add "View More" Button to the UI</h3>
<p>Navigate to your <code>App.tsx</code> file. Scroll down to the JSX code where you map through the <code>recipes</code> array and add a "View More" button below it.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// ... other code</span>
{
  recipes.map(<span class="hljs-function">(<span class="hljs-params">recipe</span>) =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">RecipeCard</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{recipe.id}</span> <span class="hljs-attr">recipe</span>=<span class="hljs-string">{recipe}</span> /&gt;</span></span>);
}
&lt;button className=<span class="hljs-string">"view-more"</span> onClick={handleViewMoreClick}&gt;
  View More
&lt;/button&gt;;
<span class="hljs-comment">// ... other code</span>
</code></pre>
<h3 id="heading-step-3-create-a-useref-hook-to-store-the-current-page-number">Step 3: Create a <code>useRef</code> Hook to Store the Current Page Number</h3>
<p>Above your component's return statement, create a <code>useRef</code> hook to keep track of the current page number without causing re-renders.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// ... other code</span>
<span class="hljs-keyword">const</span> pageNumber = useRef(<span class="hljs-number">1</span>);
<span class="hljs-comment">// ... other code</span>
</code></pre>
<h3 id="heading-step-4-implement-the-handleviewmoreclick-function">Step 4: Implement the <code>handleViewMoreClick</code> Function</h3>
<p>Define a function called <code>handleViewMoreClick</code> to handle the logic for loading more recipes.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// ... other code</span>
<span class="hljs-keyword">const</span> handleViewMoreClick = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> nextPage = pageNumber.current + <span class="hljs-number">1</span>;
    <span class="hljs-keyword">const</span> nextRecipes = <span class="hljs-keyword">await</span> api.searchRecipes(searchTerm, nextPage);
    setRecipes(<span class="hljs-function">(<span class="hljs-params">prevRecipes</span>) =&gt;</span> [...prevRecipes, ...nextRecipes.results]);
    pageNumber.current = nextPage;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
  }
};
<span class="hljs-comment">// ... other code</span>
</code></pre>
<h3 id="heading-step-5-reset-page-number-on-new-search">Step 5: Reset Page Number on New Search</h3>
<p>Modify your <code>handleSearchSubmit</code> function to reset the page number back to 1 whenever a new search term is entered.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// ... other code</span>
<span class="hljs-keyword">const</span> handleSearchSubmit = <span class="hljs-keyword">async</span> (event: FormEvent) =&gt; {
  <span class="hljs-comment">// ... other code</span>
  setRecipes(recipes.results);
  pageNumber.current = <span class="hljs-number">1</span>;
};
<span class="hljs-comment">// ... other code</span>
</code></pre>
<h3 id="heading-step-6-test-your-implementation">Step 6: Test Your Implementation</h3>
<p>Run your app and perform a search. Click the "View More" button to load more results. Change the search term and ensure that the page number resets, and you get a fresh list of recipes.</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>Now, as you search for recipes and click "View More," you should see additional recipes being loaded and displayed in the UI.</p>
<h2 id="heading-how-to-build-the-recipe-summary-modal-component">How to Build the Recipe Summary Modal Component</h2>
<p>I'll walk you through this process step-by-step. We'll create a model that displays a recipe summary using a specific endpoint from the provided API.</p>
<h3 id="heading-step-1-understanding-the-recipe-summary-endpoint">Step 1: Understanding the Recipe Summary Endpoint</h3>
<p>You can understand where the summary data comes from by looking at your API documentation. The endpoint you need is called <code>Summarize Recipe</code>. This endpoint requires a recipe ID to generate a summary.</p>
<h3 id="heading-step-2-setup-backend-endpoint">Step 2: Setup Backend Endpoint</h3>
<p>Create a backend endpoint that interfaces with the <code>Summarize Recipe</code> endpoint.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// In your backend, create an endpoint to fetch recipe summary</span>
<span class="hljs-comment">// File: recipe-api.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getRecipeSummary = <span class="hljs-keyword">async</span> (recipeId: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">if</span> (!apiKey) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"API key not found"</span>);
  }

  <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">new</span> URL(
    <span class="hljs-string">`https://api.spoonacular.com/recipes/<span class="hljs-subst">${recipeId}</span>/summary`</span>
  );
  <span class="hljs-keyword">const</span> params = { apiKey: apiKey };
  url.search = <span class="hljs-keyword">new</span> URLSearchParams(params).toString();

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url.toString());
  <span class="hljs-keyword">const</span> json = <span class="hljs-keyword">await</span> response.json();
  <span class="hljs-keyword">return</span> json;
};
</code></pre>
<h3 id="heading-step-3-create-a-backend-route">Step 3: Create a Backend Route</h3>
<p>Create a route in your backend to handle requests to your new endpoint.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// File: index.ts</span>
app.get(<span class="hljs-string">"/api/recipe/:recipeId/summary"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> recipeId = req.params.recipeId;
  <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> recipeSummary(recipeId);
  res.json(result);
});
</code></pre>
<h3 id="heading-step-4-create-the-recipe-modal-component">Step 4: Create the Recipe Modal Component</h3>
<p>Create a React component for the recipe modal. We will use the useEffect hook to call the backend endpoint we just created, and store the Recipe Summary data in state.</p>
<p>First add a type for <code>RecipeSummary</code> to <code>types.ts</code></p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> RecipeSummary {
  id: <span class="hljs-built_in">number</span>;
  title: <span class="hljs-built_in">string</span>;
  summary: <span class="hljs-built_in">string</span>;
}
</code></pre>
<pre><code class="lang-jsx"><span class="hljs-comment">// File: RecipeModal.tsx</span>
<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { RecipeSummary } <span class="hljs-keyword">from</span> <span class="hljs-string">"../types"</span>;

interface Props {
  <span class="hljs-attr">recipeId</span>: string;
  onClose: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span>;
}

<span class="hljs-keyword">const</span> RecipeModal: React.FC&lt;Props&gt; = <span class="hljs-function">(<span class="hljs-params">{ recipeId, onClose }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [recipeSummary, setRecipeSummary] =
    (useState &lt; RecipeSummary) | (<span class="hljs-literal">null</span> &gt; <span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchRecipeSummary = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> summary = <span class="hljs-keyword">await</span> getRecipeSummary(recipeId);
        setRecipeSummary(summary);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(error);
      }
    };
    fetchRecipeSummary();
  }, [recipeId]);

  <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">"overlay"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-content"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-header"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{recipeSummary?.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"close-button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClose}</span>&gt;</span>
              <span class="hljs-symbol">&amp;times;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</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">p</span> <span class="hljs-attr">dangerouslySetInnerHTML</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">__html:</span> <span class="hljs-attr">recipeSummary</span>?<span class="hljs-attr">.summary</span> }} /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> RecipeModal;
</code></pre>
<h3 id="heading-step-5-style-the-modal">Step 5: Style the Modal</h3>
<p>Add the following CSS to style the modal:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* File: app.css */</span>
<span class="hljs-selector-class">.overlay</span> {
  <span class="hljs-attribute">position</span>: fixed;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</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">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.7</span>);
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">1</span>;
}

<span class="hljs-selector-class">.modal</span> {
  <span class="hljs-attribute">position</span>: fixed;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>);
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">2</span>;
  <span class="hljs-attribute">background-color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2em</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">4px</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">500px</span>;
}

<span class="hljs-selector-class">.modal-header</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: row;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: space-between;
}
</code></pre>
<h3 id="heading-step-6-render-and-handle-modal-interactions">Step 6: Render and Handle Modal Interactions</h3>
<p>Modify your main component to handle rendering and interactions with the modal.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// File: App.tsx</span>
<span class="hljs-keyword">const</span> App: React.FC = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [selectedRecipe, setSelectedRecipe] =
    (useState &lt; Recipe) | (<span class="hljs-literal">undefined</span> &gt; <span class="hljs-literal">undefined</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>
      {/* Other components and logic */}
      {selectedRecipe &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">RecipeModal</span>
          <span class="hljs-attr">recipeId</span>=<span class="hljs-string">{selectedRecipe.id.toString()}</span>
          <span class="hljs-attr">onClose</span>=<span class="hljs-string">{()</span> =&gt;</span> setSelectedRecipe(undefined)}
        /&gt;
      )}
    <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>Now, when a user clicks on a recipe, the modal will appear displaying the summary of the selected recipe. The modal can be closed by clicking the close button, which will set the <code>selectedRecipe</code> back to undefined, hiding the modal.</p>
<h2 id="heading-how-to-create-endpoints-to-getcreatedelete-favorite-recipes">How to Create Endpoints to Get/Create/Delete Favorite Recipes</h2>
<h3 id="heading-step-1-setup-the-database">Step 1: Setup the Database</h3>
<p>First, we need to extend our database schema to include a table for storing favorite recipes by their IDs.</p>
<p>First, navigate to the <code>Prisma</code> folder within the <code>backend</code> directory of your project. Then open the <code>schema.prisma</code> file.</p>
<p>Define a new model for favorite recipes as follows:</p>
<pre><code class="lang-prisma">model FavoriteRecipe {
  id        Int    @id @default(autoincrement())
  recipeId  Int    @unique
}
</code></pre>
<h3 id="heading-step-2-synchronize-the-database-schema">Step 2: Synchronize the Database Schema</h3>
<p>Now, let's synchronize the updated schema with our database.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> backend
npx prisma db push
</code></pre>
<h3 id="heading-step-3-setup-the-endpoints">Step 3: Setup the Endpoints</h3>
<p>We need to set up endpoints in our Node backend to handle creating, viewing, and deleting favorites. We'll use the prismaClient to help us perform crud operations on the database.</p>
<p>First, we'll create a new post endpoint like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In backend/index.ts</span>
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;

<span class="hljs-keyword">const</span> prismaClient = <span class="hljs-keyword">new</span> PrismaClient();

app.post(<span class="hljs-string">"/api/recipes/favorite"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { recipeId } = req.body;
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> favoriteRecipe = <span class="hljs-keyword">await</span> prismaClient.favoriteRecipe.create({
      <span class="hljs-attr">data</span>: { recipeId },
    });
    res.status(<span class="hljs-number">201</span>).json(favoriteRecipe);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Oops, something went wrong."</span> });
  }
});
</code></pre>
<p>Next, we'll create the View endpoint. To do that, create a utility function to fetch recipe details by IDs:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In backend/src/recipe-api.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getFavoriteRecipesByIds = <span class="hljs-keyword">async</span> (ids: string[]) =&gt; {
  <span class="hljs-keyword">if</span> (!apiKey) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"API Key not found"</span>);
  }
  <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">new</span> URL(<span class="hljs-string">"https://api.spoonacular.com/recipes/informationBulk"</span>);
  url.search = <span class="hljs-keyword">new</span> URLSearchParams({
    <span class="hljs-attr">apiKey</span>: apiKey,
    <span class="hljs-attr">ids</span>: ids.join(<span class="hljs-string">","</span>),
  }).toString();

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url);
  <span class="hljs-keyword">const</span> json = <span class="hljs-keyword">await</span> response.json();
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">results</span>: json };
};
</code></pre>
<p>Now, create the endpoint to fetch all favorite recipes:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In backend/index.ts</span>
<span class="hljs-keyword">import</span> { getFavoriteRecipesByIds } <span class="hljs-keyword">from</span> <span class="hljs-string">"./src/recipe-api"</span>;

app.get(<span class="hljs-string">"/api/recipes/favorite"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> favoriteRecipes = <span class="hljs-keyword">await</span> prismaClient.favoriteRecipe.findMany();
    <span class="hljs-keyword">const</span> recipeIds = favoriteRecipes.map(<span class="hljs-function">(<span class="hljs-params">recipe</span>) =&gt;</span>
      recipe.recipeId.toString()
    );
    <span class="hljs-keyword">const</span> favorites = <span class="hljs-keyword">await</span> getFavoriteRecipesByIds(recipeIds);
    res.json(favorites);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Oops, something went wrong."</span> });
  }
});
</code></pre>
<p>Next up is the Delete endpoint:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In backend/index.ts</span>
app.delete(<span class="hljs-string">"/api/recipes/favorite"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { recipeId } = req.body;
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> prismaClient.favoriteRecipe.delete({
      <span class="hljs-attr">where</span>: { recipeId },
    });
    res.status(<span class="hljs-number">204</span>).send();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Oops, something went wrong."</span> });
  }
});
</code></pre>
<h3 id="heading-step-4-test-the-endpoints">Step 4: Test the Endpoints</h3>
<p>You can use tools like Postman or Thunder Client to test the endpoints. Make sure to adjust the request method and URL accordingly, and provide the necessary request body or parameters.</p>
<ul>
<li><strong>Creating a Favorite:</strong> POST request to <code>/api/recipes/favorite</code> with <code>recipeId</code> in the body.</li>
<li><strong>Viewing Favorites:</strong> GET request to <code>/api/recipes/favorite</code>.</li>
<li><strong>Deleting a Favorite:</strong> DELETE request to <code>/api/recipes/favorite</code> with <code>recipeId</code> in the body.</li>
</ul>
<h3 id="heading-step-5-verify-the-database">Step 5: Verify the Database</h3>
<p>Check the <code>favoriteRecipes</code> table in your ElephantSQL database to verify the actions performed through the endpoints.</p>
<h2 id="heading-how-to-add-favorites-functionality-to-the-frontend">How to Add Favorites Functionality to the Frontend</h2>
<h3 id="heading-step-1-setup-the-tab-functionality">Step 1: Setup the Tab Functionality</h3>
<p>Next, we'll look at how to integrate these endpoints on the frontend. We'll start by setting up tabs for 'Search' and 'Favorites' in our app.</p>
<p>First, define a new state to keep track of the selected tab.</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>;

type Tabs = <span class="hljs-string">"search"</span> | <span class="hljs-string">"favorites"</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">const</span> [selectedTab, setSelectedTab] = useState &lt; Tabs &gt; <span class="hljs-string">"search"</span>;

  <span class="hljs-comment">// Rest of your code...</span>
}
</code></pre>
<h3 id="heading-step-2-render-tabs">Step 2: Render Tabs</h3>
<p>Now you'll render tabs in your JSX, and handle tab switching with the <code>onClick</code> event. This makes each <code>&lt;h1&gt;</code> element is clickable, and saves the tab the user clicked on in state. This helps conditionally render different UI elements depending on their selection.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// Inside your JSX...</span>
&lt;div className=<span class="hljs-string">"tabs"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSelectedTab("search")}&gt;Recipe Search<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSelectedTab("favorites")}&gt;Favorites<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
&lt;/div&gt;
</code></pre>
<h3 id="heading-step-3-conditional-rendering">Step 3: Conditional Rendering</h3>
<p>Based on the selected tab, you want to conditionally render either the search component or the favorites component. This will show/hide either the "search section" or the "favourites" section depending on the <code>selectedTab</code> state variable.</p>
<pre><code class="lang-jsx">{selectedTab === <span class="hljs-string">'search'</span> &amp;&amp; (
  <span class="hljs-comment">// search component code...</span>
)}
{selectedTab === <span class="hljs-string">'favorites'</span> &amp;&amp; (
  <span class="hljs-comment">// favorites component code...</span>
)}
</code></pre>
<h3 id="heading-step-4-fetch-favorite-recipes">Step 4: Fetch Favorite Recipes</h3>
<p>Next we need to populate the Favorite recipes tab with our favourite recipes. We want to do this when the App loads, for a quick user experience.</p>
<p>To do this, fetch the favorite recipes from the backend when the app loads using the <code>useEffect</code> hook, and store the fetched favorite recipes in a new state.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// api.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getFavouriteRecipes = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">new</span> URL(<span class="hljs-string">"http://localhost:5000/api/recipes/favourite"</span>);
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url);

  <span class="hljs-keyword">if</span> (!response.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP error! Status: <span class="hljs-subst">${response.status}</span>`</span>);
  }
  <span class="hljs-keyword">return</span> response.json();
};
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">//App.tsx</span>
<span class="hljs-keyword">import</span> React, { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// ... Rest of your imports and code</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-comment">// ... Rest of your state declarations</span>

  <span class="hljs-keyword">const</span> [favoriteRecipes, setFavoriteRecipes] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchFavoriteRecipes = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> favouriteRecipes = <span class="hljs-keyword">await</span> api.getFavouriteRecipes();
        setFavouriteRecipes(favouriteRecipes.results);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(error);
      }
    };

    fetchFavoriteRecipes();
  }, []);

  <span class="hljs-comment">// ... Rest of your code</span>
}
</code></pre>
<h3 id="heading-step-5-render-favorite-recipes">Step 5: Render Favorite Recipes</h3>
<p>Now you need to render the favorite recipes in the 'Favorites' tab.</p>
<pre><code class="lang-jsx">{selectedTab === <span class="hljs-string">'favorites'</span> &amp;&amp; (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    {favoriteRecipes.map(recipe =&gt; (
      // Render each favorite recipe card...
    ))}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
)}
</code></pre>
<h3 id="heading-step-6-add-a-heart-icon">Step 6: Add a Heart Icon</h3>
<p>Next we'll add a way for the user to add and remove favorites. We'll do this by adding a "heart" icon to each card. </p>
<p>Before diving into the code, ensure you are in the correct directory by navigating to your project's front-end directory in your terminal. Install the necessary package for icons by running:</p>
<pre><code class="lang-bash">npm install react-icons
</code></pre>
<h3 id="heading-step-7-import-the-icon">Step 7: Import the Icon</h3>
<p>Open the <code>RecipeCard</code> component, and import the heart icon at the top of your file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { AiOutlineHeart } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/ai"</span>;
</code></pre>
<h3 id="heading-step-8-insert-the-icon">Step 8: Insert the icon</h3>
<p>In the <code>RecipeCard</code> component, add the heart icon within a <code>span</code> element just above the <code>h3</code> tag:</p>
<pre><code class="lang-javascript">&lt;span onClick={handleFavoriteClick}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AiOutlineHeart</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{25}</span> /&gt;</span></span>
&lt;/span&gt;
</code></pre>
<h3 id="heading-step-9-add-css-styling">Step 9: Add CSS Styling</h3>
<p>In your <code>App.css</code> file, add the following CSS to style the icon and ensure it appears on the same line as the title. Using <code>flex</code> and <code>align-items</code> means the icon and title will be aligned nicely beneath the image:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.recipe-card-title</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.5rem</span>;
}
</code></pre>
<h3 id="heading-step-10-create-an-add-favourite-event-handler">Step 10: Create an Add Favourite Event Handler</h3>
<p>In <code>App.tsx</code>, create an event handler for favoriting a recipe. This is what will get called when the user clicks the heart icon on an recipe that hasn't yet been favorited:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> addfavoriteRecipe = <span class="hljs-keyword">async</span> (recipe) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> API.addFavoriteRecipe(recipe);
    setFavoriteRecipes([...favoriteRecipes, recipe]);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  }
};
</code></pre>
<h3 id="heading-step-11-api-logic">Step 11: API Logic</h3>
<p>In a new file called <code>API.ts</code>, create a function to handle the API call to save a favorite recipe. This will call our endpoint which we created earlier in the backend:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addFavoriteRecipe = <span class="hljs-keyword">async</span> (recipe) =&gt; {
  <span class="hljs-keyword">const</span> body = {
    <span class="hljs-attr">recipeId</span>: recipe.id,
  };
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:5000/api/recipes/favourite"</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
    },
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(body),
  });
  <span class="hljs-keyword">if</span> (!response.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Failed to save favorite"</span>);
  }
};
</code></pre>
<h3 id="heading-step-12-hook-up-the-event-handler">Step 12: Hook Up the Event Handler</h3>
<p>Pass the event handler to the <code>RecipeCard</code> component:</p>
<pre><code class="lang-javascript">&lt;RecipeCard
  <span class="hljs-comment">//.. other props</span>
  onFavoriteButtonClick={favoriteRecipe}
/&gt;
</code></pre>
<h3 id="heading-step-13-create-the-remove-favorite-event-handler">Step 13: Create the Remove Favorite Event Handler</h3>
<p>Similarly, create an event handler for un-favoriting a recipe in <code>App.tsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> removeFavoriteRecipe = <span class="hljs-keyword">async</span> (recipe) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> API.removeFavoriteRecipe(recipe);
    <span class="hljs-keyword">const</span> updatedRecipes = favoriteRecipes.filter(
      <span class="hljs-function">(<span class="hljs-params">favRecipe</span>) =&gt;</span> favRecipe.id !== recipe.id
    );
    setFavoriteRecipes(updatedRecipes);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  }
};
</code></pre>
<h3 id="heading-step-14-api-logic">Step 14: API Logic</h3>
<p>In <code>API.ts</code>, create a function to handle the API call to remove a favorite recipe. Again, this will call the backend API to remove a recipe which we created earlier:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> removeFavoriteRecipe = <span class="hljs-keyword">async</span> (recipe) =&gt; {
  <span class="hljs-keyword">const</span> body = {
    <span class="hljs-attr">recipeID</span>: recipe.id,
  };
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:5000/api/recipes/favourite"</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"DELETE"</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
    },
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(body),
  });
  <span class="hljs-keyword">if</span> (!response.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Failed to remove favorite"</span>);
  }
};
</code></pre>
<h3 id="heading-step-15-conditional-event-handler">Step 15: Conditional Event Handler</h3>
<p>Depending on if the user is "favoriting" or "unfavoriting" a recipe, we want to conditionally call either <code>addFavoriteRecipe</code> or <code>removeFavoriteRecipe</code> based on the favorited state:</p>
<pre><code class="lang-javascript">&lt;RecipeCard
  <span class="hljs-comment">//.. other props</span>
  onFavoriteButtonClick={isFavorite ? removeFavoriteRecipe : favoriteRecipe}
/&gt;
</code></pre>
<h3 id="heading-step-16-determine-the-favorited-state">Step 16: Determine the Favorited State</h3>
<p>Before we can display the heart icon a favorited/non-favorited state, we need to know if the recipe is already a or not.   </p>
<p>To do this, we determine whether a recipe is favorited by checking if it exists in the <code>favoriteRecipes</code> state array. Pass this information to <code>RecipeCard</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> isFavorite = favoriteRecipes.some(
  <span class="hljs-function">(<span class="hljs-params">favRecipe</span>) =&gt;</span> favRecipe.id === recipe.id
);
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">RecipeCard</span>
  // <span class="hljs-attr">...other</span> <span class="hljs-attr">props</span>
  <span class="hljs-attr">isFavorite</span>=<span class="hljs-string">{isFavorite}</span>
/&gt;</span></span>;
</code></pre>
<h3 id="heading-step-17-display-the-favorited-state">Step 17: Display the Favorited State</h3>
<p>In <code>RecipeCard</code>, conditionally render a filled or outlined heart icon based on the <code>isFavorite</code> prop:</p>
<pre><code class="lang-javascript">{
  isFavorite ? (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AiFillHeart</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{25}</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"red"</span> /&gt;</span></span>
  ) : (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AiOutlineHeart</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{25}</span> /&gt;</span></span>
  );
}
</code></pre>
<h2 id="heading-how-to-add-cssstyling">How to Add CSS/Styling</h2>
<h3 id="heading-step-1-prepare-the-hero-image">Step 1: Prepare the Hero Image</h3>
<p>We've added some basic styling so far, so lets complete the CSS so that our app looks polished!</p>
<p>Firstly obtain an image from a source like <a target="_blank" href="https://www.pexels.com">Pexels</a> or any other image repository. This will be used in the Hero section of our app at the top, and will have our title overlaid on it. Ensure the image has a horizontal orientation for better handling of aspect ratios.</p>
<p>Place the image in the <code>public</code> folder of your project.</p>
<pre><code class="lang-plaintext">project-folder
│
└───public
    │   hero-image.jpeg
</code></pre>
<h3 id="heading-step-2-structure-the-header">Step 2: Structure the Header</h3>
<p>Open <code>app.tsx</code> and locate the JSX markup. Add a <code>className</code> of <code>app-container</code> to the top <code>div</code> element.</p>
<p>Inside the <code>app-container</code> div, add a new <code>div</code> with a <code>className</code> of <code>header</code>. Within the <code>header</code> div, add an <code>img</code> element with a <code>src</code> attribute pointing to your image, and a <code>div</code> element with a <code>className</code> of <code>title</code> containing the app's title.</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">"app-container"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/hero-image.jpeg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Hero"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"title"</span>&gt;</span>My Recipe App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  {<span class="hljs-comment">/* ...rest of your code */</span>}
&lt;/div&gt;
</code></pre>
<h3 id="heading-step-3-style-the-header">Step 3: Style the Header</h3>
<p>Open <code>app.css</code> and scroll to the top. Add the following CSS to style the <code>app-container</code>, <code>header</code>, <code>img</code>, and <code>title</code> elements. This makes the <code>title</code> appear on top of the image, with a translucent background:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.app-container</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">2em</span>;
}

<span class="hljs-selector-class">.header</span> {
  <span class="hljs-attribute">position</span>: relative;
}

<span class="hljs-selector-class">.header</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">500px</span>;
  <span class="hljs-attribute">object-fit</span>: cover;
  <span class="hljs-attribute">object-position</span>: center;
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.5</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1em</span>;
}

<span class="hljs-selector-class">.title</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>);
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2em</span>;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">background-color</span>: black;
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.8</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5em</span> <span class="hljs-number">1.5em</span> <span class="hljs-number">0.5em</span> <span class="hljs-number">1.5em</span>;
}
</code></pre>
<h3 id="heading-step-4-adjust-the-layout">Step 4: Adjust the Layout</h3>
<p>Add padding to the <code>body</code> element and use a media query to add margins on larger screens. We do this so our app doesn't appear to narrow on mobile devices. When the screen size reaches <code>768px</code>, the media query will kick in and add margin to the left and right of our app, so that the app doesn't appear too wide.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">5em</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f0f0f0</span>; <span class="hljs-comment">/* or any color you prefer */</span>
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">768px</span>) {
  <span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">10em</span>;
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">10em</span>;
  }
}
</code></pre>
<h3 id="heading-step-5-style-tabs-underline">Step 5: Style Tabs Underline</h3>
<p>Currently its not clear which tab the user has selected. What we want to do is add an orange underline to the selected tab. To do this, we can use a combination of CSS classes and conditional rendering.</p>
<p>Within <code>app.tsx</code>, locate your <code>h1</code> elements representing tabs, and dynamically apply a <code>className</code> of <code>tab-active</code> based on the selected tab.</p>
<pre><code class="lang-jsx">&lt;h1 className={selectedTab === <span class="hljs-string">'search'</span> ? <span class="hljs-string">'tab-active'</span> : <span class="hljs-string">''</span>}&gt;Search&lt;/h1&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{selectedTab</span> === <span class="hljs-string">'favorites'</span> ? '<span class="hljs-attr">tab-active</span>' <span class="hljs-attr">:</span> ''}&gt;</span>Favorites<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
</code></pre>
<p>In <code>app.css</code>, define the <code>tab-active</code> class:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.tab-active</span> {
  <span class="hljs-attribute">border-bottom</span>: <span class="hljs-number">4px</span> solid orange; <span class="hljs-comment">/* or any color you prefer */</span>
  <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">0.5em</span>;
}
</code></pre>
<h3 id="heading-step-6-style-the-search-bar">Step 6: Style the Search Bar</h3>
<p>We want our search bar to take up the width of the container, and we want to add an icon instead of the search button, which makes our UI more interesting. </p>
<p>In <code>app.tsx</code>, locate the <code>form</code> element within the <code>Search</code> tab. Replace the text "Submit" in the <code>button</code> element with an icon from a library like React Icons.</p>
<pre><code class="lang-jsx">&lt;button&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AiOutlineSearch</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{40}</span> /&gt;</span></span>
&lt;/button&gt;
</code></pre>
<p>In <code>app.css</code>, style the <code>form</code>, <code>input</code>, and <code>button</code> elements:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">form</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">background-color</span>: white;
  <span class="hljs-attribute">align-items</span>: center;
}

<span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5em</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2em</span>;
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">border</span>: none;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">outline</span>: none;
}

<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: white;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">cursor</span>: pointer;
}
</code></pre>
<h3 id="heading-step-7-implement-a-responsive-recipe-card-grid">Step 7: Implement a Responsive Recipe Card Grid</h3>
<p>Currently our Recipe Cards are stacked horizontally. We'll use CSS grid to make the recipe cards appear in a grid layout, which will also make things more responsive. </p>
<p>Within <code>app.tsx</code>, create a new <code>div</code> with a <code>className</code> of <code>recipe-grid</code> just above where you map over your recipes, and place the logic to rendering the recipes inside this <code>div</code>.</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">"recipe-grid"</span>&gt;
  {recipes.map(<span class="hljs-function">(<span class="hljs-params">recipe</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> isFavourite = favouriteRecipes.some(<span class="hljs-function">(<span class="hljs-params">favRecipe</span>) =&gt;</span> favRecipe.id === recipe.id);

    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">RecipeCard</span>
        <span class="hljs-attr">key</span>=<span class="hljs-string">{recipe.id}</span>
        <span class="hljs-attr">recipe</span>=<span class="hljs-string">{recipe}</span>
        <span class="hljs-attr">onFavouriteButtonClick</span>=<span class="hljs-string">{isFavourite</span> ? <span class="hljs-attr">removeFavouriteRecipe</span> <span class="hljs-attr">:</span> <span class="hljs-attr">addFavouriteRecipe</span>}
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSelectedRecipe(recipe)}
        isFavourite={isFavourite}
      /&gt;</span>
    );
  })}
&lt;/div&gt;
</code></pre>
<p>In <code>app.css</code>, style the <code>recipe-grid</code> and <code>recipe-card</code> elements:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.recipe-grid</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(auto-fill, minmax(<span class="hljs-number">400px</span>, <span class="hljs-number">1</span>fr));
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">2em</span>;
}

<span class="hljs-selector-class">.recipe-card</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: space-evenly;
  <span class="hljs-attribute">background-color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">4px</span> <span class="hljs-number">12px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1.5em</span>;
}

<span class="hljs-selector-class">.recipe-card</span> <span class="hljs-selector-tag">h3</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5em</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">white-space</span>: nowrap;
  <span class="hljs-attribute">overflow</span>: hidden;
  <span class="hljs-attribute">text-overflow</span>: ellipsis;
}
</code></pre>
<h3 id="heading-step-8-final-touches">Step 8: Final Touches</h3>
<p>Style the "View More" button to make sure it matches the style of our app, and is centered beneath our recipe grid:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.view-more-button</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5em</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
  <span class="hljs-attribute">font-weight</span>: bold;
  <span class="hljs-attribute">margin</span>: auto;
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congrats on making it to the end! Hopefully you've learned a few things about full stack development using React and Node. </p>
<p>If you enjoyed this project, you can find more at <a target="_blank" href="https://www.codecoyotes.com/">CodeCoyotes.com</a>, where you can also send me a message if you need to get in contact.   </p>
<p>Thanks for reading, see you in the next one!  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Get Started with NodeJS – a Handbook for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ By Krish Jaiswal Hello folks! 👋 Recently, I have been learning about Node.js. So I decided to share my learnings with you here. 👨‍💻 In this tutorial, we'll take a high-level look at Node.js – what it is, and what you can do with it.  We will be co... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/get-started-with-nodejs/</link>
                <guid isPermaLink="false">66d460139f2bec37e2da063b</guid>
                
                    <category>
                        <![CDATA[ Back end development  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 02 May 2023 18:25:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/e5aa6e1c-fe02-4e17-bdb1-1622b97831e6.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Krish Jaiswal</p>
<p>Hello folks! 👋 Recently, I have been learning about Node.js. So I decided to share my learnings with you here. 👨‍💻</p>
<p>In this tutorial, we'll take a high-level look at <a target="_blank" href="https://twitter.com/nodejs">Node.js</a> – what it is, and what you can do with it. </p>
<p>We will be covering all the important Node concepts with hands-on examples and a lot of code snippets. This will give you the foundational knowledge required to get started with backend development with NodeJS.</p>
<p>This article is heavily inspired by the <strong>NodeJS and Express - Full Course</strong> on freeCodeCamp taught by John Smilga. You can <a target="_blank" href="https://www.freecodecamp.org/news/free-8-hour-node-express-course/">check that out here if you'd like</a>.</p>
<h2 id="heading-heres-what-well-cover-in-this-guide">Here's what we'll cover in this guide:</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-node">What Is NodeJS?</a></li>
<li><a class="post-section-overview" href="#heading-global-variables">Global Variables</a></li>
<li><a class="post-section-overview" href="#heading-modules-in-nodejs">Modules</a></li>
<li><a class="post-section-overview" href="#heading-short-note-on-moduleexports">Short Note On <code>module.exports</code></a></li>
<li><a class="post-section-overview" href="#heading-types-of-modules-in-node">Types Of Modules</a></li>
<li><a class="post-section-overview" href="#heading-event-driven-programming">Event Driven Programming</a></li>
<li><a class="post-section-overview" href="#heading-lets-create-a-server">Creating our first server</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/p/af44b49e-dac0-4ba4-abe6-32ad97ee5afe/Let's%20Serve%20Something%20Interesting">Let's Serve Something Interesting!</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h1 id="heading-what-is-node">What is Node?</h1>
<p>Node is an environment in which you can run JavaScript code "<strong>Outside the web browser</strong>". Node be like – "Hey y'all, you give your JS code to me and I'll run it 😎". It uses Google's V8 Engine to convert the JavaScript code to Machine Code.</p>
<p>Since Node runs JavaScript code outside the web browser, this means that it doesn't have access to certain features that are only available in the browser, like the DOM or the <code>window</code> object or even the <code>localStorage</code>.</p>
<p>This means that at any point in your code, you can't type in <code>document.querySelector()</code> or <code>alert()</code> as these will produce errors (This is what is shown in the below image). </p>
<p><strong>Remember:</strong> Node is meant for server-side programming, while those browser features are meant for client-side programming.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-135.png" alt="Node does not know about Browser API's" width="600" height="400" loading="lazy"></p>
<p>Front-end folks don't be sad – there's more to it! Node provides you with lots of API's and Modules with which you can perform a variety of operations like File Handling, Creating Servers, and much more. Before diving into the NodeJS, first let's install it in our machine.</p>
<h2 id="heading-how-to-install-nodejs">How to Install NodeJS</h2>
<p>Installing NodeJS is straightforward. If you already have Node installed in your machine, you can skip this section. If not, then follow along.</p>
<p>Here are the steps to download NodeJS on your machine:</p>
<ol>
<li>Navigate to <a target="_blank" href="https://nodejs.org/">https://nodejs.org/</a></li>
<li>Download the LTS Version of NodeJS for your operating system</li>
<li>Run the installer and follow the installation wizard. Simply answer Yes to all the questions.</li>
<li>Once the installation is complete, open a new terminal or command prompt window and run the following command to verify that NodeJS is installed correctly: <code>node -v</code>. If you see the version of NodeJS printed in your terminal, Congratulations! You have now successfully installed NodeJS on your machine.</li>
</ol>
<p><strong>Note:</strong> If you encounter any issues during the installation process, you can refer to the official NodeJS documentation for more detailed instructions and troubleshooting tips.</p>
<h1 id="heading-global-variables">Global Variables</h1>
<p>Let's start this article by learning about some variables present in NodeJS called Global Variables. These are basically variables which store some data and can be accessed from anywhere in your code – doesn't matter how deeply nested the code is.</p>
<p>You should know about these commonly used Global variables: </p>
<ul>
<li><code>__dirname</code>: This variable stores the path to the current working directory.</li>
<li><code>__filename</code>: This variable stores the path to the current working file.</li>
</ul>
<p>Let's use them and see what value they contain. For this, let's create a new folder called <code>NodeJSTut</code> in your <code>Desktop</code> and open it up with your favorite text editor (In the entire tutorial, we will be using VS Code). Create a new file called <code>app.js</code> and open up a new integrated VS Code Terminal. </p>
<p>Paste the following code in the <code>app.js</code> file and save it:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// __dirname Global Variable</span>
<span class="hljs-built_in">console</span>.log(__dirname);

<span class="hljs-comment">// __filename Global Variable</span>
<span class="hljs-built_in">console</span>.log(__filename);
</code></pre>
<p>To run this code using Node, type in the following command in the terminal and press Enter: <code>node app.js</code>. You will see the absolute path to the present working directory and the path to the current file is printed in the terminal. This is what the output looks like in my case:</p>
<pre><code class="lang-text">C:\Desktop\NodeJSTut
C:\Desktop\NodeJSTut\app.js
</code></pre>
<p>You can go ahead and create your own global variables which can be accessed from anywhere in your code. You can do so, like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define a global variable in NodeJS</span>
<span class="hljs-built_in">global</span>.myVariable = <span class="hljs-string">'Hello World'</span>;

<span class="hljs-comment">// Access the global variable</span>
<span class="hljs-built_in">console</span>.log(myVariable); <span class="hljs-comment">// Output: Hello World</span>
</code></pre>
<h1 id="heading-modules-in-nodejs">Modules in NodeJS</h1>
<p>In Node.js, a module is essentially a reusable block of code that can be used to perform a specific set of tasks or provide a specific functionality. A module can contain variables, functions, classes, objects, or any other code that can be used to accomplish a particular task or set of tasks.</p>
<p>The primary purpose of using modules in Node.js is to help organize code into smaller, more manageable pieces. A modules can then be imported at any time and used flexibly which helps in creating reusable code components that can be shared across multiple projects.</p>
<p>To understand this, consider this example: Let's say you have defined lots of functions in your code that works with a huge volume of JSON data. </p>
<p>Losing your sleep and increased anxiety levels are common side effects of keeping all this stuff (functions + data + some other logic) in one single file.</p>
<p>So you, being a clever programmer, thought of making a separate file for the JSON data and a separate file for storing all the functions. Now, you can simply import the data and the functions whenever you want and use them accordingly. This method increases efficiency as your file size reduces drastically. This is the concept of modules!</p>
<p>Let's see how we can make our own modules. For this, we are going to write some code where we will be defining a function called <code>sayHello()</code> in a file called <code>hello.js</code>. This function will accept a <code>name</code> as the parameter and simply print a greeting message in the console.</p>
<p>We will then import it in another file called <code>app.js</code> and use it there. How interesting, right 😂? Let's check out the code:</p>
<p>This is the code in <code>hello.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sayHello</span>(<span class="hljs-params">name</span>)</span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello <span class="hljs-subst">${name}</span>`</span>);
}

<span class="hljs-built_in">module</span>.exports = sayHello
</code></pre>
<p>This is the code in <code>app.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> sayHello = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./hello.js'</span>);

sayHello(<span class="hljs-string">'John'</span>);
sayHello(<span class="hljs-string">'Peter'</span>);
sayHello(<span class="hljs-string">'Rohit'</span>);
</code></pre>
<p>The file <code>hello.js</code> can be called the <code>module</code> in this case. Every module has an object called <code>exports</code> which should contain all the stuff you want to export from this module like variables or functions. In our case, we are defining a function in the <code>hello.js</code> file and directly exporting it.</p>
<p>The <code>app.js</code> file imports the <code>sayHello()</code> function from <code>hello.js</code> and stores it in the <code>sayHello</code> variable. To import something from a module, we use the <code>require()</code> method which accepts the path to the module. Now we can simply invoke the variable and pass a name as a parameter. Running the code in <code>app.js</code> file will produce the following output:</p>
<pre><code class="lang-javascript">Hello John
Hello Peter
Hello Rohit
</code></pre>
<h1 id="heading-short-note-on-moduleexports">Short Note on <code>module.exports</code></h1>
<p>In the previous section of the article, we saw how to use <code>module.exports</code> but I felt that it is important to understand how it works in a bit more detail. Hence, this section of the article is like a mini tutorial where we will see how we can export one variable/function as well as multiple variables and functions using <code>module.exports</code>. So, Let's get started:</p>
<p><code>module.exports</code> is a special object in NodeJS that allows you to export functions, objects, or values from a module, so that other modules can access and use them. Here's an example of how to use <code>module.exports</code> to export a function from a module:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// myModule.js</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myFunction</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hello from myFunction!'</span>);
}

<span class="hljs-built_in">module</span>.exports = myFunction;
</code></pre>
<p>In this example, we define a function <code>myFunction</code> and then export it using <code>module.exports</code>. Other modules can now require this module and use the exported function:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// app.js</span>

<span class="hljs-keyword">const</span> myFunction = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./myModule'</span>);

myFunction(); <span class="hljs-comment">// logs 'Hello from myFunction!'</span>
</code></pre>
<p>Everything seems fine now and life is good. But the problem arises when we have to export multiple functions and variables from a single file. The point is when you use <code>module.exports</code> multiple times in a single module, it will replace the previously assigned value with the new one. Consider this code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// module.js</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myFunction</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hello from myFunction!'</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myFunction2</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hello from myFunction2!'</span>);
}

<span class="hljs-comment">// First Export</span>
<span class="hljs-built_in">module</span>.exports = myFunction;

<span class="hljs-comment">// Second Export</span>
<span class="hljs-built_in">module</span>.exports = myFunction2;
</code></pre>
<p>In this example, we first export <code>myFunction()</code>. But we then overwrite <code>module.exports</code> with a new function - <code>myFunction2()</code>. As a result, only the second export statement will take effect, and the <code>myFunction()</code> function will not be exported.</p>
<p>This problem can be solved if you assign <code>module.exports</code> to an object which contains all the functions you want to export, like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// myModule.js</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myFunction1</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hello from myFunction1!'</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myFunction2</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hello from myFunction2!'</span>);
}

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">foo</span>: <span class="hljs-string">'bar'</span>,
  <span class="hljs-attr">myFunction1</span>: myFunction1,
  <span class="hljs-attr">myFunction2</span>: myFunction2
};
</code></pre>
<p>In this example, we export an object with three properties: <code>foo</code>, <code>myFunction1</code>, and <code>myFunction2</code>. Other modules can require this module and access these properties:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// app.js</span>

<span class="hljs-keyword">const</span> myModule = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./myModule'</span>);

<span class="hljs-built_in">console</span>.log(myModule.foo); <span class="hljs-comment">// logs 'bar'</span>
myModule.myFunction1(); <span class="hljs-comment">// logs 'Hello from myFunction1!'</span>
myModule.myFunction2(); <span class="hljs-comment">// logs 'Hello from myFunction2!'</span>
</code></pre>
<p>To summarize, you can use <code>module.exports</code> as many times as you want in your NodeJS code, but you should be aware that each new assignment will replace the previous one. You should use an object to group multiple exports together.</p>
<h1 id="heading-types-of-modules-in-node">Types Of Modules in Node</h1>
<p>There are 2 types of modules in NodeJS:</p>
<ul>
<li><strong>Built In Modules</strong>: These are modules included in Node by default, so you can use them without installation. You just need to import them and get started.</li>
<li><strong>External Modules</strong>: These are modules created by other developers which are not included by default. So you need to install them first before using them.</li>
</ul>
<p>Here is an image of popular built-in modules in NodeJS and what can you do using them:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-137-1.png" alt="Tabular representation of the different built-in modules in NodeJS" width="600" height="400" loading="lazy"></p>
<p>Let's go over each of these in more detail so you can learn more about what they do.</p>
<h2 id="heading-the-os-module">The OS Module</h2>
<p>The OS Module (as its name implies) provides you methods/functions with which you can get information about your Operating System.</p>
<p>To use this module, the first step is to import it like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> os = <span class="hljs-built_in">require</span>(<span class="hljs-string">'os'</span>);
</code></pre>
<p>This is how you can use the OS Module to get information about the Operating System:👇</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> os = <span class="hljs-built_in">require</span>(<span class="hljs-string">'os'</span>)

<span class="hljs-comment">// os.uptime()</span>
<span class="hljs-keyword">const</span> systemUptime = os.uptime();

<span class="hljs-comment">// os.userInfo()</span>
<span class="hljs-keyword">const</span> userInfo = os.userInfo();

<span class="hljs-comment">// We will store some other information about my WindowsOS in this object:</span>
<span class="hljs-keyword">const</span> otherInfo = {
    <span class="hljs-attr">name</span>: os.type(),
    <span class="hljs-attr">release</span>: os.release(),
    <span class="hljs-attr">totalMem</span>: os.totalmem(),
    <span class="hljs-attr">freeMem</span>: os.freemem(),
}

<span class="hljs-comment">// Let's Check The Results:</span>
<span class="hljs-built_in">console</span>.log(systemUptime);
<span class="hljs-built_in">console</span>.log(userInfo);
<span class="hljs-built_in">console</span>.log(otherInfo);
</code></pre>
<p>This is the output of the above code: </p>
<p>Note that the output shows information about the Windows Operating System running on my system. The output could be different from yours.</p>
<pre><code class="lang-text">521105
{
    uid: -1,
    gid: -1,
    username: 'krish',
    homedir: 'C:\\Users\\krish',
    shell: null
}
{
    name: 'Windows_NT',
    release: '10.0.22621',
    totalMem: 8215212032,
    freeMem: 1082208256
}
</code></pre>
<p>Let's break down the above code and output:</p>
<ul>
<li><code>os.uptime()</code> tells the system uptime in seconds. This function returns the number of seconds the system has been running since it was last rebooted. If you check the first line of the output: <code>521105</code> is the number of seconds, my system has been running since it was last rebooted. Of course, it will be different for you.</li>
<li><code>os.userInfo()</code> gives the information about the current user. This function returns an object with information about the current user including the user ID, group ID, username, home directory, and default shell. Below is the breakdown of the output in my case:</li>
</ul>
<pre><code class="lang-javascript">    {
        <span class="hljs-attr">uid</span>: <span class="hljs-number">-1</span>,
        <span class="hljs-attr">gid</span>: <span class="hljs-number">-1</span>,
        <span class="hljs-attr">username</span>: <span class="hljs-string">'krish'</span>,
        <span class="hljs-attr">homedir</span>: <span class="hljs-string">'C:\\Users\\krish'</span>,
        <span class="hljs-attr">shell</span>: <span class="hljs-literal">null</span>
    }
</code></pre>
<p>The <code>uid</code> and <code>gid</code> is set to <code>-1</code> in Windows, because Windows does not have the concept of user IDs like Unix-based systems. The <code>username</code> of my OS is <code>krish</code> and the home directory is <code>'C:\\Users\\krish'</code>. The <code>shell</code> is set to <code>null</code> because the concept of a default shell does not exist on Windows. Windows has a default command interpreter program called Command Prompt (cmd.exe), which runs commands and manages the system.</p>
<p>The other methods related to OS Module like <code>os.type()</code>, <code>os.release()</code> and so on, which you saw in the above code has been used within the <code>otherInfo</code> object. Here is a breakdown of what these methods do:</p>
<ul>
<li><code>os.type()</code> - Tells the name of the Operating System</li>
<li><code>os.release()</code> - Tells the release version of the Operating System</li>
<li><code>os.totalMem()</code> - Tells the total amount of memory available in bytes</li>
<li><code>os.freeMem()</code> - Tells the total amount of free memory available in bytes</li>
</ul>
<p>This is the information which the above methods display about my OS:</p>
<pre><code class="lang-javascript">{
    <span class="hljs-attr">name</span>: <span class="hljs-string">'WindowsNT'</span>, <span class="hljs-comment">// Name of my OS</span>
    <span class="hljs-attr">release</span>: <span class="hljs-string">'10.0.22621'</span>, <span class="hljs-comment">// Release Version of my OS</span>
    <span class="hljs-attr">totalMem</span>: <span class="hljs-number">8215212032</span>, <span class="hljs-comment">// Total Memory Available in bytes (~ 8 GB)</span>
     <span class="hljs-attr">freeMem</span>: <span class="hljs-number">1082208256</span> <span class="hljs-comment">// Free Memory Available in bytes (~ 1 GB) </span>
}
</code></pre>
<h2 id="heading-the-path-module">The PATH Module</h2>
<p>The PATH module comes in handy while working with file and directory paths. It provides you with various methods with which you can:</p>
<ul>
<li>Join path segments together</li>
<li>Tell if a path is absolute or not</li>
<li>Get the last portion/segment of a path</li>
<li>Get the file extension from a path, and much more!</li>
</ul>
<p>You an see the PATH Module in action in the code below.</p>
<p>Code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import 'path' module using the 'require()' method:</span>
<span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>)

<span class="hljs-comment">// Assigning a path to the myPath variable</span>
<span class="hljs-keyword">const</span> myPath = <span class="hljs-string">'/mnt/c/Desktop/NodeJSTut/app.js'</span>

<span class="hljs-keyword">const</span> pathInfo = {
    <span class="hljs-attr">fileName</span>: path.basename(myPath),
    <span class="hljs-attr">folderName</span>: path.dirname(myPath),
    <span class="hljs-attr">fileExtension</span>: path.extname(myPath),
    <span class="hljs-attr">absoluteOrNot</span>: path.isAbsolute(myPath),
    <span class="hljs-attr">detailInfo</span>: path.parse(myPath),
}

<span class="hljs-comment">// Let's See The Results:</span>
<span class="hljs-built_in">console</span>.log(pathInfo);
</code></pre>
<p>Output:</p>
<pre><code class="lang-text">{
  fileName: 'app.js',
  folderName: '/mnt/c/Desktop/NodeJSTut',
  fileExtension: '.js',
  absoluteOrNot: true,
  detailInfo: {
    root: '/',
    dir: '/mnt/c/Desktop/NodeJSTut',
    base: 'app.js',
    ext: '.js',
    name: 'app'
  }
}
</code></pre>
<p>Let's have a detailed breakdown of the above code and its output:</p>
<p>The first and foremost step to work with <code>path</code> module is to import it in the <code>app.js</code> file using the <code>require()</code> method. </p>
<p>Next, we are assigning a path of some file to a variable called <code>myPath</code>. This can be a path to any random file. For the purpose of understanding the <code>path</code> module, I chose this: <code>/mnt/c/Desktop/NodeJSTut/app.js</code>.</p>
<p>Using the <code>myPath</code> variable, we will understand the <code>path</code> module in detail. Let's check out the functions which this module has to offer and what can we do with it:</p>
<ul>
<li><code>path.basename(myPath)</code>: The <code>basename()</code> function accepts a path and returns the last part of that path. In our case, the last part of <code>myPath</code> is: <code>app.js</code>.</li>
<li><code>path.dirname(myPath)</code>: The <code>dirname()</code> function selects the last part of the path provided to it and returns the path to it's parent's directory. In our case, since the last part of <code>myPath</code> is <code>app.js</code>. The <code>dirname()</code> function returns the path to the parent directory of <code>app.js</code> (the folder inside which <code>app.js</code> file lies), i.e, <code>/mnt/c/Desktop/NodeJSTut</code>. It can be also thought as: the <code>dirname()</code> function simply excludes the last part of the path provided to it and returns the leftover path.</li>
<li><code>path.extname(myPath)</code>: This function checks for any extension on the last part of the provided path and it returns the file extension (if it exists), otherwise it returns an empty string: <code>''</code>. In our case, since the last part is <code>app.js</code> and a file extension exists, we get <code>'.js'</code> as the output.</li>
<li><code>path.isAbsolute(myPath)</code>: This tells whether the provided path is absolute or not. On Unix-based systems (such as macOS and Linux), an absolute path always starts with the forward slash (<code>/</code>). On Windows systems, an absolute path can start with a drive letter (such as <code>C:</code>) followed by a colon (<code>:</code>), or with two backslashes (<code>\\</code>). Since the value stored in <code>myPath</code> variable starts with <code>/</code>, therefore <code>isAbsolute()</code> returns <code>true</code>.  </li>
</ul>
<p>However, if you just change the <code>myPath</code> variable to this: <code>Desktop/NodeJSTut/app.js</code> (converting it to a relative path), <code>isAbsolute()</code> returns <code>false</code>.</p>
<ul>
<li><code>path.parse(myPath)</code>: This function accepts a path and returns an object which contains a detailed breakdown of the path provided to it. Here is what it returns when we provide the <code>myPath</code> variable to it:  </li>
<li><code>root</code>: The root of the path (in this case, <code>/</code>).  </li>
<li><code>dir</code>: The directory of the file (in this case, <code>/mnt/c/Desktop/NodeJSTut</code>).  </li>
<li><code>base</code>: The base file name (in this case, <code>app.js</code>).  </li>
<li><code>ext</code>: The file extension (in this case, <code>.js</code>).  </li>
<li><code>name</code>: The base name of the file, without the extension (in this case, <code>app</code>).</li>
</ul>
<p>Before continuing with the other functions of the <code>path</code> module, we need to understand something called <strong>path separator and the path structure</strong>. </p>
<p>You must have seen that the path to a same file looks different in different Operating Systems. For example, consider the path to a file named <code>example.txt</code> located in a folder called <code>Documents</code> on the desktop of a Windows user:</p>
<pre><code class="lang-text">C:\Users\username\Desktop\Documents\example.txt
</code></pre>
<p>On the other hand, the file path to the same file for a user on a macOS system would look like this:</p>
<pre><code class="lang-text">/Users/username/Desktop/Documents/example.txt
</code></pre>
<p>2 differences are to be noted here:</p>
<ol>
<li><strong>Difference in path separators:</strong> In Windows, file paths use the backslash (<code>\</code>) as the separator between directories, while in macOS/Linux (which is a Unix-based system), file paths use the forward slash (<code>/</code>) as the separator.</li>
<li><strong>Difference in root directory of the users files:</strong> On Windows, the root directory for a user's files is commonly found at <code>C:\Users\username</code>, whereas on macOS and Linux, it is located at <code>/Users/username/</code>. While this holds true for most Windows, macOS, and Linux systems, there may be some variations in the exact location of the user's home directory based on the system's configuration.</li>
</ol>
<p>With this in mind, let's move ahead and understand some other functions provided by the <code>path</code> module:</p>
<ul>
<li><code>path.sep</code>: <code>sep</code> is a variable which contains the system specific path separator. For Windows machine: <code>console.log(path.sep)</code> prints <code>\</code> in the console while in case of macOS or Linux, <code>path.sep</code> returns a forward slash ( <code>/</code> ).</li>
<li><code>path.join(&lt;paths&gt;)</code>: The <code>path.join()</code> function accepts path(s) as strings. It then joins those paths using the system specific path separator and returns the joined path. For example, consider this code:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(path.join(<span class="hljs-string">'grandParentFolder'</span>, <span class="hljs-string">'parentFolder'</span>, <span class="hljs-string">'child.txt'</span>))
</code></pre>
<p>The above code prints different results for different Operating Systems.<br>In Windows, it will give this output: <code>grandParentFolder\parentFolder\child.txt</code> while in macOS/Linux, it will give this output: <code>grandParentFolder/parentFolder/child.txt</code>. Note that the difference is only in the path separators - backward slash and forward slash.</p>
<ul>
<li><code>path.resolve(&lt;paths&gt;)</code>: This function works in a similar way as compared to <code>path.join()</code>. The <code>path.resolve()</code> function just joins the different paths provided to it using the system specific path separator and then appends the final output to the absolute path of the present working directory. </li>
</ul>
<p>Suppose you are a Windows user and the absolute path to your present working directory is this: <code>C:\Desktop\NodeJSTut</code>, If you run this code:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(path.resolve(<span class="hljs-string">'grandParentFolder'</span>, <span class="hljs-string">'parentFolder'</span>, <span class="hljs-string">'child.txt'</span>));
</code></pre>
<p> You will see the following output in the console:</p>
<pre><code class="lang-text">C:\Desktop\NodeJSTut\grandParentFolder\parentFolder\child.txt
</code></pre>
<p>The same is applicable to a macOS or a Linux user. It's just the difference in the absolute path of the present working directory and the path separator.</p>
<h2 id="heading-the-fs-module">The FS Module</h2>
<p>This module helps you with file handling operations such as:</p>
<ul>
<li>Reading a file (sync or async way)</li>
<li>Writing to a file (sync or async way)</li>
<li>Deleting a file</li>
<li>Reading the contents of a director</li>
<li>Renaming a file</li>
<li>Watching for changes in a file, and much more</li>
</ul>
<p>Let's perform some of these tasks to see the <code>fs</code> (File System) module in action below:</p>
<h3 id="heading-how-to-create-a-directory-using-fsmkdir">How to create a directory using <code>fs.mkdir()</code></h3>
<p>The <code>fs.mkdir()</code> function in Node.js is used to create a new directory. It takes two arguments: the path of the directory to be created and an optional callback function that gets executed when the operation is complete.</p>
<ul>
<li><strong>path</strong>: Here, path refers to the location where you want to create a new folder. This can be an absolute or a relative path. In my case, the path to the present working directory (the folder I am currently in), is: <code>C:\Desktop\NodeJSTut</code>. So, Let's create a folder in the <code>NodeJSTut</code> directory called <code>myFolder</code>.</li>
<li><strong>callback function:</strong> The purpose of the callback function is to notify that the directory creation process has completed. This is necessary because the <code>fs.mkdir()</code> function is asynchronous, meaning that it does not block the execution of the rest of the code while the operation is in progress. Instead, it immediately returns control to the callback function, allowing it to continue executing other tasks. Once the directory has been created, the callback function is called with an error object (if any) and any other relevant data related to the operation. In the below code, we are just using it to display a success message in the console or any error.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import fs module</span>
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

<span class="hljs-comment">// Present Working Directory: C:\Desktop\NodeJSTut</span>
<span class="hljs-comment">// Making a new directory called ./myFolder:</span>

fs.mkdir(<span class="hljs-string">'./myFolder'</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span>(err){
        <span class="hljs-built_in">console</span>.log(err);
    } <span class="hljs-keyword">else</span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Folder Created Successfully'</span>);
    }
})
</code></pre>
<p>After executing the above code, you will see a new folder called <code>myFolder</code> created in the <code>NodeJSTut</code> directory.</p>
<h3 id="heading-how-to-create-and-write-to-a-file-asynchronously-using-fswritefile">How to create and write to a file asynchronously using <code>fs.writeFile()</code></h3>
<p>After the <code>myFolder</code> directory is created successfully, it's time to create a file and write something to it by using the <code>fs</code> module. </p>
<p>There are basically 2 ways of doing this:</p>
<ul>
<li><strong>Synchronous Approach:</strong> In this approach, we create a file and write the data to it in a blocking manner, which means that NodeJS waits for the creation and write operation to complete before moving on to the next line of code. If an error occurs during this process, it throws an exception that must be caught using <code>try...catch</code>.</li>
<li><strong>Asynchronous Approach:</strong> In this approach, we create and write data to a file in a non-blocking manner, which means that NodeJS does not wait for the write operation to complete before moving on to the next line of code. Instead, it takes a callback function that gets called once the entire process is completed. If an error occurs during the write operation, the error object is passed to the callback function.</li>
</ul>
<p>In this tutorial, we will be using the <code>fs.writeFile()</code> function which follows the asynchronous approach.</p>
<p><code>writeFile()</code> is a method provided by the <code>fs</code> (file system) module in Node.js. It is used to write data to a file asynchronously. The method takes three arguments:</p>
<ol>
<li>The <strong>path</strong> of the file to write to (including the file name and extension)</li>
<li>The <strong>data</strong> to write to the file (as a string or buffer)</li>
<li>An optional <strong>callback function</strong> that is called once the write operation is complete or an error occurs during the write operation.</li>
</ol>
<p>When <code>writeFile()</code> is called, Node.js creates a new file or overwrites an existing file at the specified <strong>path</strong>. It then writes the provided <strong>data</strong> to the file and closes it. Since the method is asynchronous, the write operation does not block the event loop, allowing other operations to be performed in the meantime. </p>
<p>Below is the code where we create a new file called <code>myFile.txt</code> in the <code>myFolder</code> directory and write this <code>data</code> to it: <code>Hi,this is newFile.txt</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

<span class="hljs-keyword">const</span> data = <span class="hljs-string">"Hi,this is newFile.txt"</span>;

fs.writeFile(<span class="hljs-string">'./myFolder/myFile.txt'</span>, data, <span class="hljs-function">(<span class="hljs-params">err</span>)=&gt;</span> {
    <span class="hljs-keyword">if</span>(err){
        <span class="hljs-built_in">console</span>.log(err);
        <span class="hljs-keyword">return</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Writen to file successfully!'</span>);
    }
})
</code></pre>
<p>Since <code>newFile.txt</code> didn't exist previously, Hence the <code>writeFile()</code> function created this file for us on the provided path and then wrote the value in the <code>data</code> variable to the file. Suppose this file already existed. In that case, <code>writeFile()</code> will just open the file, erase all the existing text present in it and then write the data to it.</p>
<p>The problem with this code is: when you run the same code multiple times, it erases the previous data that is already present in <code>newFile.txt</code> and writes the data to it. </p>
<p>In case you do not want the original data to get deleted and just want the new data to be added/appended at the end of the file, you need to make a little change in the above code by adding this "options object": <code>{flag: 'a'}</code> as the third parameter to <code>writeFile()</code> – like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

<span class="hljs-keyword">const</span> data = <span class="hljs-string">'Hi,this is newFile.txt'</span>;

fs.writeFile(<span class="hljs-string">'./myFolder/myFile.txt'</span>, data, {<span class="hljs-attr">flag</span>: <span class="hljs-string">'a'</span>}, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span>(err){
        <span class="hljs-built_in">console</span>.log(err);
        <span class="hljs-keyword">return</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Writen to file successfully!'</span>);
    }
})
</code></pre>
<p>Once you run the above code again and again, you will see that the <code>myFile.txt</code> has the value of the <code>data</code> variable written to it multiple times. This is because the object (3rd parameter): <code>{flag: 'a'}</code> indicates the <code>writeFile()</code> method to append the <code>data</code> at the end of the file instead of erasing the previous data present in it.</p>
<h3 id="heading-how-to-read-a-file-asynchronously-using-fsreadfile">How to read a file asynchronously using <code>fs.readFile()</code></h3>
<p>After creating and writing to the file, it's time we learn how to read the data present in the file using the <code>fs</code> module.</p>
<p>Again there are 2 ways of doing this: Synchronous approach and the Asynchronous approach (just like the previous function). Here we are going to use the <code>readFile()</code> function provided by <code>fs</code> module which performs the reading operation asynchronously.</p>
<p>The <code>readFile()</code> function takes 3 parameters:</p>
<ol>
<li>The <strong>path</strong> to the file which is to be read.</li>
<li>The <strong>encoding</strong> of the file.</li>
<li>The <strong>callback function</strong> that gets executed once the reading operation is completed or if any error occurs during the reading operation. It accepts 2 parameters: first parameter stores the file data (if read operation is successful) and the second parameter stores the error object (if read operation fails due to some error).</li>
</ol>
<p>The <code>readFile()</code> function is very intuitive and once called, it reads the data present in the provided file according to the given encoding. If the read operation is successful, it returns the data to the callback function and if not, it will return the error occurred.</p>
<p>In the below code, we read the contents of the file - <code>myFile.txt</code> which we had created while learning the previous function and then log the data stored in it in the console.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

fs.readFile(<span class="hljs-string">'./myFolder/myFile.txt'</span>, {<span class="hljs-attr">encoding</span>: <span class="hljs-string">'utf-8'</span>}, <span class="hljs-function">(<span class="hljs-params">err, data</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span>(err){
        <span class="hljs-built_in">console</span>.log(err);
        <span class="hljs-keyword">return</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'File read successfully! Here is the data'</span>);
        <span class="hljs-built_in">console</span>.log(data);
    }
})
</code></pre>
<p>It is to be noted here that the <code>encoding</code> property is set to <code>'utf-8'</code>. At this point, some of you may not know about the encoding property, So Let's understand it in a bit more detail:</p>
<p>The <code>encoding</code> parameter in the <code>fs.readFile()</code> method of Node.js is used to specify the character encoding used to interpret the file data. By default, if no <code>encoding</code> parameter is provided, the method returns a raw buffer.</p>
<p>If the <code>readFile()</code> method is called without providing an <code>encoding</code> parameter, you will see a result similar to this printed in the console:</p>
<pre><code class="lang-javascript">&lt;Buffer <span class="hljs-number">54</span> <span class="hljs-number">68</span> <span class="hljs-number">69</span> <span class="hljs-number">73</span> <span class="hljs-number">20</span> <span class="hljs-number">69</span> <span class="hljs-number">73</span> <span class="hljs-number">20</span> <span class="hljs-number">73</span> <span class="hljs-number">6</span>f <span class="hljs-number">6</span>d <span class="hljs-number">65</span> <span class="hljs-number">20</span> <span class="hljs-number">64</span> <span class="hljs-number">61</span> <span class="hljs-number">74</span> <span class="hljs-number">61</span> <span class="hljs-number">20</span> <span class="hljs-number">69</span> <span class="hljs-number">6</span>e <span class="hljs-number">20</span> <span class="hljs-number">61</span> <span class="hljs-number">20</span> <span class="hljs-number">66</span> <span class="hljs-number">69</span> <span class="hljs-number">6</span>c <span class="hljs-number">65</span>&gt;
</code></pre>
<p>This raw buffer is difficult to read and interpret as it represents the contents of the file in binary form. To convert the buffer to a readable string, you can specify an <code>encoding</code> parameter when calling <code>readFile()</code>. </p>
<p>In our case, we specified the <code>'utf8'</code> encoding as the second parameter of the <code>readFile()</code> method. This tells Node.js to interpret the file contents as a string using the UTF-8 character encoding, thus you see the original data printed in the console. Other common encodings that can be used with <code>readFile()</code> include:</p>
<ul>
<li><code>'ascii'</code>: Interpret the file contents as ASCII-encoded text.</li>
<li><code>'utf16le'</code>: Interpret the file contents as 16-bit Unicode text in little-endian byte order.</li>
<li><code>'latin1'</code>: Interpret the file contents as ISO-8859-1 (also known as Latin-1) encoded text.</li>
</ul>
<h3 id="heading-reading-and-writing-to-a-file-synchronously">Reading and Writing to a File Synchronously</h3>
<p>Up until now, you have learned how to write to and read the data from a file asynchronously. But there are synchronous alternatives to the 2 functions we learnt above, namely: <code>readFileSync()</code> and <code>writeFileSync()</code>. </p>
<p>Note that since these are synchronous operations, they need to be wrapped in a <code>try...catch</code> block. In case the operations fail for some reason, the errors thrown will be caught by the <code>catch</code> block.</p>
<p>In the below code, we first create a new file: <code>./myFolder/myFileSync.txt</code> and write to it using the <code>writeFileSync()</code> method. Then we read the contents of the file using the <code>readFileSync()</code> method and print the data in the console:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

<span class="hljs-keyword">try</span>{
    <span class="hljs-comment">// Write to file synchronously</span>
    fs.writeFileSync(<span class="hljs-string">'./myFolder/myFileSync.txt'</span>, <span class="hljs-string">'myFileSync says Hi'</span>);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Write operation successful'</span>);

    <span class="hljs-comment">// Read file synchronously</span>
    <span class="hljs-keyword">const</span> fileData = fs.readFileSync(<span class="hljs-string">'./myFolder/myFileSync.txt'</span>, <span class="hljs-string">'utf-8'</span>);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Read operation successful. Here is the data:'</span>);
    <span class="hljs-built_in">console</span>.log(fileData);

} <span class="hljs-keyword">catch</span>(err){
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error occurred!'</span>);
    <span class="hljs-built_in">console</span>.log(err);
}
</code></pre>
<p>When you run the above code, a new file called <code>myFileSync.txt</code> is created in the <code>myFolder</code> directory and it contains the following text in it: <code>myFileSync says Hi</code>. This is the output printed in the console:</p>
<pre><code class="lang-text">Write operation successful
Read operation successful. Here is the data:
myFileSync says Hi
</code></pre>
<h3 id="heading-how-to-read-the-contents-of-a-directory-using-fsreaddir">How to read the contents of a directory using <code>fs.readdir()</code></h3>
<p>If you have been following along until now, you will see that we currently have 2 files in the <code>myFolder</code> directory, i.e, <code>myFile.txt</code> and <code>myFileSync.txt</code>. The <code>fs</code> module provides you with <code>readdir()</code> function using which you can read the contents of a directory (the files and folders present in the directory). </p>
<p>The <code>readdir()</code> function accepts 2 parameters:</p>
<ul>
<li>The <strong>path</strong> of the folder whose contents are to be read.</li>
<li><strong>Callback function</strong> which gets executed once the operation is completed or if any error occurs during the operation. This function accepts 2 parameters: The first one which accepts the error object (if any error occurs) and the second parameter which accepts an array of the various files and folders present in the directory whose path has been provided.</li>
</ul>
<p>In the code below, we are reading the contents of the <code>myFolder</code> directory and printing the result in the console.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

fs.readdir(<span class="hljs-string">'./myFolder'</span>, <span class="hljs-function">(<span class="hljs-params">err, files</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span>(err){
        <span class="hljs-built_in">console</span>.log(err);
        <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Directory read successfully! Here are the files:'</span>);
    <span class="hljs-built_in">console</span>.log(files);
})
</code></pre>
<p>This is what we get as output when we run the above code:</p>
<pre><code class="lang-text">[ 'myFile.txt', 'myFileSync.txt' ]
</code></pre>
<h3 id="heading-how-to-rename-a-file-using-fsrename">How to rename a file using <code>fs.rename()</code></h3>
<p>The <code>fs.rename()</code> method in Node.js is used to rename a file or directory. The method takes two arguments, the current file path and the new file path, and a callback function that is executed when the renaming is complete.</p>
<p>Here's the syntax for the <code>fs.rename()</code> method:</p>
<pre><code class="lang-javascript">fs.rename(oldPath, newPath, callback);
</code></pre>
<p>where:</p>
<ul>
<li><code>oldPath</code> (string) - The current file path</li>
<li><code>newPath</code> (string) - The new file path</li>
<li><code>callback</code> (function) - A callback function to be executed when the renaming is complete. This function takes an error object as its only parameter.</li>
</ul>
<p>Let's rename the <code>newFile.txt</code> file to <code>newFileAsync.txt</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

fs.rename(<span class="hljs-string">'./newFolder/newFile.txt'</span>, <span class="hljs-string">'./newFolder/newFileAsync.txt'</span>, <span class="hljs-function">(<span class="hljs-params">err</span>)=&gt;</span>{
    <span class="hljs-keyword">if</span>(err){
        <span class="hljs-built_in">console</span>.log(err);
        <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'File renamed successfully!'</span>)
})
</code></pre>
<p>Once you run the above code, you will see that the <code>newFile.txt</code> gets renamed to <code>newFileAsync.txt</code>.</p>
<p>Note that you should only provide valid paths (absolute or relative) to the <code>rename()</code> function and not just the names of the files. Remember it's <code>oldPath</code> and <code>newPath</code> and NOT <code>oldName</code> and <code>newName</code>.   </p>
<p>For example, consider this code: <code>fs.rename('./newFolder/newFile.txt', 'newFileAsync.txt', ...rest of the code)</code>. In this case, since we did not provide a proper path in the 2nd parameter, <code>rename()</code> assumes that the path to the newly named file should be: <code>./newFileAsync.txt</code>. Thus, it basically removes the <code>newFile.txt</code> from the <code>newFolder</code> directory, renames the file to <code>newFileAsync.txt</code> and moves it to the current working directory.</p>
<h3 id="heading-how-to-delete-a-file-using-fsunlink">How to delete a file using <code>fs.unlink()</code></h3>
<p>Last but not the least, we have the <code>fs.unlink()</code> function which is used to delete a file. It takes in 2 parameters:</p>
<ul>
<li>The path of the file which you want to delete, and</li>
<li>The callback function which gets executed once the delete operation is over or if any error occurs during the operation.</li>
</ul>
<p>Running the following code deletes the <code>newFileSync.txt</code> file present in the <code>myFolder</code> directory:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

fs.unlink(<span class="hljs-string">'./myFolder/myFileSync.txt'</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span>(err){
        <span class="hljs-built_in">console</span>.log(err);
        <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'File Deleted Successfully!'</span>)
})
</code></pre>
<h1 id="heading-event-driven-programming">Event-Driven Programming</h1>
<p>Ok, before we move forward to learn the HTTP Module and create our own servers, it's important to know about something called "Event driven programming".</p>
<p>Event-driven programming is a programming paradigm where program flow is largely determined by events or user actions, rather than by the program's logic. </p>
<p>In this type of programming, the program listens for events, and when they occur, it executes some code/function that should run in response to that event.</p>
<p>An event could be anything from a mouse click or a button press to the arrival of new data in the system.</p>
<p>The below image demonstrates how event driven programming works. In this form of programming, we write some code which constantly listens for a particular event and once that event occurs, we run some code in response to it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/23fd96e9-49ff-4607-a820-be6adef554b1.png" alt="Event Driven Programming Diagrammatic Representation" width="600" height="400" loading="lazy"></p>
<p>In this section of the tutorial we will be learning about events in NodeJS. Although we may not be using events directly for our day-to-day coding tasks, but a lot of NodeJS modules use the concept of events under the hood. This is why it becomes important to be aware about it.</p>
<p>To implement Event Driven Programming in NodeJS, You need to remember 2 things:</p>
<ul>
<li><p>There is a function called <code>emit()</code> which causes an event to occur.<br>For example, <code>emit('myEvent')</code> emits/causes an event called <code>myEvent</code>.  </p>
</li>
<li><p>There is another function called <code>on()</code> which is used to listen for a particular event and when this event occurs, the <code>on()</code> method executes a listener function in response to it. For example, Consider this code: <code>on('myEvent', myFunction)</code>: Here we are listening for an event called <code>myEvent</code> and when this event takes place, we run the <code>myFunction</code> listener function in response to it.</p>
</li>
</ul>
<p>We can access the <code>on()</code> and <code>emit()</code> functions by creating an instance of the <code>EventEmitter</code> class. The <code>EventEmitter</code> class can be imported from a built-in package called <code>events</code>.</p>
<p>In the below code, we are listening for the <code>userJoined</code> event and once this event takes place, we run the <code>welcomeUser()</code> function using the <code>on()</code> method and we emit the <code>userJoined</code> event using the <code>emit()</code> method:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Importing 'events' module and creating an instance of the EventEmitter Class</span>
<span class="hljs-keyword">const</span> EventEmitter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'events'</span>);
<span class="hljs-keyword">const</span> myEmitter = <span class="hljs-keyword">new</span> EventEmitter();

<span class="hljs-comment">// Listener Function - welcomeUser()</span>
<span class="hljs-keyword">const</span> welcomeUser = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hi There, Welcome to the server!'</span>);
}

<span class="hljs-comment">// Listening for the userJoined event using the on() method</span>
myEmitter.on(<span class="hljs-string">'userJoined'</span>, welcomeUser);

<span class="hljs-comment">// Emitting the userJoined event using the emit() method</span>
myEmitter.emit(<span class="hljs-string">'userJoined'</span>);
</code></pre>
<h3 id="heading-points-to-note">Points to Note:</h3>
<p>There are 3 points you should note while working with events in Node.<br>Each point in shown in action in the corresponding code snippets:</p>
<ul>
<li>There can be multiple <code>on()</code>'s for a single <code>emit()</code>:</li>
</ul>
<p>Check out the following code, where multiple <code>on()</code> functions are listening for a single event to happen (<code>userJoined</code> event) and when this event is emitted in the last line of the code using the <code>emit()</code> function, you will see that the all the listener functions which were attached to the <code>on()</code> function get's executed:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Importing `events` module and creating an instance of EventEmitter class</span>
<span class="hljs-keyword">const</span> EventEmitter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'events'</span>);
<span class="hljs-keyword">const</span> myEmitter = <span class="hljs-keyword">new</span> EventEmitter();

<span class="hljs-comment">// Listener Function 1: sayHello</span>
<span class="hljs-keyword">const</span> sayHello = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hello User'</span>);
}

<span class="hljs-comment">// Listener Function 2: sayHi</span>
<span class="hljs-keyword">const</span> sayHi = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hi User'</span>);
}

<span class="hljs-comment">// Listener Function 3: greetNewYear</span>
<span class="hljs-keyword">const</span> greetNewYear = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Happy New Year!'</span>);
}

<span class="hljs-comment">// Subscribing to `userJoined` event</span>
myEmitter.on(<span class="hljs-string">'userJoined'</span>, sayHello);
myEmitter.on(<span class="hljs-string">'userJoined'</span>, sayHi);
myEmitter.on(<span class="hljs-string">'userJoined'</span>, greetNewYear);

<span class="hljs-comment">// Emiting the `userJoined` Event</span>
myEmitter.emit(<span class="hljs-string">'userJoined'</span>);
</code></pre>
<p>You can think of it this way: Each time the <code>userJoined</code> event is emitted, a notification is sent to all the <code>on()</code> functions listening for the event and then all of them will run their corresponding listener functions: <code>sayHello</code>, <code>sayHi</code>, <code>greetNewYear</code>.</p>
<p>Thus, when you run the code, you will see the following output printed in the console:</p>
<pre><code class="lang-text">Hello User
Hi User
Happy New Year!
</code></pre>
<ul>
<li>The <code>emit()</code> can also contain arguments which will be passed to the listener functions:</li>
</ul>
<p>In the following code, We are using the <code>on()</code> method to subscribe to an event called <code>birthdayEvent</code> and when this event is emitted, we run the <code>greetBirthday()</code> function in response to it.  </p>
<p>The extra parameters mentioned in the <code>emit()</code> function, gets passed as parameters to all the listener functions which will run in response to the <code>birthdayEvent</code>. Therefore <code>John</code> and <code>24</code> gets passed as parameters to the <code>greetBirthday()</code> function.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> EventEmitter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'events'</span>);
<span class="hljs-keyword">const</span> myEvent = <span class="hljs-keyword">new</span> EventEmitter();

<span class="hljs-comment">// Listener function</span>
<span class="hljs-keyword">const</span> greetBirthday = <span class="hljs-function">(<span class="hljs-params">name, newAge</span>) =&gt;</span> {
    <span class="hljs-comment">// name = John</span>
    <span class="hljs-comment">// newAge = 24</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Happy Birthday <span class="hljs-subst">${name}</span>. You are now {newAge}!`</span>);
}

<span class="hljs-comment">// Listening for the birthdayEvent</span>
myEmitter.on(<span class="hljs-string">'birthdayEvent'</span>, greetBirthday);

<span class="hljs-comment">// Emitting the birthdayEvent with some extra parameters</span>
myEmitter.emit(<span class="hljs-string">'birthdayEvent'</span>, <span class="hljs-string">'John'</span>, <span class="hljs-string">'24'</span>);
</code></pre>
<p>The following output will be seen printed in the console: <code>Happy Birthday John, You are now 24!</code>.</p>
<ul>
<li>The <code>emit()</code> function should always be defined after the <code>on()</code> function(s):</li>
</ul>
<p>The entire process of communication between <code>on()</code> and <code>emit()</code> works like this: Before emitting any event, you need to make sure that all the listener functions have subscribed/registered to that event. Any function which is registered as a listener after the event has been emitted, will not be executed.</p>
<p>Check out the following code where this process is studied in detail:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> EventEmitter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'events'</span>);
<span class="hljs-keyword">const</span> myEmitter = <span class="hljs-keyword">new</span> EventEmitter();

<span class="hljs-comment">// Listener Function 1 - sayHi</span>
<span class="hljs-keyword">const</span> sayHi = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hi User'</span>);
}

<span class="hljs-comment">// Listener Function 2 - sayHello</span>
<span class="hljs-keyword">const</span> sayHello = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hello User'</span>);
}

<span class="hljs-comment">// Registering sayHi function as listener</span>
myEmitter.on(<span class="hljs-string">'userJoined'</span>, sayHi);

<span class="hljs-comment">// Emitting the event</span>
myEmitter.emit(<span class="hljs-string">'userJoined'</span>);

<span class="hljs-comment">// Registering sayHello function as listener</span>
myEmitter.on(<span class="hljs-string">'userJoined'</span>, sayHello);
</code></pre>
<p>When the above code is executed, we see <code>Hi User</code> printed in the console but <code>Hello User</code> is not printed. </p>
<p>The reason behind this is: First we had registered the <code>sayHi</code> function as the listener using <code>myEmitter.on('userJoined', sayHi)</code>. Next we emit the <code>userJoined</code> event which results in execution of the <code>sayHi</code> function. In the next line we are registering the <code>sayHello</code> function as the listener, but it's already too late to do this because <code>userJoined</code> event has been emitted. This signifies the importance of defining all the <code>on()</code> functions before we emit the event using <code>emit()</code>.</p>
<p>You can also think of it this way: When you use <code>emit()</code> to trigger an event, NodeJS looks for any corresponding <code>on()</code> methods that have been defined in your code above the <code>emit()</code> method. If it finds any, it will execute them in order to handle the event.</p>
<h2 id="heading-the-http-module">The HTTP Module</h2>
<p>Let's move forward and learn the HTTP Module which helps you create Web Servers.</p>
<p>HTTP stands for Hypertext Transfer Protocol. It is used to transfer data over the internet which allows communication between clients and servers. </p>
<p>Suppose you want to watch some YouTube videos, you go to your web browser and type in: <a target="_blank" href="https://youtube.com">https://youtube.com</a>, and then YouTube's home page gets displayed on your screen. This entire process happened because of communication between your machine (client) and YouTube's Server. The client, in this case, your machine requested for YouTube's home page and the server sent back the HTML, CSS and JS Files as the response.</p>
<p>The client sends a request to the server in the form of a URL with some additional information, such as headers and query parameters.</p>
<p>The server processes the request, performs necessary operations, and sends a response back to the client. The response contains a status code, headers, and the response body with the requested data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/9ef9b0bc-2b5c-433e-b39e-439993d53982.png" alt="Client sends request to the server for some resources and the server sends back those resources as responses." width="600" height="400" loading="lazy">
_<a target="_blank" href="https://res.cloudinary.com/diqqf3eq2/image/upload/v1613596625/course%20slides/http-messages_lugv8b.png">Source: https://course-api.com/slides/</a>_</p>
<h2 id="heading-components-of-request-response">Components Of Request-Response</h2>
<p>Both the Request (sent by client to the server) and the Response (sent by server to the client) comprises of 3 parts:</p>
<ol>
<li><strong>The Status Line</strong>: This is the first line of the request or response. It contains information about the message, such as the method used, URL, protocol version, and so on.</li>
<li><strong>The Header</strong>: This is a collection of key-value pairs, separated by colon.<br>The headers include additional information about the message such as the content type, content length, caching information, and so on.</li>
<li><strong>The Body</strong>: The Body contains the actual data being sent or received. In the case of requests, it might contain form data or query parameters. In the case of responses, it could be HTML, JSON, XML, or any other data format.</li>
</ol>
<p>The 3 components of a Request and Response are described in much more detail in the below image:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/9e0fc122-3902-4284-9907-d0713bfbd0b1.png" alt="Request and Response Object Visual Representation" width="600" height="400" loading="lazy">
_<a target="_blank" href="https://res.cloudinary.com/diqqf3eq2/image/upload/v1614137856/course%20slides/http-req-res_bslzni.png">Source: https://course-api.com/slides/</a>_</p>
<h2 id="heading-what-are-http-methods">What are HTTP Methods?</h2>
<p>HTTP methods, also known as HTTP verbs, are actions that a Client can perform on a Server. The 4 HTTP Methods are:</p>
<ul>
<li>GET: Retrieves a resource from the server</li>
<li>POST: Inserts a resource in the server</li>
<li>PUT: Updates an existing resource in the server</li>
<li>DELETE: Deletes a resource from the server</li>
</ul>
<p>This might sound complicated, but let's try to understand these methods with the help of an example:</p>
<ol>
<li><strong>GET:</strong> Retrieves a resource from the server<br>When you enter <a target="_blank" href="http://www.google.com"><code>http://www.google.com</code></a> in your web browser's address bar and press enter, your browser sends a HTTP GET request to the Google server asking for the HTML content of the Google homepage. That's then rendered and displayed by your browser.</li>
<li><strong>POST</strong>: Inserts a resource in the server<br>Imagine you're filling out a registration form to create an account on Google. When you submit the form, your browser sends a POST request to Google's server with the data you typed in the form fields like: Username, Age, Birthdate, Address, Phone Number, Email, Gender and so on.  </li>
</ol>
<p>The server will then create a new user account in its database storing all the information sent to it using the POST Request. So a POST request is used to add/insert a resource in the server.</p>
<ol start="3">
<li><strong>PUT</strong>: Updates an existing resource in the server<br>Now imagine you want to update your Google account's password. You would send a PUT request to the server with the new password. The server would then update your user account in its database with the new password.</li>
<li><strong>DELETE</strong>: Deletes a resource from the server<br>Finally, imagine you want to delete your Google user account. You would send a DELETE request to the server indicating that you want your account to be deleted. The server would then delete your user account from its database.</li>
</ol>
<p>Note that these are just examples. The actual requests and their purposes may vary.</p>
<p>To see more examples of HTTP Methods, you can refer this image:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/577c1df7-def5-42dd-ac65-2e3a15b72288.png" alt="Some examples of different HTTP Methods" width="600" height="400" loading="lazy">
_<a target="_blank" href="https://res.cloudinary.com/diqqf3eq2/image/upload/v1614201237/course%20slides/http-methods_w5lppa.png">Source: https://course-api.com/slides/</a>_</p>
<h2 id="heading-what-is-a-status-code">What is a Status Code?</h2>
<p>HTTP status codes are three-digit numbers that indicate the status of a HTTP request made to a server. They are server responses that provide information about the request's outcome. Here are some of the most common HTTP status codes and what they represent:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/5ccaff5a-0f68-4f19-90a9-bd21202a633a.png" alt="Tabular representation of the different status codes, their meaning and description" width="600" height="400" loading="lazy"></p>
<h1 id="heading-lets-create-a-server">Let's Create a Server</h1>
<p>Finally let's move to the good part 🥳🔥 and learn how to create a Web Server using the <code>http</code> module:</p>
<p><strong>Step 1:</strong> Import the <code>http</code> module like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);
</code></pre>
<p><strong>Step 2:</strong> The <code>http</code> module provides you with <code>http.createServer()</code> function which helps you create a server. This function accepts a callback function with 2 parameters – <code>req</code> (which stores the incoming request object) and <code>res</code> which stands for the response to be sent by the server. This callback function gets executed every time someone hits the server. </p>
<p>This is how we can create a server using the <code>createServer()</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);

<span class="hljs-keyword">const</span> server = http.createServer(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.end(<span class="hljs-string">'Hello World'</span>);
})
</code></pre>
<p>Note: <code>res.send()</code> is a function attached on the <code>res</code> object using which we can send some data back to the client. Here once we are done setting up the server, you will see a <code>Hello World</code> message in your web browser.</p>
<p><strong>Step 3:</strong> Listening the server at some port using the <code>listen()</code> method.</p>
<p>The <code>listen()</code> function in Node.js <code>http</code> module is used to start a server that listens for incoming requests. It takes a port number as an argument and binds the server to that port number so that it can receive incoming requests on that port.</p>
<p>In the below code, we use the <code>listen()</code> function to start the server and bind it to port 5000. The second argument to the <code>listen()</code> function is a callback function that is executed when the server starts listening on the specified port. We are using this callback function just to display a success message in the console.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);

<span class="hljs-keyword">const</span> server = http.createServer(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.end(<span class="hljs-string">'Hello World'</span>);
})

server.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 listening at port 5000'</span>);
})
</code></pre>
<p>You are likely to see a  <code>Hello World</code> message when you visit this URL: <a target="_blank" href="http://localhost:5000/">http://localhost:5000/</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image.png" alt="Image of what the web browser displays when I visit localhost:5000 -> Hello World Message" width="600" height="400" loading="lazy"></p>
<p>If you try to visit some other port like 5001 (<a target="_blank" href="http://localhost:5001/">http://localhost:5001/</a>), which is not bound to your server, you won't see any response because your server is not listening on that port. You will likely receive an error message stating that the connection to the server could not be established.</p>
<p>At this point, we've made a server that renders a simple <code>Hello World</code> message every time someone tries to access it. This is quite good but there is a problem....</p>
<p>The problem is that for every route, the server sends the same message. For example, if I try to access the about page or the contact page, still the server shows the same message:</p>
<ul>
<li><a target="_blank" href="http://localhost:5000/">http://localhost:5000/</a> -&gt; Hello World</li>
<li><a target="_blank" href="http://localhost:5000/">http://localhost:5000/about</a> -&gt; Hello World</li>
<li><a target="_blank" href="http://localhost:5000/contact">http://localhost:5000/contact</a> -&gt; Hello World</li>
</ul>
<p>There is a simple way to fix this: there's a property called <code>url</code> in the <code>req</code> object which gives the URL of the request or in other words it tells you about the resource the client is trying to access.</p>
<p>Suppose if I type in: <strong><a target="_blank" href="http://localhost:5000/about">http://localhost:5000/about</a></strong> in my web browser's search bar, this means I am performing a GET Request on the server and I am trying to access the <code>/about</code> page. So In this case the value of <code>req.url</code> will be <code>/about</code>.</p>
<p>Similarly for the below requests, the value of <code>req.url</code> will be:</p>
<table>
<thead>
<tr>
<th><strong>URL</strong></th>
<th><code>req.url</code></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong><a href="http://localhost:5000">http://localhost:5000</a></strong></td>
<td><code>/</code></td>
</tr>
<tr>
<td><strong><a href="http://localhost:5000/about">http://localhost:5000/about</a></strong></td>
<td><code>/about</code></td>
</tr>
<tr>
<td><strong><a href="http://localhost:5000/contact">http://localhost:5000/contact</a></strong></td>
<td><code>/contact</code></td>
</tr>
<tr>
<td><strong><a href="http://localhost:5000/error">http://localhost:5000/error</a></strong></td>
<td><code>/error</code></td>
</tr>
</tbody>
</table>

<p>We can use some conditionals <code>if...else</code> along with the <code>req.url</code> property to make our server respond to different requests differently. This is how we can achieve this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);

<span class="hljs-keyword">const</span> server = http.createServer(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span>(req.url === <span class="hljs-string">'/'</span>){
        res.end(<span class="hljs-string">'This is my Home Page'</span>);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(req.url === <span class="hljs-string">'/about'</span>){
        res.end(<span class="hljs-string">'This is my About Page'</span>);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(req.url === <span class="hljs-string">'/contact'</span>){
        res.end(<span class="hljs-string">'This is my Contact Page'</span>);
    } <span class="hljs-keyword">else</span> {
        res.end(<span class="hljs-string">'404, Resource Not Found'</span>);
    }
})

server.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 listening at port 5000'</span>);
})
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/a087f16b-6eee-45f3-9875-bfd0cc2f4982--1-.png" alt="Image of the different responses the server provides upon visiting different URL's" width="600" height="400" loading="lazy"></p>
<p>Now we have a perfect server that responds to different requests differently. We are sending back responses using a method called <code>res.end()</code>. But there is an even better way of sending back a response in which we can add on 2 more methods along with <code>res.end()</code>:</p>
<ol>
<li><code>res.writeHead()</code> – This method is used to send the response headers to the client. The status code and headers like <code>content-type</code> can be set using this method.</li>
<li><code>res.write()</code> – This method is used to send the response body to the client.</li>
<li><code>res.end()</code> – This method is used to end the response process.</li>
</ol>
<p>Below is the modified code where we added the <code>writeHead()</code> and <code>write()</code> methods along with <code>end()</code> method:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);

<span class="hljs-keyword">const</span> server = http.createServer(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span>(req.url === <span class="hljs-string">'/'</span>){
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span>});
        res.write(<span class="hljs-string">'&lt;h1&gt;Home Page&lt;/h1&gt;'</span>);
        res.end();
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(req.url === <span class="hljs-string">'/about'</span>){
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span>});
        res.write(<span class="hljs-string">'&lt;h1&gt;About Page&lt;/h1&gt;'</span>);
        res.end();
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(req.url === <span class="hljs-string">'/contact'</span>){
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span>});
        res.write(<span class="hljs-string">'&lt;h1&gt;Contact Page&lt;/h1&gt;'</span>);
        res.end();
    } <span class="hljs-keyword">else</span> {
        res.writeHead(<span class="hljs-number">404</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span>});
        res.write(<span class="hljs-string">'&lt;h1&gt;404, Resource Not Found &lt;a href="/"&gt;Go Back Home&lt;/a&gt;&lt;/h1&gt;'</span>);
        res.end();
    }
})

server.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 listening at port 5000'</span>);
})
</code></pre>
<p>The below image shows what the server sends back as response when we visit multiple URL's:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/91ab5e0d-0368-4619-ba99-059099b26252--1-.png" alt="Image of the different HTML responses the server provides upon visiting different URL's" width="600" height="400" loading="lazy"></p>
<p>Let's break down what's happening in the above code:</p>
<ol>
<li>Here we are responding differently to different incoming requests by using the <code>req.url</code> property.</li>
<li>In every response, we are doing 3 things:<br>– Setting the response header using the <code>res.writeHead()</code> method. Here we provide 2 parameters to <code>res.writeHead()</code>: the status code and an object which has the <code>content-type</code> property set to <code>text/html</code><br>– Setting the response body using the <code>res.write()</code> method. Note that instead of sending simple messages, we are actually sending some HTML code in this case,<br>– And closing the response process using the <code>res.end()</code> method.</li>
<li>In case of resources like: <code>/</code>, <code>/about</code> and <code>/contact</code> the status code is set to <code>200</code> which means that the request to access a resource was successful. But if the client tries to access some other resource, they simply get back an error message and the status code is set to <code>404</code>.</li>
<li>Here the <code>'content-type': 'text/html'</code> is a way of telling the browser how it should interpret and display the response. In this case, we are telling the browser to interpret the response as some HTML code. There are different <code>content-type</code>'s for different types of responses:<br>– To send back JSON data as a response, we need to set the <code>content-type</code> to <code>application/json</code><br>– To send back CSS as a response, the <code>content-type</code> should be <code>text/css</code><br>– To send back JavaScript code as a response, the <code>content-type</code> should be <code>text/javascript</code>, and so on...</li>
</ol>
<p>Setting the content type is very important as it determines how the web browser interprets the response. For example: if we just change the content-type from <code>text/html</code> to <code>text/plain</code>, this is how the response will be displayed in the web browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/cd1d0d0b-c224-4970-8dde-5212733892d7--1-.png" alt="Changing the content type from text/html to text/plain to see the change in response" width="600" height="400" loading="lazy"></p>
<h1 id="heading-lets-serve-something-interesting">Let's Serve Something Interesting</h1>
<p>Up until now you've learned how to set up web servers but we haven't built anything interesting. So let's add some fun to our lives.</p>
<p>In the last section of this tutorial, we will be serving this navbar:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1680026253758/29c08d70-df1b-4dbf-ae30-552b41cba12b.gif" alt="Animated GIF of the navbar that we we will be serving from our server" width="600" height="315" loading="lazy"></p>
<p>Since this is not a front-end related tutorial, we will not be building this navbar from scratch. Instead, you can head over to this GitHub repo and copy the contents of the <code>navbar-app</code> directory and set it up locally: <a target="_blank" href="https://github.com/john-smilga/node-express-course/tree/main/02-express-tutorial/navbar-app">John Smilga's GitHub repo</a>. The idea is to:</p>
<ol>
<li>Set up the <code>navbar-app</code> folder locally</li>
<li>Use the <code>fs</code> module to read the contents of the HTML, CSS, JS file and the Logo</li>
<li>Using the <code>http</code> Module to render the files when someone tries to access the <code>/</code> route or the home page. So Let's Get Started:</li>
</ol>
<p>In the below code, we are using the <code>fs</code> module's <code>readFileSync()</code> method to read the contents of the HTML, CSS, JS file and the Logo. </p>
<p>Note that we are going to serve the contents of the file and not the file itself. So <code>readFileSync()</code> comes into picture.</p>
<p>Then, we serve the contents of the HTML file (stored in <code>homePage</code> variable) using the <code>res.write()</code> method. Remember to set the <code>content-type</code> as <code>text/html</code> as we are serving HTML content. We have also set up responses for <code>/about</code> route and also a 404 page.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

<span class="hljs-comment">// Get the contents of the HTML, CSS, JS and Logo files</span>
<span class="hljs-keyword">const</span> homePage = fs.readFileSync(<span class="hljs-string">'./navbar-app/index.html'</span>);
<span class="hljs-keyword">const</span> homeStyles = fs.readFileSync(<span class="hljs-string">'./navbar-app/style.css'</span>);
<span class="hljs-keyword">const</span> homeLogo = fs.readFileSync(<span class="hljs-string">'./navbar-app/logo.svg'</span>);
<span class="hljs-keyword">const</span> homeLogic = fs.readFileSync(<span class="hljs-string">'./navbar-app/browser-app.js'</span>);

<span class="hljs-comment">// Creating the Server</span>
<span class="hljs-keyword">const</span> server = http.createServer(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> url = req.url;
    <span class="hljs-keyword">if</span>(url === <span class="hljs-string">'/'</span>){
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span>});
        res.write(homePage);
        res.end();
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(url === <span class="hljs-string">'/about'</span>){
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span>});
        res.write(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>About Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>);
        res.end();
    } <span class="hljs-keyword">else</span>{
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span>});
        res.write(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>404, Resource Not Found<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>);
        res.end();
    }
})

server.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 listening at port 5000'</span>);
})
</code></pre>
<p>When you run this code using <code>node app.js</code> command, you will see these responses sent by the server for the following routes:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/c5892af9-1fff-49b4-af43-2c6db6053b9d.png" alt="Image of the different HTML responses the server sends upon visiting different URL's. Here we see only the HTML Structure of the navbar, the CSS, Logo and JS is missing" width="600" height="400" loading="lazy"></p>
<p>We see that the other routes work fine, but the home page doesn't look as we expected. The problem is that we only see the HTML Structure of the navbar being displayed and not the other stuff like the CSS, logo, and JavaScript.</p>
<p>Let's see what the bug is. We can check what requests are being made by the web browser to the server by modifying the above code like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ... above code</span>
<span class="hljs-keyword">const</span> server = http.createServer(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> url = req.url;
    <span class="hljs-built_in">console</span>.log(url);

    <span class="hljs-comment">// ... rest of the code</span>
})
</code></pre>
<p>Here we are simply printing the <code>url</code> of the request being made by the client to the server.</p>
<p>Once we refresh the page, we see that initially the browser asks for the home page and makes a GET request with the <code>/</code> URL. Afterward it makes 3 more requests:</p>
<ul>
<li><code>/style.css</code> – asking for the CSS file</li>
<li><code>/browser-app.js</code> – asking for the JS file</li>
<li><code>/logo.svg</code> – asking for the logo</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-2.png" alt="An image of the console showing the req.url property of the different requests: /, /style.css, /browser-app.js and /logo.svg" width="600" height="400" loading="lazy"></p>
<p><strong>From this, we can infer how browsers work.</strong></p>
<p>The browser makes request for the contents of the <code>/</code> path and the server just sends back the HTML content. Once the browser receives the HTML content, it interprets it and starts displaying the elements. While parsing HTML, if the browser encounters any additional resource like a CSS page or JS page, it will make a request to the server for the same.</p>
<p>Since we are not sending the CSS, JS and Logo in the response, we do not see them on the screen. We can fix this by adding some more <code>if()</code>s in the code and sending those resources which the browser asks for and BOOM – this bug is fixed.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

<span class="hljs-comment">// Get the contents of the HTML, CSS, JS and Logo files</span>
<span class="hljs-keyword">const</span> homePage = fs.readFileSync(<span class="hljs-string">'./navbar-app/index.html'</span>);
<span class="hljs-keyword">const</span> homeStyles = fs.readFileSync(<span class="hljs-string">'./navbar-app/style.css'</span>);
<span class="hljs-keyword">const</span> homeLogo = fs.readFileSync(<span class="hljs-string">'./navbar-app/logo.svg'</span>);
<span class="hljs-keyword">const</span> homeLogic = fs.readFileSync(<span class="hljs-string">'./navbar-app/browser-app.js'</span>);

<span class="hljs-comment">// Creating the Server</span>
<span class="hljs-keyword">const</span> server = http.createServer(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> url = req.url;
    <span class="hljs-keyword">if</span>(url === <span class="hljs-string">'/'</span>){
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span>});
        res.write(homePage);
        res.end();
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(url === <span class="hljs-string">'/style.css'</span>){
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/css'</span>});
        res.write(homeStyles);
        res.end();
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(url === <span class="hljs-string">'/browser-app.js'</span>){
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/javascript'</span>});
        res.write(homeLogic);
        res.end();
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(url === <span class="hljs-string">'/logo.svg'</span>){
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'image/svg+xml'</span>});
        res.write(homeLogo);
        res.end();
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(url === <span class="hljs-string">'/about'</span>){
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span>});
        res.write(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>About Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>);
        res.end();
    } <span class="hljs-keyword">else</span>{
        res.writeHead(<span class="hljs-number">200</span>, {<span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span>});
        res.write(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>404, Resource Not Found<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>);
        res.end();
    }
})

server.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 listening at port 5000'</span>);
})
</code></pre>
<p>Now we can see the HTML, CSS, Logo and the JS Functionality present:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/somerandomImage--1-.png" alt="Image of the Navbar served by the server" width="600" height="400" loading="lazy"></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>With this we come to the end of this tutorial – I hope you liked it and learned a lot about Node. </p>
<p>Do share your learnings from this guide on Twitter and LinkedIn (#LearnInPublic) and follow freeCodeCamp for more such informative coding articles.</p>
<p>Connect with me on Twitter: <a target="_blank" href="https://twitter.com/Krish4856">Twitter - Krish4856</a>, DMs Open. </p>
<p>See you next time 👋 ❤️ ✨</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The GraphQL API Handbook – How to Build, Test, Consume and Document GraphQL APIs ]]>
                </title>
                <description>
                    <![CDATA[ Hi everyone! In this tutorial we're going to take a deep dive into GraphQL APIs. I recently wrote this article where I explained the main differences between common API types nowadays. And this tutorial aims to show you an example of how you can full... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/building-consuming-and-documenting-a-graphql-api/</link>
                <guid isPermaLink="false">66d45ef1230dff0166905805</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GraphQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ German Cocca ]]>
                </dc:creator>
                <pubDate>Tue, 02 May 2023 13:23:30 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/jj-ying-8bghKxNU1j0-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hi everyone! In this tutorial we're going to take a deep dive into GraphQL APIs.</p>
<p>I recently wrote <a target="_blank" href="https://www.freecodecamp.org/news/rest-vs-graphql-apis/">this article</a> where I explained the main differences between common API types nowadays. And this tutorial aims to show you an example of how you can fully implement a GraphQL API.</p>
<p>We'll cover basic setup and architecture with Node and Apollo GraphQL, unit testing with Supertest, seeing how we can consume the API from a React front-end app using Apollo client and finally documenting the API using Apollo sandbox.</p>
<p>Keep in mind we won't go too deep into how each technology works. The goal here is to give you a general overview of how a GraphQL API works, how its pieces interact, and what a full implementation might consist of.</p>
<p>Let's go!</p>
<h1 id="heading-table-of-contents"><strong>Table of Contents</strong></h1>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-graphql">What is GraphQL?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-core-graphql-concepts">Core GraphQL concepts</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-object-types">Object Types</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-queries">Queries</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-mutations">Mutations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-resolvers">Resolvers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-schemas">Schemas</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tldr-and-comparison-with-equivalent-rest-concepts">TLDR and comparison with equivalent REST concepts</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-a-graphql-api-with-node-and-apollo-graphql">How to Build a GraphQL API with Node and Apollo GraphQL</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-a-graphql-api-with-supertest">How to Test a GraphQL API with Supertest</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-consume-a-graphql-api-on-a-front-end-react-app">How to Consume a GraphQL API on a Front-end React App</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-document-a-graphql-api-with-apollo-sandbox">How to Document a GraphQL API with Apollo sandbox</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping up</a></p>
</li>
</ul>
<h1 id="heading-what-is-graphql">What is GraphQL?</h1>
<p><a target="_blank" href="https://graphql.org/">GraphQL</a> is a query language and runtime for APIs that was developed by Facebook in 2012. It was released to the public in 2015 and has since gained popularity as an alternative to REST APIs.</p>
<p>GraphQL was originally developed by Facebook as a way to simplify data fetching for their mobile applications. They needed a way to make complex data requests from the server without causing performance issues or over-fetching data. GraphQL was born out of the need to solve these problems.</p>
<p>GraphQL was released as an open-source project in 2015 and has since gained popularity in the developer community. It is now supported by many development tools and frameworks, including Apollo, Prisma, and Hasura.</p>
<p><strong>Main Characteristics:</strong></p>
<ol>
<li><p><strong>Strongly Typed:</strong> GraphQL APIs are strongly typed, which means that each field has a specific data type. This makes it easier to validate and handle data on the client and server sides.</p>
</li>
<li><p><strong>Query Language:</strong> GraphQL has its own query language that allows clients to specify exactly what data they need. This reduces over-fetching of data and improves performance.</p>
</li>
<li><p><strong>Single Endpoint:</strong> GraphQL APIs have a single endpoint, which means that clients can fetch all the data they need from a single request.</p>
</li>
<li><p><strong>Declarative:</strong> GraphQL APIs are declarative, which means that clients specify what they want, not how to get it. This allows for more efficient and flexible data fetching.</p>
</li>
<li><p><strong>Schema-Driven:</strong> GraphQL APIs are schema-driven, which means that the schema defines the structure of the data and the available queries and mutations. This makes it easier for developers to understand and work with the API.</p>
</li>
</ol>
<p><strong>Pros:</strong></p>
<ul>
<li><p><strong>Efficient Data Fetching:</strong> GraphQL APIs allow clients to fetch only the data they need, reducing over-fetching and improving performance.</p>
</li>
<li><p><strong>Strongly Typed:</strong> GraphQL APIs are strongly typed, making it easier to validate and handle data.</p>
</li>
<li><p><strong>Single Endpoint:</strong> GraphQL APIs have a single endpoint, reducing the complexity of the API and making it easier to work with.</p>
</li>
<li><p><strong>Schema-Driven:</strong> GraphQL APIs are schema-driven, which makes it easier for developers to understand and work with the API.</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p><strong>Complexity:</strong> GraphQL APIs can be more complex to set up and work with compared to REST APIs.</p>
</li>
<li><p><strong>Caching:</strong> Caching can be more challenging with GraphQL APIs due to the flexible nature of the API.</p>
</li>
<li><p><strong>Learning Curve:</strong> GraphQL requires a learning curve for both developers and clients, as it has its own query language and approach to data fetching.</p>
</li>
</ul>
<p><strong>Best for:</strong></p>
<ul>
<li><p><strong>Efficient and flexible needs:</strong> GraphQL is well-suited for building applications that require efficient and flexible data fetching, such as mobile and web applications.</p>
</li>
<li><p><strong>Complex data requirements:</strong> It is particularly useful in situations where there are complex data requirements and where over-fetching data can cause performance issues.</p>
</li>
</ul>
<p>So to recap, GraphQL is a query language and runtime for APIs that provides efficient and flexible data fetching capabilities.</p>
<p>While it can be more complex to set up and work with compared to REST APIs, it offers benefits such as strongly typed data, single endpoints, and schema-driven development. It is well-suited for building applications with complex data requirements and where efficient data fetching is important.</p>
<h1 id="heading-core-graphql-concepts">Core GraphQL Concepts</h1>
<p>Before we jump into building stuff, there are some core GraphQL concepts you need to understand in order to know what you're doing and how the code will work.</p>
<h2 id="heading-object-types">Object Types</h2>
<p>In GraphQL, an Object Type is a complex type that represents a collection of fields. <strong>Object Types are used to define the structure of data that can be queried and mutated</strong> through a GraphQL API.</p>
<p>Each Object Type has a unique name and a set of fields, where each field has a name and a type. The type of a field can be a scalar type (such as Int, String, or Boolean), another Object Type, or a list of another type.</p>
<p>If you're familiar with <a target="_blank" href="https://www.freecodecamp.org/news/an-introduction-to-typescript/#interfaces">Typescript and interfaces</a>, this might ring a bell or two for you.</p>
<p>Here's an example of an Object Type that represents a "User" in a social media application:</p>
<pre><code class="lang-yaml"><span class="hljs-string">type</span> <span class="hljs-string">User</span> {
  <span class="hljs-attr">id:</span> <span class="hljs-string">ID!</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">String!</span>
  <span class="hljs-attr">email:</span> <span class="hljs-string">String!</span>
  <span class="hljs-attr">friends:</span> [<span class="hljs-string">User!</span>]<span class="hljs-string">!</span>
}
</code></pre>
<p>The <code>!</code> sign means the field is mandatory.</p>
<p>In this example, the "User" Object Type has four fields: "id", "name", "email", and "friends". The "id" field has a type of ID, which is a built-in scalar type in GraphQL that represents a unique identifier. The "name" and "email" fields have a type of String, and the "friends" field has a type of a list of "User" Objects.</p>
<p>Here's another example of an Object Type that represents a "Book" in a library application:</p>
<pre><code class="lang-yaml"><span class="hljs-string">type</span> <span class="hljs-string">Book</span> {
  <span class="hljs-attr">id:</span> <span class="hljs-string">ID!</span>
  <span class="hljs-attr">title:</span> <span class="hljs-string">String!</span>
  <span class="hljs-attr">author:</span> <span class="hljs-string">Author!</span>
  <span class="hljs-attr">genre:</span> <span class="hljs-string">String!</span>
  <span class="hljs-attr">published:</span> <span class="hljs-string">Int!</span>
}
</code></pre>
<p>In this example, the "Book" Object Type has five fields: "id", "title", "author", "genre", and "published". The "id" field has a type of ID, the "title" and "genre" fields have a type of String, the "published" field has a type of Int, and the "author" field has a type of an "Author" Object.</p>
<p>Object Types can be used to define the structure of data that is returned from a query or mutation in a GraphQL API. For example, a query that returns a list of users might look like this:</p>
<pre><code class="lang-yaml"><span class="hljs-string">query</span> {
  <span class="hljs-string">users</span> {
    <span class="hljs-string">id</span>
    <span class="hljs-string">name</span>
    <span class="hljs-string">email</span>
    <span class="hljs-string">friends</span> {
      <span class="hljs-string">id</span>
      <span class="hljs-string">name</span>
    }
  }
}
</code></pre>
<p>In this query, the "users" field returns a list of "User" Objects, and the query specifies which fields to include in the response.</p>
<h2 id="heading-queries">Queries</h2>
<p>In GraphQL, <strong>a query is a request for specific data from the server</strong>. The query specifies the shape of the data that the client wants to receive, and the server responds with the requested data in the same shape.</p>
<p>A query in GraphQL follows a similar structure to the shape of the data it expects to receive. It consists of a set of fields that correspond to the properties of the data the client wants to retrieve. Each field can also have arguments that modify the data returned.</p>
<p>Here's an example of a simple query in GraphQL:</p>
<pre><code class="lang-yaml"><span class="hljs-string">query</span> {
  <span class="hljs-string">user(id:</span> <span class="hljs-string">"1"</span><span class="hljs-string">)</span> {
    <span class="hljs-string">name</span>
    <span class="hljs-string">email</span>
    <span class="hljs-string">age</span>
  }
}
</code></pre>
<p>In this example, the query is requesting information about a user with the ID of "1". The fields specified in the query are "name", "email", and "age", which correspond to the properties of the user object.</p>
<p>The response from the server would be in the same shape as the query, with the requested data returned in the corresponding fields:</p>
<pre><code class="lang-yaml">{
  <span class="hljs-attr">"data":</span> {
    <span class="hljs-attr">"user":</span> {
      <span class="hljs-attr">"name":</span> <span class="hljs-string">"John Doe"</span>,
      <span class="hljs-attr">"email":</span> <span class="hljs-string">"johndoe@example.com"</span>,
      <span class="hljs-attr">"age":</span> <span class="hljs-number">25</span>
    }
  }
}
</code></pre>
<p>Here, the server has returned the requested data about the user in the "name", "email", and "age" fields. The data is contained in a "data" object to differentiate it from any errors or other metadata that may be included in the response.</p>
<h2 id="heading-mutations">Mutations</h2>
<p>In GraphQL, mutations are used to modify or create data on the server. Like queries, mutations specify the shape of the data being sent to and received from the server. The main difference is that while <strong>queries only read data, mutations can both read and write data</strong>.</p>
<p>Here's an example of a simple mutation in GraphQL:</p>
<pre><code class="lang-yaml"><span class="hljs-string">mutation</span> {
  <span class="hljs-string">createUser(name:</span> <span class="hljs-string">"Jane Doe"</span>, <span class="hljs-attr">email:</span> <span class="hljs-string">"janedoe@example.com"</span>, <span class="hljs-attr">age:</span> <span class="hljs-number">30</span><span class="hljs-string">)</span> {
    <span class="hljs-string">id</span>
    <span class="hljs-string">name</span>
    <span class="hljs-string">email</span>
    <span class="hljs-string">age</span>
  }
}
</code></pre>
<p>In this example, the mutation is creating a new user on the server with the name "Jane Doe", email "janedoe@example.com", and age 30. The fields specified in the mutation are "id", "name", "email", and "age", which correspond to the properties of the user object.</p>
<p>The response from the server would be in the same shape as the mutation, with the newly created user data returned in the corresponding fields:</p>
<pre><code class="lang-yaml">{
  <span class="hljs-attr">"data":</span> {
    <span class="hljs-attr">"createUser":</span> {
      <span class="hljs-attr">"id":</span> <span class="hljs-string">"123"</span>,
      <span class="hljs-attr">"name":</span> <span class="hljs-string">"Jane Doe"</span>,
      <span class="hljs-attr">"email":</span> <span class="hljs-string">"janedoe@example.com"</span>,
      <span class="hljs-attr">"age":</span> <span class="hljs-number">30</span>
    }
  }
}
</code></pre>
<p>Here, the server has returned the data about the newly created user in the "id", "name", "email", and "age" fields.</p>
<p>Mutations can also be used to update or delete data on the server. Here's an example of a mutation that updates a user's name:</p>
<pre><code class="lang-yaml"><span class="hljs-string">mutation</span> {
  <span class="hljs-string">updateUser(id:</span> <span class="hljs-string">"123"</span>, <span class="hljs-attr">name:</span> <span class="hljs-string">"Jane Smith"</span><span class="hljs-string">)</span> {
    <span class="hljs-string">id</span>
    <span class="hljs-string">name</span>
    <span class="hljs-string">email</span>
    <span class="hljs-string">age</span>
  }
}
</code></pre>
<p>In this example, the mutation is updating the user with the ID of "123" to have the name "Jane Smith". The fields specified in the mutation are the same as in the previous example.</p>
<p>The response from the server would be the updated user data:</p>
<pre><code class="lang-yaml">{
  <span class="hljs-attr">"data":</span> {
    <span class="hljs-attr">"updateUser":</span> {
      <span class="hljs-attr">"id":</span> <span class="hljs-string">"123"</span>,
      <span class="hljs-attr">"name":</span> <span class="hljs-string">"Jane Smith"</span>,
      <span class="hljs-attr">"email":</span> <span class="hljs-string">"janedoe@example.com"</span>,
      <span class="hljs-attr">"age":</span> <span class="hljs-number">30</span>
    }
  }
}
</code></pre>
<p>Mutations in GraphQL are designed to be composable, meaning that multiple mutations can be combined into a single request. This allows clients to perform complex operations with a single network round-trip.</p>
<h2 id="heading-resolvers">Resolvers</h2>
<p>In GraphQL, a resolver is a function responsible for fetching the data for a specific field defined in a GraphQL schema. Resolvers are the bridge between the schema and the data source. The resolver function receives four parameters: parent, args, context, and info.</p>
<ul>
<li><p><code>parent</code>: The parent object for the current field. In nested queries, it refers to the parent field's value.</p>
</li>
<li><p><code>args</code>: The arguments passed to the current field. It is an object with key-value pairs of the argument names and their values.</p>
</li>
<li><p><code>context</code>: An object shared across all resolvers for a particular request. It contains information about the request such as the currently authenticated user, database connection, etc.</p>
</li>
<li><p><code>info</code>: Contains information about the query including the field name, alias, and the query document AST.</p>
</li>
</ul>
<p>Here's an example of a resolver function for a <code>User</code> type's <code>posts</code> field:</p>
<pre><code class="lang-yaml"><span class="hljs-string">const</span> <span class="hljs-string">resolvers</span> <span class="hljs-string">=</span> {
  <span class="hljs-attr">User:</span> {
    <span class="hljs-attr">posts:</span> <span class="hljs-string">(parent</span>, <span class="hljs-string">args</span>, <span class="hljs-string">context</span>, <span class="hljs-string">info)</span> <span class="hljs-string">=&gt;</span> {
      <span class="hljs-string">return</span> <span class="hljs-string">getPostsByUserId(parent.id);</span>
    },
  },
}<span class="hljs-string">;</span>
</code></pre>
<p>In this example, <code>User</code> is a GraphQL object type with a <code>posts</code> field. When the <code>posts</code> field is queried, the resolver function is called with the parent object <code>User</code>, any arguments passed, the context object, and query information. In this example, the resolver function calls a function <code>getPostsByUserId</code> to fetch the posts for the current user.</p>
<p>Resolvers can also be used for mutations to create, update or delete data. Here's an example of a resolver function for a <code>createUser</code> mutation:</p>
<pre><code class="lang-yaml"><span class="hljs-string">const</span> <span class="hljs-string">resolvers</span> <span class="hljs-string">=</span> {
  <span class="hljs-attr">Mutation:</span> {
    <span class="hljs-attr">createUser:</span> <span class="hljs-string">(parent</span>, <span class="hljs-string">args</span>, <span class="hljs-string">context</span>, <span class="hljs-string">info)</span> <span class="hljs-string">=&gt;</span> {
      <span class="hljs-string">const</span> <span class="hljs-string">user</span> <span class="hljs-string">=</span> { <span class="hljs-attr">name:</span> <span class="hljs-string">args.name</span>, <span class="hljs-attr">email:</span> <span class="hljs-string">args.email</span> }<span class="hljs-string">;</span>
      <span class="hljs-string">const</span> <span class="hljs-string">createdUser</span> <span class="hljs-string">=</span> <span class="hljs-string">createUser(user);</span>
      <span class="hljs-string">return</span> <span class="hljs-string">createdUser;</span>
    },
  },
}<span class="hljs-string">;</span>
</code></pre>
<p>In this example, <code>Mutation</code> is a GraphQL object type with a <code>createUser</code> mutation field. When the mutation is invoked, the resolver function is called with the parent object, arguments passed, context object, and query information. In this example, the resolver function calls a function <code>createUser</code> to create a new user with the given name and email, and returns the newly created user.</p>
<h2 id="heading-schemas">Schemas</h2>
<p>In GraphQL, a schema is a blueprint that defines the structure of the data that can be queried in the API. It defines the available types, fields, and operations that can be performed on those types.</p>
<p>GraphQL schemas are written in the GraphQL Schema Definition Language (SDL), which uses a simple syntax to define the types and fields available in the API. The schema is typically defined in the server-side code and then used to validate and execute incoming queries.</p>
<p>Here's an example of a simple GraphQL schema definition:</p>
<pre><code class="lang-yaml"><span class="hljs-string">type</span> <span class="hljs-string">Book</span> {
  <span class="hljs-attr">id:</span> <span class="hljs-string">ID!</span>
  <span class="hljs-attr">title:</span> <span class="hljs-string">String!</span>
  <span class="hljs-attr">author:</span> <span class="hljs-string">String!</span>
  <span class="hljs-attr">published:</span> <span class="hljs-string">Int!</span>
}

<span class="hljs-string">type</span> <span class="hljs-string">Query</span> {
  <span class="hljs-attr">books:</span> [<span class="hljs-string">Book!</span>]<span class="hljs-string">!</span>
  <span class="hljs-string">book(id:</span> <span class="hljs-string">ID!):</span> <span class="hljs-string">Book</span>
}

<span class="hljs-string">type</span> <span class="hljs-string">Mutation</span> {
  <span class="hljs-string">addBook(title:</span> <span class="hljs-string">String!</span>, <span class="hljs-attr">author:</span> <span class="hljs-string">String!</span>, <span class="hljs-attr">published:</span> <span class="hljs-string">Int!):</span> <span class="hljs-string">Book!</span>
  <span class="hljs-string">updateBook(id:</span> <span class="hljs-string">ID!</span>, <span class="hljs-attr">title:</span> <span class="hljs-string">String</span>, <span class="hljs-attr">author:</span> <span class="hljs-string">String</span>, <span class="hljs-attr">published:</span> <span class="hljs-string">Int):</span> <span class="hljs-string">Book</span>
  <span class="hljs-string">deleteBook(id:</span> <span class="hljs-string">ID!):</span> <span class="hljs-string">Book</span>
}
</code></pre>
<p>In this schema, we have three types: <code>Book</code>, <code>Query</code>, and <code>Mutation</code>. The <code>Book</code> type has four fields: <code>id</code>, <code>title</code>, <code>author</code>, and <code>published</code>. The <code>Query</code> type has two fields: <code>books</code> and <code>book</code>, which can be used to retrieve a list of books or a specific book by ID, respectively. The <code>Mutation</code> type has three fields: <code>addBook</code>, <code>updateBook</code>, and <code>deleteBook</code>, which can be used to create, update, or delete books.</p>
<p>Note that each field has a type, which can be a built-in scalar type like <code>String</code> or <code>Int</code>, or a custom type like <code>Book</code>. The <code>!</code> after a type indicates that the field is non-nullable, meaning it must always return a value (that is, it cannot be null).</p>
<h2 id="heading-tldr-and-comparison-with-equivalent-rest-concepts">TLDR and Comparison with Equivalent REST Concepts</h2>
<ul>
<li><p><strong>Object Types:</strong> In GraphQL, Object Types are used to define the data that can be queried from an API, similar to how the response data model is defined in REST APIs. However, unlike REST, where data models are often defined in different formats (for example, JSON or XML), GraphQL Object Types are defined using a single language-agnostic syntax.</p>
</li>
<li><p><strong>Queries:</strong> In GraphQL, queries are used to fetch data from an API, similar to HTTP GET requests in REST APIs. However, unlike REST APIs, where multiple requests may be required to fetch nested data, GraphQL queries can be used to fetch nested data in a single request.</p>
</li>
<li><p><strong>Mutations:</strong> In GraphQL, mutations are used to modify data in an API, similar to HTTP POST, PUT, and DELETE requests in REST APIs. However, unlike REST APIs, where different endpoints may be required to perform different modifications, GraphQL mutations are performed through a single endpoint.</p>
</li>
<li><p><strong>Resolvers:</strong> In GraphQL, resolvers are used to specify how to fetch data for a particular field in a query or mutation. Resolvers are similar to controller methods in REST APIs, which are used to fetch data from a database and return it as a response.</p>
</li>
<li><p><strong>Schemas:</strong> In GraphQL, a schema is used to define the data that can be queried or mutated from an API. It specifies the types of data that can be requested, how they can be queried, and what mutations are allowed. In REST APIs, schemas are often defined using OpenAPI or Swagger, which specify the endpoints, request and response types, and other metadata for an API.</p>
</li>
</ul>
<p>Overall, GraphQL and REST APIs differ in how they handle data fetching and modification.</p>
<p>REST APIs rely on multiple endpoints and HTTP methods to fetch and modify data, whereas GraphQL uses a single endpoint and queries/mutations to accomplish the same.</p>
<p>GraphQL's use of a single schema to define the data model of an API makes it easier to understand and maintain compared to REST APIs, which often require multiple documentation formats to describe the same data model.</p>
<h1 id="heading-how-to-build-a-graphql-api-with-node-and-apollo-graphql">How to Build a GraphQL API with Node and Apollo GraphQL</h1>
<h2 id="heading-our-tools">Our Tools</h2>
<p><a target="_blank" href="https://nodejs.org/"><strong>Node.js</strong></a> is an open-source, cross-platform, back-end JavaScript runtime environment that allows developers to execute JavaScript code outside of a web browser. It was created by Ryan Dahl in 2009 and has since become a popular choice for building web applications, APIs, and servers.</p>
<p>Node.js provides an event-driven, non-blocking I/O model that makes it lightweight and efficient, allowing it to handle large amounts of data with high performance. It also has a large and active community, with many libraries and modules available to help developers build their applications more quickly and easily.</p>
<p><a target="_blank" href="https://www.apollographql.com/"><strong>Apollo GraphQL</strong></a> is a full-stack platform for building GraphQL APIs. It provides tools and libraries that simplify the process of building, managing, and consuming GraphQL APIs.</p>
<p>The core of the Apollo GraphQL platform is the Apollo Server, a lightweight and flexible server that makes it easy to build scalable and performant GraphQL APIs. The Apollo Server supports a wide range of data sources, including databases, REST APIs, and other services, making it easy to integrate with existing systems.</p>
<p>Apollo also provides a number of client libraries, including the Apollo Client for web and mobile, which simplifies the process of consuming GraphQL APIs. The Apollo Client makes it easy to query and mutate data, and provides advanced features like caching, optimistic UI, and real-time updates.</p>
<p>In addition to the Apollo Server and Apollo Client, Apollo provides a number of other tools and services, including a schema management platform, a GraphQL analytics service, and a set of developer tools for building and debugging GraphQL APIs.</p>
<p>If you're new to GraphQL or to Apollo itself, I really recommend you <a target="_blank" href="https://www.apollographql.com/docs/">check out their docs</a>. They're some of the best out there in my opinion.</p>
<h2 id="heading-our-architecture">Our Architecture</h2>
<p>For this project we'll follow a layers architecture in our codebase. Layers architecture is about dividing concerns and responsibilities into different folders and files, and allowing direct communication only between certain folders and files.</p>
<p>The matter of how many layers should your project have, what names should each layer have, and what actions should it handle is all a matter of discussion. So let's see what I think is a good approach for our example.</p>
<p>Our application will have five different layers, which will be ordered in this way:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/Untitled-Diagram.drawio.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Application layers</em></p>
<ul>
<li><p>The application layer will have the basic setup of our server and the connection to our schema and resolvers (the next layer).</p>
</li>
<li><p>The schema and resolvers layer will have the type definitions for our data and the connection to our queries and mutations (the next layer).</p>
</li>
<li><p>The queries and mutations layer will have the actual logic we want to perform in each of our queries and mutations and the connection to the model layer (the next layer, you get the idea...)</p>
</li>
<li><p>The model layer will hold the logic for interacting with our mock database.</p>
</li>
<li><p>Finally, the persistence layer is where our database will be.</p>
</li>
</ul>
<p>An important thing to keep in mind is that in these kinds of architectures, <strong>there's a defined communication flow</strong> between the layers that has to be followed for it to make sense.</p>
<p>This means that a request first has to go through the first layer, then the second, then the third and so on. No request should skip layers because that would mess with the logic of the architecture and the benefits of organization and modularity it gives us.</p>
<p>If you'd like to know some other API architecture options, I recommend <a target="_blank" href="https://www.freecodecamp.org/news/an-introduction-to-software-architecture-patterns/">this software architecture article</a> I wrote a while ago.</p>
<h2 id="heading-the-code">The Code</h2>
<p>Before jumping to the code, let's mention what we'll actually build. We'll be building an API for a pet shelter business. This pet shelter needs to register the pets that are staying in the shelter, and for that we'll perform basic CRUD operations (create, read, update and delete).</p>
<p>We're using the exact same example we used in <a target="_blank" href="https://www.freecodecamp.org/news/build-consume-and-document-a-rest-api/">my article about fully implementing a REST API.</a> If you're interested in reading that too, this should help to compare concepts between REST and GraphQL, and understand its differences and similarities. ;)</p>
<p>Now let's get this thing going. Create a new directory, hop in to it and start a new Node project by running <code>npm init -y</code>. For our GraphQL server we'll need two more dependencies, so run <code>npm i @apollo/server</code> and <code>npm i graphql</code> too.</p>
<h3 id="heading-appjs">App.js</h3>
<p>In the root of your project, create an <code>app.js</code> file and drop this code in it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { ApolloServer } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/server'</span>
<span class="hljs-keyword">import</span> { startStandaloneServer } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/server/standalone'</span>
<span class="hljs-keyword">import</span> { typeDefs, resolvers } <span class="hljs-keyword">from</span> <span class="hljs-string">'./pets/index.js'</span>

<span class="hljs-comment">// The ApolloServer constructor requires two parameters: your schema</span>
<span class="hljs-comment">// definition and your set of resolvers.</span>
<span class="hljs-keyword">const</span> server = <span class="hljs-keyword">new</span> ApolloServer({
    typeDefs,
    resolvers
})

<span class="hljs-comment">// Passing an ApolloServer instance to the `startStandaloneServer` function:</span>
<span class="hljs-comment">//  1. creates an Express app</span>
<span class="hljs-comment">//  2. installs your ApolloServer instance as middleware</span>
<span class="hljs-comment">//  3. prepares your app to handle incoming requests</span>
<span class="hljs-keyword">const</span> { url } = <span class="hljs-keyword">await</span> startStandaloneServer(server, {
    <span class="hljs-attr">listen</span>: { <span class="hljs-attr">port</span>: <span class="hljs-number">4000</span> }
})

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`🚀  Server ready at: <span class="hljs-subst">${url}</span>`</span>)
</code></pre>
<p>Here we're setting up our Apollo server, by passing it our typeDefs and resolvers (we'll explain those in a sec), and then starting the server in port 4000.</p>
<p>Next, go ahead and create this folder structure in your project:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Our folder structure</em></p>
<h3 id="heading-indexjs">index.js</h3>
<p>Within the <code>index.js</code> file put this code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { addPet, editPet, deletePet } <span class="hljs-keyword">from</span> <span class="hljs-string">'./mutations/pets.mutations.js'</span>
<span class="hljs-keyword">import</span> { listPets, getPet } <span class="hljs-keyword">from</span> <span class="hljs-string">'./queries/pets.queries.js'</span>

<span class="hljs-comment">// A schema is a collection of type definitions (hence "typeDefs")</span>
<span class="hljs-comment">// that together define the "shape" of queries that are executed against your data.</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> typeDefs = <span class="hljs-string">`#graphql
  # OBJECT TYPES
  # This "Pet" type defines the queryable fields for every pet in our data source.
  type Pet {
    id: ID!
    name: String!
    type: String!
    age: Int!
    breed: String!
  }

  # INPUT TYPES
  # Define the input objects for addPet and editPet mutations
  input PetToEdit {
    id: ID!
    name: String!
    type: String!
    age: Int!
    breed: String!
  }

  input PetToAdd {
    name: String!
    type: String!
    age: Int!
    breed: String!
  }

  # The "Query" type is special: it lists all of the available queries that
  # clients can execute, along with the return type for each. In this
  # case, the "pets" query returns an array of zero or more pets.
  # QUERY TYPES
  type Query {
    pets: [Pet],
    pet(id: ID!): Pet
  }

  # MUTATION TYPES
  type Mutation {
    addPet(petToAdd: PetToAdd!): Pet,
    editPet(petToEdit: PetToEdit!): Pet,
    deletePet(id: ID!): [Pet],
  }
`</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> resolvers = {
    <span class="hljs-comment">// Resolvers for Queries</span>
    <span class="hljs-attr">Query</span>: {
        <span class="hljs-attr">pets</span>: <span class="hljs-function">() =&gt;</span> listPets(),
        <span class="hljs-attr">pet</span>: <span class="hljs-function">(<span class="hljs-params">_, { id }</span>) =&gt;</span> getPet(id)
    },

    <span class="hljs-comment">// Resolvers for Mutations</span>
    <span class="hljs-attr">Mutation</span>: {
        <span class="hljs-attr">addPet</span>: <span class="hljs-function">(<span class="hljs-params">_, { petToAdd }</span>) =&gt;</span> addPet(petToAdd),
        <span class="hljs-attr">editPet</span>: <span class="hljs-function">(<span class="hljs-params">_, { petToEdit }</span>) =&gt;</span> editPet(petToEdit),
        <span class="hljs-attr">deletePet</span>: <span class="hljs-function">(<span class="hljs-params">_, { id }</span>) =&gt;</span> deletePet(id)
    }
}
</code></pre>
<p>Here we have two main things: typeDefs and resolvers.</p>
<p><strong>typeDefs</strong> defines the types for the data that can be queried in our API (in our case that's the <code>pet</code> object), as well as the input for queries/mutations (in our case that's <code>PetToEdit</code> and <code>PetToAdd</code>).</p>
<p>Lastly, it also defines the available queries and mutations for our API, declaring their names, as well as their input and return values. In our case we have two queries (<code>pets</code> and <code>pet</code>) and three mutations (<code>addPet</code>, <code>editPet</code> and <code>deletePet</code>).</p>
<p><strong>resolvers</strong> contain the actual implementation of our queries and mutations types. Here we're declaring each query and mutation, and indicating what each should do. In our case, we're linking them with the queries/mutations we're importing from our queries/mutations layer.</p>
<h3 id="heading-petsqueriesjs">pets.queries.js</h3>
<p>In your <code>pets.queries.js</code> file drop this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { getItem, listItems } <span class="hljs-keyword">from</span> <span class="hljs-string">'../models/pets.models.js'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getPet = <span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> resp = getItem(id)
        <span class="hljs-keyword">return</span> resp
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> err
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> listPets = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> resp = listItems()
        <span class="hljs-keyword">return</span> resp
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> err
    }
}
</code></pre>
<p>As you can see, this file is very simple. It declares the functions that are imported in the <code>index.js</code> file and links them to the functions declared in the models layer.</p>
<h3 id="heading-petsmutationsjs">pets.mutations.js</h3>
<p>Same goes for our <code>pets.mutations.js</code> file, but with mutations now.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { editItem, addItem, deleteItem } <span class="hljs-keyword">from</span> <span class="hljs-string">'../models/pets.models.js'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addPet = <span class="hljs-function"><span class="hljs-params">petToAdd</span> =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> resp = addItem(petToAdd)
        <span class="hljs-keyword">return</span> resp
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> err
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> editPet = <span class="hljs-function"><span class="hljs-params">petToEdit</span> =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> resp = editItem(petToEdit?.id, petToEdit)
        <span class="hljs-keyword">return</span> resp
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> err
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deletePet = <span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> resp = deleteItem(id)
        <span class="hljs-keyword">return</span> resp
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> err
    }
}
</code></pre>
<h3 id="heading-petsmodelsjs">pets.models.js</h3>
<p>Now go to the models folder and create a <code>pets.models.js</code> file with this code in it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> db <span class="hljs-keyword">from</span> <span class="hljs-string">'../../db/db.js'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getItem = <span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> pet = db?.pets?.filter(<span class="hljs-function"><span class="hljs-params">pet</span> =&gt;</span> pet?.id === <span class="hljs-built_in">parseInt</span>(id))[<span class="hljs-number">0</span>]
        <span class="hljs-keyword">return</span> pet
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error'</span>, err)
        <span class="hljs-keyword">return</span> err
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> listItems = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">return</span> db?.pets
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error'</span>, err)
        <span class="hljs-keyword">return</span> err
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> editItem = <span class="hljs-function">(<span class="hljs-params">id, data</span>) =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> index = db.pets.findIndex(<span class="hljs-function"><span class="hljs-params">pet</span> =&gt;</span> pet.id === <span class="hljs-built_in">parseInt</span>(id))

        <span class="hljs-keyword">if</span> (index === <span class="hljs-number">-1</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Pet not found'</span>)
        <span class="hljs-keyword">else</span> {
            data.id = <span class="hljs-built_in">parseInt</span>(data.id)
            db.pets[index] = data
            <span class="hljs-keyword">return</span> db.pets[index]
        }
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error'</span>, err)
        <span class="hljs-keyword">return</span> err
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addItem = <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> newPet = { <span class="hljs-attr">id</span>: db.pets.length + <span class="hljs-number">1</span>, ...data }
        db.pets.push(newPet)
        <span class="hljs-keyword">return</span> newPet
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error'</span>, err)
        <span class="hljs-keyword">return</span> err
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deleteItem = <span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// delete item from db</span>
        <span class="hljs-keyword">const</span> index = db.pets.findIndex(<span class="hljs-function"><span class="hljs-params">pet</span> =&gt;</span> pet.id === <span class="hljs-built_in">parseInt</span>(id))

        <span class="hljs-keyword">if</span> (index === <span class="hljs-number">-1</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Pet not found'</span>)
        <span class="hljs-keyword">else</span> {
            db.pets.splice(index, <span class="hljs-number">1</span>)
            <span class="hljs-keyword">return</span> db.pets
        }
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error'</span>, err)
        <span class="hljs-keyword">return</span> err
    }
}
</code></pre>
<p>These are the functions responsible for interacting with our data layer (database) and returning the corresponding information to our controllers.</p>
<h3 id="heading-database"><strong>Database</strong></h3>
<p>We wont use a real database for this example. Instead we'll just use a simple array that will work just fine for example purposes, though our data will of course reset every time our server does.</p>
<p>In the root of our project, create a <code>db</code> folder and a <code>db.js</code> file with this code in it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> db = {
    <span class="hljs-attr">pets</span>: [
        {
            <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Rex'</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'dog'</span>,
            <span class="hljs-attr">age</span>: <span class="hljs-number">3</span>,
            <span class="hljs-attr">breed</span>: <span class="hljs-string">'labrador'</span>,
        },
        {
            <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Fido'</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'dog'</span>,
            <span class="hljs-attr">age</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">breed</span>: <span class="hljs-string">'poodle'</span>,
        },
        {
            <span class="hljs-attr">id</span>: <span class="hljs-number">3</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Mittens'</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
            <span class="hljs-attr">age</span>: <span class="hljs-number">2</span>,
            <span class="hljs-attr">breed</span>: <span class="hljs-string">'tabby'</span>,
        },
    ]
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> db
</code></pre>
<p>As you can see, our <code>db</code> object contains a <code>pets</code> property whose value is an array of objects, each object being a pet. For each pet, we store an id, name, type, age and breed.</p>
<p>Now go to your terminal and run <code>nodemon app.js</code>. You should see this message confirming your server is alive: <code>🚀 Server ready at: [http://localhost:4000/](http://localhost:4000/)</code>.</p>
<h1 id="heading-how-to-test-a-graphql-api-with-supertest">How to Test a GraphQL API with Supertest</h1>
<p>Now that our server is up and running, let's implement a simple test suit to check if our queries and mutations behave as expected.</p>
<p>If you're not familiar with automated testing, I recommend you read <a target="_blank" href="https://www.freecodecamp.org/news/test-a-react-app-with-jest-testing-library-and-cypress/">this introductory article I wrote a while ago</a>.</p>
<h2 id="heading-our-tools-1"><strong>Our Tools</strong></h2>
<p><a target="_blank" href="https://www.npmjs.com/package/supertest"><strong>SuperTest</strong></a> is a JavaScript library that is used for testing HTTP servers or web applications that make HTTP requests. It provides a high-level abstraction for testing HTTP, allowing developers to send HTTP requests and make assertions about the responses received, making it easier to write automated tests for web applications.</p>
<p>SuperTest works with any JavaScript testing framework, such as <a target="_blank" href="https://mochajs.org/">Mocha</a> or <a target="_blank" href="https://jestjs.io/">Jest</a>, and can be used with any HTTP server or web application framework, such as Express.</p>
<p>SuperTest is built on top of the popular testing library Mocha, and uses the <a target="_blank" href="https://www.chaijs.com/">Chai</a> assertion library to make assertions about the responses received. It provides an easy-to-use API for making HTTP requests, including support for authentication, headers, and request bodies.</p>
<p>SuperTest also allows developers to test the entire request/response cycle, including middleware and error handling, making it a powerful tool for testing web applications.</p>
<p>Overall, SuperTest is a valuable tool for developers who want to write automated tests for their web applications. It helps ensure that their applications are functioning correctly and that any changes they make to the codebase do not introduce new bugs or issues.</p>
<h2 id="heading-the-code-1"><strong>The Code</strong></h2>
<p>First we'll need to install some dependencies. To save up terminal commands, go to your <code>package.json</code> file and replace your <code>devDependencies</code> section with the code below. Then run <code>npm install</code>.</p>
<pre><code class="lang-javascript">  <span class="hljs-string">"devDependencies"</span>: {
    <span class="hljs-string">"@babel/core"</span>: <span class="hljs-string">"^7.21.4"</span>,
    <span class="hljs-string">"@babel/preset-env"</span>: <span class="hljs-string">"^7.21.4"</span>,
    <span class="hljs-string">"babel-jest"</span>: <span class="hljs-string">"^29.5.0"</span>,
    <span class="hljs-string">"jest"</span>: <span class="hljs-string">"^29.5.0"</span>,
    <span class="hljs-string">"jest-babel"</span>: <span class="hljs-string">"^1.0.1"</span>,
    <span class="hljs-string">"nodemon"</span>: <span class="hljs-string">"^2.0.22"</span>,
    <span class="hljs-string">"supertest"</span>: <span class="hljs-string">"^6.3.3"</span>
  }
</code></pre>
<p>Here we're installing the <code>supertest</code> and <code>jest</code> libraries, which we need for our tests to run, plus some <code>babel</code> stuff we need for our project to correctly identify which files are test files.</p>
<p>Still in your <code>package.json</code>, add this script:</p>
<pre><code class="lang-javascript">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"jest"</span>
  },
</code></pre>
<p>To end with the boilerplate, in the root of your project, create a <code>babel.config.cjs</code> file and drop this code in it:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//babel.config.cjs</span>
<span class="hljs-built_in">module</span>.exports = {
    <span class="hljs-attr">presets</span>: [
      [
        <span class="hljs-string">'@babel/preset-env'</span>,
        {
          <span class="hljs-attr">targets</span>: {
            <span class="hljs-attr">node</span>: <span class="hljs-string">'current'</span>,
          },
        },
      ],
    ],
  };
</code></pre>
<p>Now let's write some actual tests! Within your pets folder, create a <code>pets.test.js</code> file with this code in it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> request <span class="hljs-keyword">from</span> <span class="hljs-string">'supertest'</span>

<span class="hljs-keyword">const</span> graphQLEndpoint = <span class="hljs-string">'http://localhost:4000/'</span>

describe(<span class="hljs-string">'Get all pets'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> postData = {
        <span class="hljs-attr">query</span>: <span class="hljs-string">`query Pets {
            pets {
                id
                name
                type
                age
                breed
            }
        }`</span>
    }

    test(<span class="hljs-string">'returns all pets'</span>, <span class="hljs-keyword">async</span> () =&gt; {
        request(graphQLEndpoint)
            .post(<span class="hljs-string">'?'</span>)
            .send(postData)
            .expect(<span class="hljs-number">200</span>)
            .end(<span class="hljs-function">(<span class="hljs-params">error, response</span>) =&gt;</span> {
                <span class="hljs-keyword">if</span> (error) <span class="hljs-built_in">console</span>.error(error)

                <span class="hljs-keyword">const</span> res = <span class="hljs-built_in">JSON</span>.parse(response.text)

                expect(res.data.pets).toEqual([
                    {
                        <span class="hljs-attr">id</span>: <span class="hljs-string">'1'</span>,
                        <span class="hljs-attr">name</span>: <span class="hljs-string">'Rex'</span>,
                        <span class="hljs-attr">type</span>: <span class="hljs-string">'dog'</span>,
                        <span class="hljs-attr">age</span>: <span class="hljs-number">3</span>,
                        <span class="hljs-attr">breed</span>: <span class="hljs-string">'labrador'</span>
                    },
                    {
                        <span class="hljs-attr">id</span>: <span class="hljs-string">'2'</span>,
                        <span class="hljs-attr">name</span>: <span class="hljs-string">'Fido'</span>,
                        <span class="hljs-attr">type</span>: <span class="hljs-string">'dog'</span>,
                        <span class="hljs-attr">age</span>: <span class="hljs-number">1</span>,
                        <span class="hljs-attr">breed</span>: <span class="hljs-string">'poodle'</span>
                    },
                    {
                        <span class="hljs-attr">id</span>: <span class="hljs-string">'3'</span>,
                        <span class="hljs-attr">name</span>: <span class="hljs-string">'Mittens'</span>,
                        <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
                        <span class="hljs-attr">age</span>: <span class="hljs-number">2</span>,
                        <span class="hljs-attr">breed</span>: <span class="hljs-string">'tabby'</span>
                    }
                ])
            })
    })
})

describe(<span class="hljs-string">'Get pet detail'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> postData = {
        <span class="hljs-attr">query</span>: <span class="hljs-string">`query Pet {
            pet(id: 1) {
                id
                name
                type
                age
                breed
            }
        }`</span>
    }

    test(<span class="hljs-string">'Return pet detail information'</span>, <span class="hljs-keyword">async</span> () =&gt; {
        request(graphQLEndpoint)
            .post(<span class="hljs-string">'?'</span>)
            .send(postData)
            .expect(<span class="hljs-number">200</span>)
            .end(<span class="hljs-function">(<span class="hljs-params">error, response</span>) =&gt;</span> {
                <span class="hljs-keyword">if</span> (error) <span class="hljs-built_in">console</span>.error(error)

                <span class="hljs-keyword">const</span> res = <span class="hljs-built_in">JSON</span>.parse(response.text)

                expect(res.data.pet).toEqual({
                    <span class="hljs-attr">id</span>: <span class="hljs-string">'1'</span>,
                    <span class="hljs-attr">name</span>: <span class="hljs-string">'Rex'</span>,
                    <span class="hljs-attr">type</span>: <span class="hljs-string">'dog'</span>,
                    <span class="hljs-attr">age</span>: <span class="hljs-number">3</span>,
                    <span class="hljs-attr">breed</span>: <span class="hljs-string">'labrador'</span>
                })
            })
    })
})

describe(<span class="hljs-string">'Edit pet'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> postData = {
        <span class="hljs-attr">query</span>: <span class="hljs-string">`mutation EditPet($petToEdit: PetToEdit!) {
            editPet(petToEdit: $petToEdit) {
                id
                name
                type
                age
                breed
            }
        }`</span>,
        <span class="hljs-attr">variables</span>: {
            <span class="hljs-attr">petToEdit</span>: {
                <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
                <span class="hljs-attr">name</span>: <span class="hljs-string">'Rexo'</span>,
                <span class="hljs-attr">type</span>: <span class="hljs-string">'dogo'</span>,
                <span class="hljs-attr">age</span>: <span class="hljs-number">4</span>,
                <span class="hljs-attr">breed</span>: <span class="hljs-string">'doberman'</span>
            }
        }
    }

    test(<span class="hljs-string">'Updates pet and returns it'</span>, <span class="hljs-keyword">async</span> () =&gt; {
        request(graphQLEndpoint)
            .post(<span class="hljs-string">'?'</span>)
            .send(postData)
            .expect(<span class="hljs-number">200</span>)
            .end(<span class="hljs-function">(<span class="hljs-params">error, response</span>) =&gt;</span> {
                <span class="hljs-keyword">if</span> (error) <span class="hljs-built_in">console</span>.error(error)

                <span class="hljs-keyword">const</span> res = <span class="hljs-built_in">JSON</span>.parse(response.text)

                expect(res.data.editPet).toEqual({
                    <span class="hljs-attr">id</span>: <span class="hljs-string">'1'</span>,
                    <span class="hljs-attr">name</span>: <span class="hljs-string">'Rexo'</span>,
                    <span class="hljs-attr">type</span>: <span class="hljs-string">'dogo'</span>,
                    <span class="hljs-attr">age</span>: <span class="hljs-number">4</span>,
                    <span class="hljs-attr">breed</span>: <span class="hljs-string">'doberman'</span>
                })
            })
    })
})

describe(<span class="hljs-string">'Add pet'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> postData = {
        <span class="hljs-attr">query</span>: <span class="hljs-string">`mutation AddPet($petToAdd: PetToAdd!) {
            addPet(petToAdd: $petToAdd) {
                id
                name
                type
                age
                breed
            }
        }`</span>,
        <span class="hljs-attr">variables</span>: {
            <span class="hljs-attr">petToAdd</span>: {
                <span class="hljs-attr">name</span>: <span class="hljs-string">'Salame'</span>,
                <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
                <span class="hljs-attr">age</span>: <span class="hljs-number">6</span>,
                <span class="hljs-attr">breed</span>: <span class="hljs-string">'pinky'</span>
            }
        }
    }

    test(<span class="hljs-string">'Adds new pet and returns the added item'</span>, <span class="hljs-keyword">async</span> () =&gt; {
        request(graphQLEndpoint)
            .post(<span class="hljs-string">'?'</span>)
            .send(postData)
            .expect(<span class="hljs-number">200</span>)
            .end(<span class="hljs-function">(<span class="hljs-params">error, response</span>) =&gt;</span> {
                <span class="hljs-keyword">if</span> (error) <span class="hljs-built_in">console</span>.error(error)

                <span class="hljs-keyword">const</span> res = <span class="hljs-built_in">JSON</span>.parse(response.text)

                expect(res.data.addPet).toEqual({
                    <span class="hljs-attr">id</span>: <span class="hljs-string">'4'</span>,
                    <span class="hljs-attr">name</span>: <span class="hljs-string">'Salame'</span>,
                    <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
                    <span class="hljs-attr">age</span>: <span class="hljs-number">6</span>,
                    <span class="hljs-attr">breed</span>: <span class="hljs-string">'pinky'</span>
                })
            })
    })
})

describe(<span class="hljs-string">'Delete pet'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> postData = {
        <span class="hljs-attr">query</span>: <span class="hljs-string">`mutation DeletePet {
            deletePet(id: 2) {
                id,
                name,
                type,
                age,
                breed
            }
        }`</span>
    }

    test(<span class="hljs-string">'Deletes given pet and returns updated list'</span>, <span class="hljs-keyword">async</span> () =&gt; {
        request(graphQLEndpoint)
            .post(<span class="hljs-string">'?'</span>)
            .send(postData)
            .expect(<span class="hljs-number">200</span>)
            .end(<span class="hljs-function">(<span class="hljs-params">error, response</span>) =&gt;</span> {
                <span class="hljs-keyword">if</span> (error) <span class="hljs-built_in">console</span>.error(error)

                <span class="hljs-keyword">const</span> res = <span class="hljs-built_in">JSON</span>.parse(response.text)

                expect(res.data.deletePet).toEqual([
                    {
                        <span class="hljs-attr">id</span>: <span class="hljs-string">'1'</span>,
                        <span class="hljs-attr">name</span>: <span class="hljs-string">'Rexo'</span>,
                        <span class="hljs-attr">type</span>: <span class="hljs-string">'dogo'</span>,
                        <span class="hljs-attr">age</span>: <span class="hljs-number">4</span>,
                        <span class="hljs-attr">breed</span>: <span class="hljs-string">'doberman'</span>
                    },
                    {
                        <span class="hljs-attr">id</span>: <span class="hljs-string">'3'</span>,
                        <span class="hljs-attr">name</span>: <span class="hljs-string">'Mittens'</span>,
                        <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
                        <span class="hljs-attr">age</span>: <span class="hljs-number">2</span>,
                        <span class="hljs-attr">breed</span>: <span class="hljs-string">'tabby'</span>
                    },
                    {
                        <span class="hljs-attr">id</span>: <span class="hljs-string">'4'</span>,
                        <span class="hljs-attr">name</span>: <span class="hljs-string">'Salame'</span>,
                        <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
                        <span class="hljs-attr">age</span>: <span class="hljs-number">6</span>,
                        <span class="hljs-attr">breed</span>: <span class="hljs-string">'pinky'</span>
                    }
                ])
            })
    })
})
</code></pre>
<p>This a test suite for our GraphQL API. It uses the <code>supertest</code> library to make HTTP requests to the API endpoint (<code>http://localhost:4000/</code>) and verifies that the API responds correctly to various queries and mutations.</p>
<p>The code has five different test cases:</p>
<ol>
<li><p><code>Get all pets</code>: This test queries the API for all pets and verifies that the response matches an expected list of pets.</p>
</li>
<li><p><code>Get pet detail</code>: This test queries the API for the details of a specific pet and verifies that the response matches the expected details for that pet.</p>
</li>
<li><p><code>Edit pet</code>: This test performs a mutation to edit the details of a specific pet and verifies that the response matches the expected edited details for that pet.</p>
</li>
<li><p><code>Add pet</code>: This test performs a mutation to add a new pet and verifies that the response matches the expected details for the newly added pet.</p>
</li>
<li><p><code>Delete pet</code>: This test performs a mutation to delete a specific pet and verifies that the response matches the expected list of pets after the deletion.</p>
</li>
</ol>
<p>Each test case includes a <code>postData</code> object that contains the GraphQL query or mutation to be sent to the API endpoint as well as any necessary variables.</p>
<p>The actual HTTP request is made using the <code>request</code> function from the <code>supertest</code> library, which sends a POST request to the API endpoint with the <code>postData</code> object in the request body. The response is then parsed as JSON and the test case verifies that the response matches the expected result using the <code>expect</code> function from the Jest testing framework.</p>
<p>Now go to your terminal, run <code>npm test</code>, and you should see all your tests passing:</p>
<pre><code class="lang-javascript">&gt; jest

 PASS  pets/pets.test.js
  Get all pets
    ✓ returns all pets (<span class="hljs-number">15</span> ms)
  Get pet detail
    ✓ Return pet detail information (<span class="hljs-number">2</span> ms)
  Edit pet
    ✓ Updates pet and returns it (<span class="hljs-number">1</span> ms)
  Add pet
    ✓ Adds <span class="hljs-keyword">new</span> pet and returns the added item (<span class="hljs-number">1</span> ms)
  Delete pet
    ✓ Deletes given pet and returns updated list (<span class="hljs-number">1</span> ms)

Test Suites: <span class="hljs-number">1</span> passed, <span class="hljs-number">1</span> total
<span class="hljs-attr">Tests</span>:       <span class="hljs-number">5</span> passed, <span class="hljs-number">5</span> total
<span class="hljs-attr">Snapshots</span>:   <span class="hljs-number">0</span> total
<span class="hljs-attr">Time</span>:        <span class="hljs-number">0.607</span> s, estimated <span class="hljs-number">1</span> s
Ran all test suites.
</code></pre>
<h1 id="heading-how-to-consume-a-graphql-api-on-a-front-end-react-app">How to Consume a GraphQL API on a Front-end React App</h1>
<p>Now we know our server is running and behaving as expected. Let's see some more realistic example of how our API might be consumed by a front end app.</p>
<p>For this example, we'll use a React application, and <a target="_blank" href="https://www.apollographql.com/docs/react/">Apollo client</a> to send and process our requests.</p>
<h2 id="heading-our-tools-2">Our Tools</h2>
<p><a target="_blank" href="https://react.dev/"><strong>React</strong></a> is a popular JavaScript library for building user interfaces. It allows developers to create reusable UI components and efficiently update and render them in response to changes in application state.</p>
<p>Regarding <strong>Apollo client</strong>, we've introduced it already.</p>
<p>Side comment – we're using Apollo client here since it's a very popular tool and it makes sense to use the same set of libraries both in front and back-end. If you're interested in other possible ways a GraphQL API can be consumed from a front-end React App, <a target="_blank" href="https://www.freecodecamp.org/news/5-ways-to-fetch-data-react-graphql/">Reed Barger has a pretty cool article on this topic</a>.</p>
<h2 id="heading-the-code-2">The Code</h2>
<p>Let's create our React app by running <code>yarn create vite</code> and following the terminal prompts. Once that's done, run <code>yarn add react-router-dom</code> (which we'll use to setup basic routing in our app).</p>
<h3 id="heading-appjsx"><strong>App.jsx</strong></h3>
<p>Put this code within your <code>App.jsx</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Suspense, lazy, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { BrowserRouter <span class="hljs-keyword">as</span> Router, Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>

<span class="hljs-keyword">const</span> PetList = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/PetList'</span>))
<span class="hljs-keyword">const</span> PetDetail = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/PetDetail'</span>))
<span class="hljs-keyword">const</span> EditPet = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/EditPet'</span>))
<span class="hljs-keyword">const</span> AddPet = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/AddPet'</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">const</span> [petToEdit, setPetToEdit] = useState(<span class="hljs-literal">null</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">Router</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Pet shelter<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;&gt;</span><span class="hljs-tag">&lt;/&gt;</span>}&gt;
                                <span class="hljs-tag">&lt;<span class="hljs-name">PetList</span> /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</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">'/:petId'</span>
                        <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>
                            &lt;<span class="hljs-attr">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;&gt;</span><span class="hljs-tag">&lt;/&gt;</span>}&gt;
                                <span class="hljs-tag">&lt;<span class="hljs-name">PetDetail</span> <span class="hljs-attr">setPetToEdit</span>=<span class="hljs-string">{setPetToEdit}</span> /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</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">'/:petId/edit'</span>
                        <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>
                            &lt;<span class="hljs-attr">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;&gt;</span><span class="hljs-tag">&lt;/&gt;</span>}&gt;
                                <span class="hljs-tag">&lt;<span class="hljs-name">EditPet</span> <span class="hljs-attr">petToEdit</span>=<span class="hljs-string">{petToEdit}</span> /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
                        }
                    /&gt;</span>

                    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span>
                        <span class="hljs-attr">path</span>=<span class="hljs-string">'/add'</span>
                        <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>
                            &lt;<span class="hljs-attr">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;&gt;</span><span class="hljs-tag">&lt;/&gt;</span>}&gt;
                                <span class="hljs-tag">&lt;<span class="hljs-name">AddPet</span> /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span></span>
                        }
                    /&gt;
                &lt;/Routes&gt;
            &lt;/Router&gt;
        &lt;/div&gt;
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>Here we're just defining our routes. We'll have 4 main routes in our app, each corresponding to a different view:</p>
<ul>
<li><p>One to see the whole list of pets.</p>
</li>
<li><p>One to see the detail of a single pet.</p>
</li>
<li><p>One to edit a single pet.</p>
</li>
<li><p>One to add a new pet to the list.</p>
</li>
</ul>
<p>Besides, we have a button to add a new pet and a state that will store the information of the pet we want to edit.</p>
<p>Next, create a <code>pages</code> directory with these files in it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-281.png" alt="image-281" width="600" height="400" loading="lazy"></p>
<p><em>Folder structure</em></p>
<h3 id="heading-mainjs">main.js</h3>
<p>Before jumping into our pages, we have to set up the Apollo client library. Run <code>yarn add @apollo/client</code> and <code>yarn add graphql</code> to install the necessary dependencies.</p>
<p>The go to the <code>main.js</code> file and drop this code in it:</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">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>
<span class="hljs-keyword">import</span> { ApolloClient, InMemoryCache, ApolloProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> ApolloClient({
  <span class="hljs-attr">uri</span>: <span class="hljs-string">'http://localhost:4000/'</span>,
  <span class="hljs-attr">cache</span>: <span class="hljs-keyword">new</span> InMemoryCache(),
})

ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)).render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ApolloProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{client}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ApolloProvider</span>&gt;</span></span>
)
</code></pre>
<p>Here we're initializing the <code>ApolloClient</code>, passing its constructor a configuration object with the <code>uri</code> and <code>cache</code> fields:</p>
<ul>
<li><p><code>uri</code> specifies the URL of our GraphQL server.</p>
</li>
<li><p><code>cache</code> is an instance of <code>InMemoryCache</code>, which Apollo Client uses to cache query results after fetching them.</p>
</li>
</ul>
<p>Then we wrap our <code>App</code> component with our ApolloProvider. This allows any component in our component tree to use the hooks provided by Apollo client, much like React Context works. ;)</p>
<h3 id="heading-mutations-and-queries">Mutations and queries</h3>
<p>In the root of your project, create this folder structure:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-6.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Folder structure</em></p>
<p>In these two files we'll declare the request bodies we'll use for our queries and mutations. I like to separate this into different files because it gives use a clear view of the different kinds of request we have in our app, and it also keeps our component's code cleaner.</p>
<p>In the <code>queries.js</code> file drop this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { gql } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> GET_PETS = gql<span class="hljs-string">`
    query Pets {
        pets {
            id
            name
            type
            breed
        }
    }
`</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> GET_PET = gql<span class="hljs-string">`
    query Pet($petId: ID!) {
        pet(id: $petId) {
            id
            name
            type
            age
            breed
        }
    }
`</span>
</code></pre>
<p>And in the <code>mutations.js</code> file drop this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { gql } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> DELETE_PET = gql<span class="hljs-string">`
    mutation DeletePet($deletePetId: ID!) {
        deletePet(id: $deletePetId) {
            id
        }
    }
`</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ADD_PET = gql<span class="hljs-string">`
    mutation AddPet($petToAdd: PetToAdd!) {
        addPet(petToAdd: $petToAdd) {
            id
            name
            type
            age
            breed
        }
    }
`</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> EDIT_PET = gql<span class="hljs-string">`
    mutation EditPet($petToEdit: PetToEdit!) {
        editPet(petToEdit: $petToEdit) {
            id
            name
            type
            age
            breed
        }
    }
`</span>
</code></pre>
<p>As you can see, the syntax for queries and mutations is fairly similar. Request bodies are written in GraphQL query language, which is used to define the structure and data types of data that can be requested from a GraphQL API.</p>
<ul>
<li>GraphQL Query Syntax:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> GET_PETS = gql<span class="hljs-string">`
    query Pets {
        pets {
            id
            name
            type
            breed
        }
    }
`</span>
</code></pre>
<p>This query is named <code>Pets</code> and it requests data from the <code>pets</code> field. The fields <code>id</code>, <code>name</code>, <code>type</code>, and <code>breed</code> are requested from each <code>Pet</code> object returned by the API.</p>
<p>In GraphQL, queries always start with the keyword <code>query</code> and are followed by the name of the query, if provided. The fields requested are enclosed in curly braces and can be nested to request data from related fields.</p>
<ul>
<li>GraphQL Mutation Syntax:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ADD_PET = gql<span class="hljs-string">`
    mutation AddPet($petToAdd: PetToAdd!) {
        addPet(petToAdd: $petToAdd) {
            id
            name
            type
            age
            breed
        }
    }
`</span>
</code></pre>
<p>This mutation is named <code>AddPet</code> and sends a new <code>Pet</code> object to be added to the API via the <code>addPet</code> mutation. The <code>$petToAdd</code> variable is defined as a required input of type <code>PetToAdd</code>. When the mutation is executed, the input variable will be passed in as an argument to the <code>addPet</code> mutation. The mutation then returns the <code>id</code>, <code>name</code>, <code>type</code>, <code>age</code>, and <code>breed</code> fields for the newly created <code>Pet</code> object.</p>
<p>In GraphQL, mutations always start with the keyword <code>mutation</code> and are followed by the name of the mutation, if provided. The fields requested in the mutation response are also enclosed in curly braces.</p>
<p>Note that both queries and mutations in GraphQL can accept variables as input, which are defined in the query or mutation body using a special syntax (<code>$variableName: variableType!</code>). These variables can be passed in when the query or mutation is executed, allowing for more dynamic and reusable queries and mutations.</p>
<h3 id="heading-petlistjsx"><strong>PetList.jsx</strong></h3>
<p>Let's start with the file responsible for rendering the whole list of pets:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> { useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>
<span class="hljs-keyword">import</span> { GET_PETS } <span class="hljs-keyword">from</span> <span class="hljs-string">'../api/queries'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PetList</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> { loading, error, data } = useQuery(GET_PETS)

    <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">h2</span>&gt;</span>Pet List<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">'/add'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Add new pet<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

            {loading &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
            {error &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error: {error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}

            {data?.pets?.map(pet =&gt; {
                return (
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{pet?.id}</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                            {pet?.name} - {pet?.type} - {pet?.breed}
                        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                        <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">pet</span>?<span class="hljs-attr">.id</span>}`}&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Pet detail<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                )
            })}
        <span class="hljs-tag">&lt;/&gt;</span></span>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PetList
</code></pre>
<p>This code defines a React functional component called <code>PetList</code> that fetches a list of pets from a GraphQL API using the <code>useQuery</code> hook provided by the <code>@apollo/client</code> library. The query used to fetch the pets is defined in a separate file called <code>queries.js</code>, which exports a GraphQL query called <code>GET_PETS</code>.</p>
<p>The <code>useQuery</code> hook returns an object with three properties: <code>loading</code>, <code>error</code>, and <code>data</code>. These properties are destructured from the object and used to conditionally render different UI elements depending on the status of the API request.</p>
<p>If <code>loading</code> is true, a loading message is displayed on the screen. If <code>error</code> is defined, an error message is displayed with the specific error message returned by the API. If <code>data</code> is defined and contains an array of <code>pets</code>, each <code>pet</code> is displayed in a div with their <code>name</code>, <code>type</code>, and <code>breed</code>. Each pet div also contains a link to view more details about the pet.</p>
<p>The <code>useQuery</code> hook works by executing the <code>GET_PETS</code> query and returning the result as an object with the <code>loading</code>, <code>error</code>, and <code>data</code> properties. When the component first renders, <code>loading</code> is true while the query is being executed. If the query is successful, <code>loading</code> is false and <code>data</code> is populated with the results. If the query encounters an error, <code>error</code> is populated with the specific error message.</p>
<p>As you can see, managing requests with Apollo client is really nice and simple. And the hooks it provides, save us quite a bit of code normally used to execute requests, store it's response and handle errors.</p>
<p>Remember that to make calls to our server, we must have it up and running by running <code>nodemon app.js</code> in our server project terminal.</p>
<p>Just to show there's no weird magic going on here, if we go to our browser, open the dev tools and go to the network tab, we could see our app is making a POST request to our server endpoint. And that the payload is our request body in the form of a string.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-7.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>The POST request</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-8.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Request body</em></p>
<p>This means that if we wanted to, we could also consume our GraphQL API by using fetch, like following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PetList</span>(<span class="hljs-params"></span>) </span>{

    <span class="hljs-keyword">const</span> [pets, setPets] = useState([])

    <span class="hljs-keyword">const</span> getPets = <span class="hljs-function">() =&gt;</span> {
        fetch(<span class="hljs-string">'http://localhost:4000/'</span>, {
            <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
            <span class="hljs-attr">headers</span>: {
                <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
            },
            <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
                <span class="hljs-attr">query</span>: <span class="hljs-string">`
                query Pets {
                    pets {
                    id
                    name
                    type
                    breed
                    }
                }
                `</span>
            })
        })
            .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
            .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> setPets(data?.data?.pets))
            .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(error))
    }

    useEffect(<span class="hljs-function">() =&gt;</span> {
        getPets()
    }, [])

    <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">h2</span>&gt;</span>Pet List<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">'/add'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Add new pet<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

            {pets?.map(pet =&gt; {
                return (
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{pet?.id}</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                            {pet?.name} - {pet?.type} - {pet?.breed}
                        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                        <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">pet</span>?<span class="hljs-attr">.id</span>}`}&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Pet detail<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                )
            })}
        <span class="hljs-tag">&lt;/&gt;</span></span>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PetList
</code></pre>
<p>If you check your network tab again, you should see still the same POST request with the some request body.</p>
<p>Of course this approach is not very practical as it requires more lines of code to perform the same thing. But it's important to know that libraries like Apollo only give us a <a target="_blank" href="https://www.freecodecamp.org/news/an-introduction-to-programming-paradigms/#declarative-programming">declarative API</a> to work with and simplify our code. Beneath it all we're still working with regular HTTP requests.</p>
<h3 id="heading-petdetailjsx"><strong>PetDetail.jsx</strong></h3>
<p>Now let's go to the <code>PetDetail.jsx</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { useParams, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> { useQuery, useMutation } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>
<span class="hljs-keyword">import</span> { GET_PET } <span class="hljs-keyword">from</span> <span class="hljs-string">'../api/queries'</span>
<span class="hljs-keyword">import</span> { DELETE_PET } <span class="hljs-keyword">from</span> <span class="hljs-string">'../api/mutations'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PetDetail</span>(<span class="hljs-params">{ setPetToEdit }</span>) </span>{
    <span class="hljs-keyword">const</span> { petId } = useParams()

    <span class="hljs-keyword">const</span> { loading, error, data } = useQuery(GET_PET, {
        <span class="hljs-attr">variables</span>: { petId }
    })

    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (data &amp;&amp; data?.pet) setPetToEdit(data?.pet)
    }, [data])

    <span class="hljs-keyword">const</span> [deletePet, { <span class="hljs-attr">loading</span>: deleteLoading, <span class="hljs-attr">error</span>: deleteError, <span class="hljs-attr">data</span>: deleteData }] = useMutation(DELETE_PET, {
        <span class="hljs-attr">variables</span>: { <span class="hljs-attr">deletePetId</span>: petId }
    })

    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (deleteData &amp;&amp; deleteData?.deletePet) <span class="hljs-built_in">window</span>.location.href = <span class="hljs-string">'/'</span>
    }, [deleteData])

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">center</span>', <span class="hljs-attr">aligniItems:</span> '<span class="hljs-attr">center</span>' }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Pet Detail<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">'/'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Back to list<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

            {(loading || deleteLoading) &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}

            {error &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error: {error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
            {deleteError &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>deleteError: {deleteError.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}

            {data?.pet &amp;&amp; (
                <span class="hljs-tag">&lt;&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pet name: {data?.pet?.name}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pet type: {data?.pet?.type}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pet age: {data?.pet?.age}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pet breed: {data?.pet?.breed}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">center</span>', <span class="hljs-attr">aligniItems:</span> '<span class="hljs-attr">center</span>' }}&gt;</span>
                        <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">data</span>?<span class="hljs-attr">.pet</span>?<span class="hljs-attr">.id</span>}/<span class="hljs-attr">edit</span>`}&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginRight:</span> <span class="hljs-attr">10</span> }}&gt;</span>Edit pet<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

                        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginLeft:</span> <span class="hljs-attr">10</span> }} <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> deletePet()}&gt;
                            Delete pet
                        <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;/&gt;</span></span>
            )}
        &lt;/div&gt;
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PetDetail
</code></pre>
<p>This component loads the detail info of the pet by executing a query in a very similar way than the previous component.</p>
<p>Moreover, it executes the mutation needed to delete the pet register. You can see that for this we're using the <code>useMutation</code> hook. It's quite similar to <code>useQuery</code>, but besides the <code>loading, error and data</code> values it also provides a function to execute our query after a given event.</p>
<p>You can see that for this mutation hook we're passing an object as second parameter, containing the variables this mutation requires. In this case, it's the id of the pet register we want to delete.</p>
<pre><code class="lang-plaintext">const [deletePet, { loading: deleteLoading, error: deleteError, data: deleteData }] = useMutation(DELETE_PET, {
    variables: { deletePetId: petId }
})
</code></pre>
<p>Remember that when we declared our mutation in <code>mutations.js</code> we had already declared the variables this mutation would use.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> DELETE_PET = gql<span class="hljs-string">`
    mutation DeletePet($deletePetId: ID!) {
        deletePet(id: $deletePetId) {
            id
        }
    }
`</span>
</code></pre>
<h3 id="heading-addpetjsx"><strong>AddPet.jsx</strong></h3>
<p>This is the file responsible for adding a new pet to our register:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> { useMutation } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>
<span class="hljs-keyword">import</span> { ADD_PET } <span class="hljs-keyword">from</span> <span class="hljs-string">'../api/mutations'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AddPet</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [petName, setPetName] = useState()
    <span class="hljs-keyword">const</span> [petType, setPetType] = useState()
    <span class="hljs-keyword">const</span> [petAge, setPetAge] = useState()
    <span class="hljs-keyword">const</span> [petBreed, setPetBreed] = useState()

    <span class="hljs-keyword">const</span> [addPet, { loading, error, data }] = useMutation(ADD_PET, {
        <span class="hljs-attr">variables</span>: {
            <span class="hljs-attr">petToAdd</span>: {
                <span class="hljs-attr">name</span>: petName,
                <span class="hljs-attr">type</span>: petType,
                <span class="hljs-attr">age</span>: <span class="hljs-built_in">parseInt</span>(petAge),
                <span class="hljs-attr">breed</span>: petBreed
            }
        }
    })

    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (data &amp;&amp; data?.addPet) <span class="hljs-built_in">window</span>.location.href = <span class="hljs-string">`/<span class="hljs-subst">${data?.addPet?.id}</span>`</span>
    }, [data])

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">center</span>', <span class="hljs-attr">aligniItems:</span> '<span class="hljs-attr">center</span>' }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Add Pet<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">'/'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Back to list<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

            {loading || error ? (
                <span class="hljs-tag">&lt;&gt;</span>
                    {loading &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
                    {error &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error: {error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
                <span class="hljs-tag">&lt;/&gt;</span></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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet name<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">value</span>=<span class="hljs-string">{petName}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetName(e.target.value)} /&gt;
                    <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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet type<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">value</span>=<span class="hljs-string">{petType}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetType(e.target.value)} /&gt;
                    <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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet age<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">value</span>=<span class="hljs-string">{petAge}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetAge(e.target.value)} /&gt;
                    <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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet breed<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">value</span>=<span class="hljs-string">{petBreed}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetBreed(e.target.value)} /&gt;
                    <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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginTop:</span> <span class="hljs-attr">30</span> }}
                        <span class="hljs-attr">disabled</span>=<span class="hljs-string">{!petName</span> || !<span class="hljs-attr">petType</span> || !<span class="hljs-attr">petAge</span> || !<span class="hljs-attr">petBreed</span>}
                        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> addPet()}
                    &gt;
                        Add pet
                    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;/&gt;</span></span>
            )}
        &lt;/div&gt;
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AddPet
</code></pre>
<p>Here we have a component that loads a form to add a new pet and performs a mutation when the data is sent. It accepts the new pet info as parameter, in a similar way that the <code>deletePet</code> mutation accepted the pet id.</p>
<h3 id="heading-editpetjsx"><strong>EditPet.jsx</strong></h3>
<p>Finally, the file responsible for editing a pet register:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> { useMutation } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>
<span class="hljs-keyword">import</span> { EDIT_PET } <span class="hljs-keyword">from</span> <span class="hljs-string">'../api/mutations'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">EditPet</span>(<span class="hljs-params">{ petToEdit }</span>) </span>{
    <span class="hljs-keyword">const</span> [petName, setPetName] = useState(petToEdit?.name)
    <span class="hljs-keyword">const</span> [petType, setPetType] = useState(petToEdit?.type)
    <span class="hljs-keyword">const</span> [petAge, setPetAge] = useState(petToEdit?.age)
    <span class="hljs-keyword">const</span> [petBreed, setPetBreed] = useState(petToEdit?.breed)

    <span class="hljs-keyword">const</span> [editPet, { loading, error, data }] = useMutation(EDIT_PET, {
        <span class="hljs-attr">variables</span>: {
            <span class="hljs-attr">petToEdit</span>: {
                <span class="hljs-attr">id</span>: <span class="hljs-built_in">parseInt</span>(petToEdit.id),
                <span class="hljs-attr">name</span>: petName,
                <span class="hljs-attr">type</span>: petType,
                <span class="hljs-attr">age</span>: <span class="hljs-built_in">parseInt</span>(petAge),
                <span class="hljs-attr">breed</span>: petBreed
            }
        }
    })

    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (data &amp;&amp; data?.editPet?.id) <span class="hljs-built_in">window</span>.location.href = <span class="hljs-string">`/<span class="hljs-subst">${data?.editPet?.id}</span>`</span>
    }, [data])

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">center</span>', <span class="hljs-attr">aligniItems:</span> '<span class="hljs-attr">center</span>' }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Edit Pet<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">'/'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Back to list<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

            {loading || error ? (
                <span class="hljs-tag">&lt;&gt;</span>
                    {loading &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
                    {error &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error: {error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
                <span class="hljs-tag">&lt;/&gt;</span></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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet name<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">value</span>=<span class="hljs-string">{petName}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetName(e.target.value)} /&gt;
                    <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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet type<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">value</span>=<span class="hljs-string">{petType}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetType(e.target.value)} /&gt;
                    <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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet age<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">value</span>=<span class="hljs-string">{petAge}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetAge(e.target.value)} /&gt;
                    <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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet breed<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">value</span>=<span class="hljs-string">{petBreed}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetBreed(e.target.value)} /&gt;
                    <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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginTop:</span> <span class="hljs-attr">30</span> }}
                        <span class="hljs-attr">disabled</span>=<span class="hljs-string">{!petName</span> || !<span class="hljs-attr">petType</span> || !<span class="hljs-attr">petAge</span> || !<span class="hljs-attr">petBreed</span>}
                        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> editPet()}
                    &gt;
                        Save changes
                    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;/&gt;</span></span>
            )}
        &lt;/div&gt;
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> EditPet
</code></pre>
<p>Last, we have a component to edit a pet register through a form. It performs a mutation when the data is sent, and as parameters it accepts the new pet info.</p>
<p>And that's it! We're using all of our API queries and mutations in our front end app. =)</p>
<h1 id="heading-how-to-document-a-graphql-api-with-apollo-sandbox">How to Document a GraphQL API with Apollo Sandbox</h1>
<p>One of Apollo's coolest features is that it comes with a built-in sandbox you can use to test and document your API.</p>
<p>Apollo Sandbox is a web-based GraphQL IDE that provides a sandbox environment for testing GraphQL queries, mutations, and subscriptions. It is a free, online tool provided by Apollo that allows you to interact with your GraphQL API and explore its schema, data, and capabilities.</p>
<p>Here are some of the main features of Apollo Sandbox:</p>
<ol>
<li><p>Query Editor: A feature-rich GraphQL query editor that provides syntax highlighting, autocompletion, validation, and error highlighting.</p>
</li>
<li><p>Schema Explorer: A graphical interface that allows you to explore your GraphQL schema and see its types, fields, and relationships.</p>
</li>
<li><p>Mocking: Apollo Sandbox allows you to easily generate mock data based on your schema, which is useful for testing your queries and mutations without connecting to a real data source.</p>
</li>
<li><p>Collaboration: You can share your sandbox with others, collaborate on queries, and see real-time changes.</p>
</li>
<li><p>Documentation: You can add documentation to your schema and query results to help others understand your API.</p>
</li>
</ol>
<p>To use our sandbox, simply open your browser at <a target="_blank" href="http://localhost:4000/"><code>http://localhost:4000/</code></a>. You should see something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Apollo sandbox</em></p>
<p>From here you can see the API data schema and available mutations and queries, and also execute them and see how your API responds. For example, by executing the <code>pets</code> query, we can see that response on the right side panel.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Executing a query</em></p>
<p>If you hop on to the schema section you could see a whole detail of the available queries, mutations object and input types in our API.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-9.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>The schema section</em></p>
<p>Apollo sandbox is a great tool that can be used both as self-documentation for our API and a great development and testing tool.</p>
<h1 id="heading-wrapping-up"><strong>Wrapping Up</strong></h1>
<p>Well everyone, as always, I hope you enjoyed the article and learned something new.</p>
<p>If you want, you can also follow me on <a target="_blank" href="https://www.linkedin.com/in/germancocca/">LinkedIn</a> or <a target="_blank" href="https://twitter.com/CoccaGerman">Twitter</a>. See you in the next one!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/tumblr_6eb166181e857e65bb472a1ba4bd450c_d935c3d9_500.gif" alt="Image" width="600" height="400" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Handle File Uploads on the Back End in Node.js and Nuxt ]]>
                </title>
                <description>
                    <![CDATA[ By Austin Gil In some previous tutorials, I covered how to upload files using HTML and JavaScript. It requires sending HTTP requests with the [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) header set to multipa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/handle-file-uploads-on-the-backend-in-node-js-nuxt/</link>
                <guid isPermaLink="false">66d45d9acc7f04d2549a3722</guid>
                
                    <category>
                        <![CDATA[ Back end development  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 20 Apr 2023 22:27:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/Command-Line-Blog-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Austin Gil</p>
<p>In some previous tutorials, I covered how to upload files using <a target="_blank" href="https://austingil.com/uploading-files-with-html/">HTML</a> and <a target="_blank" href="https://austingil.com/upload-files-with-javascript/">JavaScript</a>. It requires sending HTTP requests with the <code>[Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)</code> header set to <code>multipart/form-data</code>.</p>
<p>Today, we are going to the back end to receive those <code>multipart/form-data</code> requests and access the binary data from those files.</p>
<h2 id="heading-some-background">Some Background</h2>
<p>Most of the concepts in this tutorial should broadly apply across frameworks, runtimes, and languages, but the code examples will be more specific.</p>
<p>I’ll be working within a <a target="_blank" href="https://nuxt.com/">Nuxt.js</a> project that runs in a <a target="_blank" href="https://nodejs.org/">Node.js</a> environment. Nuxt has some specific ways of <a target="_blank" href="https://nuxt.com/docs/guide/directory-structure/server">defining API routes</a> which require calling a global function called <code>defineEventHandler</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@see </span>https://nuxt.com/docs/guide/directory-structure/server
 * <span class="hljs-doctag">@see </span>https://nuxt.com/docs/guide/concepts/server-engine
 * <span class="hljs-doctag">@see </span>https://github.com/unjs/h3
 */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineEventHandler(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">ok</span>: <span class="hljs-literal">true</span> };
});
</code></pre>
<p>The <code>event</code> argument provides access to work directly with the underlying Node.js request object (a.k.a. <code>IncomingMessage</code>) through <code>event.node.req</code>. So we can write our Node-specific code in an abstraction, like a function called <code>doSomethingWithNodeRequest</code> that receives this Node request object and does something with it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineEventHandler(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> nodeRequestObject = event.node.req;

  doSomethingWithNodeRequest(event.node.req);

  <span class="hljs-keyword">return</span> { <span class="hljs-attr">ok</span>: <span class="hljs-literal">true</span> };
});

<span class="hljs-comment">/**
 * @param {import('http').IncomingMessage} req
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomethingWithNodeRequest</span>(<span class="hljs-params">req</span>) </span>{
  <span class="hljs-comment">// Do not specific stuff here</span>
}
</code></pre>
<p>Working directly with Node in this way means the code and concepts should apply regardless of whatever higher-level framework you’re working with. Ultimately, finish things up working in Nuxt.js.</p>
<h2 id="heading-how-to-deal-with-multipartform-data-in-nodejs">How to Deal with <code>multipart/form-data</code> in Node.js</h2>
<p>In this section, we’ll dive into some low-level concepts that are good to understand, but not strictly necessary. Feel free to skip this section if you are already familiar with chunks and streams and buffers in Node.js.</p>
<p>Uploading a file requires sending a <code>multipart/form-data</code> request. In these requests, the browser will split the data into little “<a target="_blank" href="https://en.wikipedia.org/wiki/Chunking_(computing)">chunks</a>” and send them through the connection, one chunk at a time. This is necessary because files can be too large to send in as one massive payload.</p>
<p>Chunks of data being sent over time make up what’s called a “<a target="_blank" href="https://en.wikipedia.org/wiki/Stream_(computing)">stream</a>”. Streams are kind of hard to understand the first time around, at least they were for me. They deserve a full article (or many) on their own, so I’ll share <a target="_blank" href="https://web.dev/streams/">web.dev’s excellent guide</a> in case you want to learn more.</p>
<p>Basically, a stream is sort of like a conveyor belt of data, where each chunk can be processed as it comes in. In terms of an HTTP request, the backend will receive parts of the request, one bit at a time.</p>
<p>Node.js provides us with an event handler API through the request object’s <code>on</code> method, which allows us to listen to “data” events as they are streamed into the backend.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@param <span class="hljs-type">{import('http').IncomingMessage}</span> <span class="hljs-variable">req</span></span>
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomethingWithNodeRequest</span>(<span class="hljs-params">req</span>) </span>{
  req.on(<span class="hljs-string">"data"</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(data);
  }
}
</code></pre>
<p>For example, when I upload <a target="_blank" href="https://www.instagram.com/p/CmUxW6jDmWO/">a photo of Nugget making a cute yawny face</a>, then look at the server’s console, I’ll see some weird things that look like this:</p>
<p><img src="https://austingil.com/wp-content/uploads/image-63-1080x103.png" alt="Screenshot of a terminal with two logs of text that begin with &quot;<Buffer&quot;, then a long list of two digit hex values, and end with a large number and &quot;... more bytes>&quot;" width="1080" height="103" loading="lazy">
<em>I used a screenshot here to prevent assistive technology from reading that gibberish out loud. Could you imagine?</em></p>
<p>These two pieces of garbled nonsense are called “<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/buffer">buffers</a>” and they represent the two chunks of data that made up the request stream containing the cute photo of Nugget.</p>
<blockquote>
<p>A buffer is a storage in physical memory used to temporarily store data while it is being transferred from one place to another. – <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/buffer">MDN</a></p>
</blockquote>
<p>Buffers are another weird, low-level concept I have to explain when talking about working with files in JavaScript. </p>
<p>JavaScript doesn’t work directly on binary data, so we get to learn about buffers. It’s also OK if these concepts still feel a little vague. Understanding everything completely is not the important part right now, and as you continue to learn about file transfers, you’ll gain a better knowledge of how it all works together.</p>
<p>Working with one partial chunk of data is not super useful. What we can do instead is rewrite our function into something we can work with:</p>
<ol>
<li>Return a <code>[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)</code> to make the async syntax easy to work with.</li>
<li>Provide an <code>[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)</code> to store the chunks of data to use later on.</li>
<li>Listen for the “data” event and add the chunks to our collection as they arrive.</li>
<li>Listen to the “end” event and convert the chunks into something we can work with.</li>
<li>Resolve the <code>Promise</code> with the final request payload.</li>
<li>We should also remember to handle “error” events.</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@param <span class="hljs-type">{import('http').IncomingMessage}</span> <span class="hljs-variable">req</span></span>
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomethingWithNodeRequest</span>(<span class="hljs-params">req</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-comment">/** @type {any[]} */</span>
    <span class="hljs-keyword">const</span> chunks = [];
    req.on(<span class="hljs-string">'data'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
      chunks.push(data);
    });
    req.on(<span class="hljs-string">'end'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> payload = Buffer.concat(chunks).toString()
      resolve(payload);
    });
    req.on(<span class="hljs-string">'error'</span>, reject);
  });
}
</code></pre>
<p>And every time that the request receives some data, it pushes that data into the array of chunks.</p>
<p>So with that function set up, we can actually <code>[await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await)</code> that returned <code>Promise</code> until the request has finished receiving all the data from the request stream, and log the resolved value to the console.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineEventHandler(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> nodeRequestObject = event.node.req;

  <span class="hljs-keyword">const</span> body = <span class="hljs-keyword">await</span> doSomethingWithNodeRequest(event.node.req);
  <span class="hljs-built_in">console</span>.log(body)

  <span class="hljs-keyword">return</span> { <span class="hljs-attr">ok</span>: <span class="hljs-literal">true</span> };
});
</code></pre>
<p>This is the request body. Isn’t it beautiful?</p>
<p><img src="https://austingil.com/wp-content/uploads/image-64-1080x479.png" alt="Sceenshot of a terminal containing a long string of unintelligible text including alphanumerical values as well as symbols and characters that cannot be rendered. It legitimately looks like alien writing" width="1080" height="479" loading="lazy">
<em>I honestly don’t even know what a screen reader would do with if this was plain text.</em></p>
<p>If you upload an image file, it’ll probably look like an alien has hacked your computer. Don’t worry, it hasn’t. That’s literally what the text contents of that file look like. You can even try opening up an image file in a basic text editor and see the same thing.</p>
<p>If I upload a more basic example, like a <code>.txt</code> file with some plain text in it, the body might look like this:</p>
<pre><code>Content-Disposition: form-data; name=<span class="hljs-string">"file"</span>; filename=<span class="hljs-string">"dear-nugget.txt"</span>
Content-Type: text/plain

I love you!
------WebKitFormBoundary4Ay52hDeKB5x2vXP--
</code></pre><p>Notice that the request is broken up into different sections for each form field. The sections are separated by the “form boundary”, which the browser will inject by default. </p>
<p>I’ll skip going into excess details, so if you want to read more, check out <code>[Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)</code> on MDN. The important thing to know is that <code>multipart/form-data</code> requests are much more complex than just key/value pairs.</p>
<p>Most server frameworks provide built-in tools to access the body of a request. So we’ve actually reinvented the wheel. For example, Nuxt provides a global <code>readBody</code> function. So we could have accomplished the same thing without writing our own code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineEventHandler(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> nodeRequestObject = event.node.req;

  <span class="hljs-keyword">const</span> body = <span class="hljs-keyword">await</span> readBody(event.node.req);
  <span class="hljs-built_in">console</span>.log(body)

  <span class="hljs-keyword">return</span> { <span class="hljs-attr">ok</span>: <span class="hljs-literal">true</span> };
});
</code></pre>
<p>This works fine for other content types, but for <code>multipart/form-data</code>, it has issues. The entire body of the request is being read into memory as one giant string of text. This includes the <code>Content-Disposition</code> information, the form boundaries, and the form fields and values. Never mind the fact that the files aren’t even being written to disk. </p>
<p>The big issue here is if a very large file is uploaded, it could consume all the memory of the application and cause it to crash.</p>
<p>The solution is, once again, working with streams.</p>
<p>When our server receives a chunk of data from the request stream, instead of storing it in memory, we can pipe it to a different stream. Specifically, we can send it to a stream that writes data to the file system using <code>[createWriteStream](https://nodejs.org/api/fs.html#filehandlecreatewritestreamoptions)</code>. As the chunks come in from the request, that data gets written to the file system, then released from memory.</p>
<p>That’s about as far down as I want to go into the low-level concepts. Let’s go back up to solving the problem without reinventing the wheel.</p>
<h2 id="heading-how-to-use-a-library-to-stream-data-onto-disk">How to Use a Library to Stream Data onto Disk</h2>
<p>Probably my best advice for handling file uploads is to reach for a library that does all this work for you:</p>
<ul>
<li>Parse <code>multipart/form-data</code> requests</li>
<li>Separate the files from the other form fields</li>
<li>Stream the file data into the file system</li>
<li>Provide you with the form field data as well as useful data about the files</li>
</ul>
<p>Today, I’m going to be using this library called <a target="_blank" href="https://github.com/node-formidable/formidable/">formidable</a>. You can install it with <code>npm install formidable</code>, then import it into your project.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> formidable <span class="hljs-keyword">from</span> <span class="hljs-string">'formidable'</span>;
</code></pre>
<p>Formidable works directly with the Node request object, which we conveniently already grabbed from the Nuxt event (“Wow, what amazing foresight!!” 🤩).</p>
<p>So we can modify our <code>doSomethingWithNodeRequest</code> function to use formidable instead. It should still return a promise because formidable uses callbacks, but promises are nicer to work with. Otherwise, we can mostly replace the contents of the function with formidable. </p>
<p>We’ll need to create a formidable instance and use it to parse the request object. As long as there isn’t an error, we can resolve the promise with a single object that contains both the form fields and the files.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/**
 * <span class="hljs-doctag">@param <span class="hljs-type">{import('http').IncomingMessage}</span> <span class="hljs-variable">req</span></span>
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomethingWithNodeRequest</span>(<span class="hljs-params">req</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-comment">/** @see https://github.com/node-formidable/formidable/ */</span>
    <span class="hljs-keyword">const</span> form = formidable({ <span class="hljs-attr">multiples</span>: <span class="hljs-literal">true</span> })
    form.parse(req, <span class="hljs-function">(<span class="hljs-params">error, fields, files</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (error) {
        reject(error);
        <span class="hljs-keyword">return</span>;
      }
      resolve({ ...fields, ...files });
    });
  });
}
</code></pre>
<p>This provides us with a handy function to parse <code>multipart/form-data</code> using promises and access the request’s regular form fields, as well as information about the files that were written to disk using streams.</p>
<p>Now, we can examine the request body:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineEventHandler(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> nodeRequestObject = event.node.req;

  <span class="hljs-keyword">const</span> body = <span class="hljs-keyword">await</span> doSomethingWithNodeRequest(event.node.req);
  <span class="hljs-built_in">console</span>.log(body)

  <span class="hljs-keyword">return</span> { <span class="hljs-attr">ok</span>: <span class="hljs-literal">true</span> };
});
</code></pre>
<p>We should see an object containing all the form fields and their values, but for each file input, we’ll see an object that represents the uploaded file, and not the file itself. This object contains all sorts of useful information including its path on disk, name, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types">mimetype</a>, and more.</p>
<pre><code class="lang-javascript">{
  file-input-name: PersistentFile {
    <span class="hljs-attr">_events</span>: [<span class="hljs-built_in">Object</span>: <span class="hljs-literal">null</span> prototype] { <span class="hljs-attr">error</span>: [<span class="hljs-built_in">Function</span> (anonymous)] },
    <span class="hljs-attr">_eventsCount</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">_maxListeners</span>: <span class="hljs-literal">undefined</span>,
    <span class="hljs-attr">lastModifiedDate</span>: <span class="hljs-number">2023</span><span class="hljs-number">-03</span><span class="hljs-number">-21</span>T22:<span class="hljs-number">57</span>:<span class="hljs-number">42.332</span>Z,
    <span class="hljs-attr">filepath</span>: <span class="hljs-string">'/tmp/d53a9fd346fcc1122e6746600'</span>,
    <span class="hljs-attr">newFilename</span>: <span class="hljs-string">'d53a9fd346fcc1122e6746600'</span>,
    <span class="hljs-attr">originalFilename</span>: <span class="hljs-string">'file.txt'</span>,
    <span class="hljs-attr">mimetype</span>: <span class="hljs-string">'text/plain'</span>,
    <span class="hljs-attr">hashAlgorithm</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">size</span>: <span class="hljs-number">13</span>,
    <span class="hljs-attr">_writeStream</span>: WriteStream {
      <span class="hljs-attr">fd</span>: <span class="hljs-literal">null</span>,
      <span class="hljs-attr">path</span>: <span class="hljs-string">'/tmp/d53a9fd346fcc1122e6746600'</span>,
      <span class="hljs-attr">flags</span>: <span class="hljs-string">'w'</span>,
      <span class="hljs-attr">mode</span>: <span class="hljs-number">438</span>,
      <span class="hljs-attr">start</span>: <span class="hljs-literal">undefined</span>,
      <span class="hljs-attr">pos</span>: <span class="hljs-literal">undefined</span>,
      <span class="hljs-attr">bytesWritten</span>: <span class="hljs-number">13</span>,
      <span class="hljs-attr">_writableState</span>: [WritableState],
      <span class="hljs-attr">_events</span>: [<span class="hljs-built_in">Object</span>: <span class="hljs-literal">null</span> prototype],
      <span class="hljs-attr">_eventsCount</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">_maxListeners</span>: <span class="hljs-literal">undefined</span>,
      [<span class="hljs-built_in">Symbol</span>(kFs)]: [<span class="hljs-built_in">Object</span>],
      [<span class="hljs-built_in">Symbol</span>(kIsPerformingIO)]: <span class="hljs-literal">false</span>,
      [<span class="hljs-built_in">Symbol</span>(kCapture)]: <span class="hljs-literal">false</span>
    },
    <span class="hljs-attr">hash</span>: <span class="hljs-literal">null</span>,
    [<span class="hljs-built_in">Symbol</span>(kCapture)]: <span class="hljs-literal">false</span>
  }
}
</code></pre>
<p>You’ll also notice that the <code>newFilename</code> is a hashed value. This is to ensure that if two files are uploaded with the same name, you will not lose data. You can, of course, modify how files are written to disk.</p>
<p>Note that in a standard application, it’s a good idea to store some of this information in a persistent place, like a database, so you can easily find all the files that have been uploaded. But that’s not the point of this post.</p>
<p>Now there’s one more thing I want to fix. I only want to process <code>multipart/form-data</code> requests with formidable. Everything else can be handled by a built-in body parser like the one we saw above.</p>
<p>So I’ll create a “body” variable first, then check the request headers, and assign the value of the body based on the “Content-Type”. I’ll also rename my function to <code>parseMultipartNodeRequest</code> to be more explicit about what it does.</p>
<p>Here’s what the whole thing looks like (note that <code>getRequestHeaders</code> is another built-in Nuxt function):</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> formidable <span class="hljs-keyword">from</span> <span class="hljs-string">'formidable'</span>;

<span class="hljs-comment">/**
 * @see https://nuxt.com/docs/guide/concepts/server-engine
 * @see https://github.com/unjs/h3
 */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineEventHandler(<span class="hljs-keyword">async</span> (event) =&gt; {
  <span class="hljs-keyword">let</span> body;
  <span class="hljs-keyword">const</span> headers = getRequestHeaders(event);

  <span class="hljs-keyword">if</span> (headers[<span class="hljs-string">'content-type'</span>]?.includes(<span class="hljs-string">'multipart/form-data'</span>)) {
    body = <span class="hljs-keyword">await</span> parseMultipartNodeRequest(event.node.req);
  } <span class="hljs-keyword">else</span> {
    body = <span class="hljs-keyword">await</span> readBody(event);
  }
  <span class="hljs-built_in">console</span>.log(body);

  <span class="hljs-keyword">return</span> { <span class="hljs-attr">ok</span>: <span class="hljs-literal">true</span> };
});

<span class="hljs-comment">/**
 * @param {import('http').IncomingMessage} req
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseMultipartNodeRequest</span>(<span class="hljs-params">req</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-comment">/** @see https://github.com/node-formidable/formidable/ */</span>
    <span class="hljs-keyword">const</span> form = formidable({ <span class="hljs-attr">multiples</span>: <span class="hljs-literal">true</span> })
    form.parse(req, <span class="hljs-function">(<span class="hljs-params">error, fields, files</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (error) {
        reject(error);
        <span class="hljs-keyword">return</span>;
      }
      resolve({ ...fields, ...files });
    });
  });
}
</code></pre>
<p>This way, we have an API that is robust enough to accept <code>multipart/form-data</code>, plain text, or URL-encoded requests.</p>
<h2 id="heading-finishing-up">📯📯📯 Finishing up</h2>
<p>There’s no emoji rave horn, so those will have to do. We covered kind of a lot, so let’s do a little recap.</p>
<p>When we upload a file using a <code>multipart/form-data</code> request, the browser will send the data one chunk at a time, using a stream. That’s because we can’t put the entire file in the request object at once.</p>
<p>In Node.js, we can listen to the request’s “data” event to work with each chunk of data as it arrives. This gives us access to the request stream.</p>
<p>Although we could capture all of that data and store it in memory, that’s a bad idea. A large file upload could consume all the server’s memory, causing it to crash.</p>
<p>Instead, we can pipe that stream somewhere else, so each chunk is received, processed, then released from memory. One option is to use <code>[fs.createWriteStream](https://nodejs.org/api/fs.html#fscreatewritestreampath-options)</code> to create a <code>[WritableStream](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)</code> that can write to the file system.</p>
<p>Instead of writing our own low-level parser, we should use a tool like formidable. But we need to confirm that the data is coming from a <code>multipart/form-data</code> request. Otherwise, we can use a standard body parser.</p>
<p>We covered a lot of low-level concepts, and landed on a high-level solution. Hopefully, it all made sense and you found this useful.</p>
<p>If you have any questions or if something was confusing, please go ahead and <a target="_blank" href="https://austingil.com/">reach out to me</a>. I’m always happy to help.</p>
<p>Thank you so much for reading. If you liked this article, and want to support me, the best ways to do so are to <a target="_blank" href="https://twitter.com/share?via=heyAustinGil">share it</a>, <a target="_blank" href="https://austingil.com/newsletter/">sign up for my newsletter</a>, and <a target="_blank" href="https://twitter.com/heyAustinGil">follow me on Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Deploy a NodeJS App with AWS CloudFormation ]]>
                </title>
                <description>
                    <![CDATA[ Imagine you have built a great product and its user base is growing rapidly. You want to scale your product to be available to people around the world. To do this, you'll need good cloud infrastructure. But managing your cloud infrastructure manually... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/deploy-nodejs-app-with-cloudformation/</link>
                <guid isPermaLink="false">66ba10a3052fa53219e0a372</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Infrastructure as code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Tue, 18 Apr 2023 18:03:26 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/CloudFormation.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Imagine you have built a great product and its user base is growing rapidly. You want to scale your product to be available to people around the world. To do this, you'll need good cloud infrastructure.</p>
<p>But managing your cloud infrastructure manually can be exhausting. You might start wondering, "how are the enterprise companies doing it?"</p>
<p>Well, they automate their cloud infrastructure management via code. And that's what AWS CloudFormation offers – a way to manage your cloud infrastructure as code.</p>
<p>In this tutorial, we'll explore the basics of AWS CloudFormation and how it can help you automate your cloud infrastructure management. Let's dive into the world of infrastructure as code.</p>
<h2 id="heading-what-is-cloudformation">What is CloudFormation?</h2>
<p>AWS CloudFormation is a service that helps you automate creating and managing your cloud resources. </p>
<p>Imagine you're building a house, and you want to ensure everything is in the right place – the walls, the roof, the doors, and the windows. Before you build, you would create a blueprint for your house, and specify exactly what you want and where you want it.</p>
<p>Similarly, CloudFormation allows you to create a blueprint for your cloud infrastructure. You can specify what resources you want to create (for example EC2 servers, databases, storage, and so on) and how they should be configured. CloudFormation takes care of creating and managing those resources for you automatically.</p>
<p>CloudFormation can be helpful in many cases. I'll list a few of them here:</p>
<ol>
<li>Managing the infrastructure changes in multiple environments (Development, Staging, Production)</li>
<li>Re-creating the same infrastructure in a different region / account</li>
<li>Re-creating a resource that's been accidentally deleted with the exact configuration in seconds (not manually, as you have all configurations in your code)</li>
</ol>
<p>The best part is that CloudFormation makes updating your infrastructure super simple and automatic. If you want to add a new resource, change a configuration, or delete a resource, you can update your blueprint, and CloudFormation will handle the changes for you.</p>
<h2 id="heading-how-cloudformation-works">How CloudFormation Works</h2>
<p>You may wonder how CloudFormation works. It's simple: we'll upload our CloudFormation templates in Amazon S3 (behind the scenes) which will be pulled by CloudFormation. </p>
<p>One important point to note is we cannot edit the template once uploaded. We'd need to re-upload the updated template to AWS which CloudFormation compares with the existing infrastructure and makes the necessary changes. </p>
<p>One awesome feature is that you can delete all resources created by CloudFormation in one click by deleting the stack. The CloudFormation stack is nothing but a collection of AWS resources that you can manage as a single unit. </p>
<p>You define a stack by creating a CloudFormation template that describes the resources you want to create, and run the template to create the stack. </p>
<h2 id="heading-how-to-deploy-cloudformation-templates">How to Deploy CloudFormation Templates</h2>
<p>We can deploy the CloudFormation template in two ways. One is using CloudFormation Designer and the other is writing the code in a YAML/JSON file. </p>
<p>If you're not familiar with YAML/JSON then you can go for CloudFormation Designer. This is what I'd recommended for those who don't know how to code. It allows you to create and edit templates graphically, making it easier to visualize your infrastructure and simplify the template creation process. But in this tutorial we'll be writing YAML code to deploy our app.</p>
<h2 id="heading-how-to-create-a-cloudformation-template-to-deploy-a-nodejs-app">How to Create a CloudFormation Template to Deploy a NodeJS App</h2>
<p>You can create a CloudFormation Template using either a YAML or JSON file – but we're going to use a YAML file in the tutorial. </p>
<p>In this template, we'll be creating an EC2 instance, we'll configure a Security Group for EC2, and add a script to deploy a simple NodeJS app. </p>
<h3 id="heading-cloudformation-template-to-create-an-ec2-instance">CloudFormation Template to Create an EC2 Instance</h3>
<p>There are over 224 types of resources, but we need to create an EC2 resource. <strong>Resources</strong> represent the different AWS Components that will be created and configured. We'll define the <strong>Resource</strong> type identifiers in the below format:</p>
<pre><code>AWS::aws-product-name::data-type-name
</code></pre><p>The resource format for the EC2 instance is <code>Aws::EC2::Instance</code>. To learn more about AWS resources and syntax, checkout the AWS official <a target="_blank" href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html">documentation</a> and play with it. Look at the <a target="_blank" href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html">EC2 documentation</a> to understand the declaration of EC2 instance. Both JSON and YAML syntax is available but we'll stick with YAML for this tutorial. </p>
<p>There are a lot of properties available to customize the creation of our EC2 instances. To make things simple, we'll be configuring AvailabilityZone, ImageId, and InstanceType which are basic properties needed to create an EC2 instance. </p>
<pre><code>Resources:
  SampleNodejsDeploy:
    Type: AWS::EC2::Instance
    <span class="hljs-attr">Properties</span>:
      AvailabilityZone: us-east<span class="hljs-number">-1</span>a
      <span class="hljs-attr">ImageId</span>: ami-a4c7edb2
      <span class="hljs-attr">InstanceType</span>: t2.micro
</code></pre><p>Here <code>SampleNodejsDeploy</code> refers to the name of the resource we'll be creating. You can name your resource as your wish. </p>
<p>Let's see the process to deploy the NodeJS app. </p>
<h3 id="heading-how-to-deploy-a-nodejs-app-using-a-cloudformation-template">How to Deploy a NodeJS App using a CloudFormation Template</h3>
<p>We're going to deploy the NodeJS app using the <code>UserData</code> property in the EC2 resource. </p>
<p>If you don't know about EC2 user data, it is a feature of AWS EC2 which allows us to pass information during the launch of the EC2 instance. You can use it to perform custom actions, such as installing software and executing the script. </p>
<p>Let's write the bash script to deploy the NodeJS app and attach it to the user data.</p>
<p>Here is the simple script to deploy the NodeJS app:</p>
<pre><code>#!<span class="hljs-regexp">/bin/</span>bash 
set -e
curl -sL https:<span class="hljs-comment">//deb.nodesource.com/setup_16.x | bash -</span>
sudo apt install nodejs
node -v
npm -v
curl -sS https:<span class="hljs-comment">//dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -</span>
echo <span class="hljs-string">"deb https://dl.yarnpkg.com/debian/ stable main"</span> | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update &amp;&amp; sudo apt install yarn
yarn --version
sudo -i -u ubuntu bash &lt;&lt; EOF
set -e
cd /home/ubuntu
sudo npm install -g pm2
git clone https:<span class="hljs-comment">//github.com/5minslearn/node_with_docker.git</span>
cd node_with_docker
yarn install 
pm2 start yarn --time --interpreter bash --name sample_node -- start -p <span class="hljs-number">8000</span>
EOF
</code></pre><p>The above script installs NodeJS, Yarn, and PM2. It clones a NodeJS project from <a target="_blank" href="https://github.com/5minslearn/node_with_docker.git">Git</a>, installs the dependencies, and starts the app with PM2. </p>
<p>Our next step is to attach this script to the CloudFormation template. </p>
<h3 id="heading-how-to-attach-userdata-to-the-cloudformation-template">How to Attach UserData to the CloudFormation Template</h3>
<pre><code>Resources:
  SampleNodejsDeploy:
    Type: AWS::EC2::Instance
    <span class="hljs-attr">Properties</span>:
      InstanceType: t2.micro
      <span class="hljs-attr">ImageId</span>: ami<span class="hljs-number">-014</span>d05e6b24240371
      <span class="hljs-attr">UserData</span>: 
        Fn::Base64:
          |
          #!<span class="hljs-regexp">/bin/</span>bash 
          set -e
          curl -sL https:<span class="hljs-comment">//deb.nodesource.com/setup_16.x | bash -</span>
          sudo apt install nodejs
          node -v
          npm -v
          curl -sS https:<span class="hljs-comment">//dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -</span>
          echo <span class="hljs-string">"deb https://dl.yarnpkg.com/debian/ stable main"</span> | sudo tee /etc/apt/sources.list.d/yarn.list
          sudo apt update &amp;&amp; sudo apt install yarn
          yarn --version
          sudo -i -u ubuntu bash &lt;&lt; EOF
          set -e
          cd /home/ubuntu
          sudo npm install -g pm2
          git clone https:<span class="hljs-comment">//github.com/5minslearn/node_with_docker.git</span>
          cd node_with_docker
          yarn install 
          pm2 start yarn --time --interpreter bash --name sample_node -- start -p <span class="hljs-number">8000</span>
          EOF
</code></pre><p>You'll notice that the <code>UserData</code> property is added to the EC2 block. <code>Fn::Base64</code> is a function in AWS CloudFormation that allows users to encode a string to base64 format. This function can be used to pass sensitive information, such as credentials, to AWS resources in a secure manner. Since EC2 user data is not encrypted it's always best practice to encode it. </p>
<p>Right below that line, you can see a small vertical bar (<code>|</code>). It is used for multi-line string support as our script is more than 1 line.</p>
<p>Alright. Now we have a script to deploy the NodeJS app. But, we have to remember one super important item. By default NodeJS applications run on port 8000. We should expose port 8000 from EC2. Now we need to create a security group configuration for our EC2 instance. </p>
<h3 id="heading-how-to-create-a-security-group-using-a-cloudformation-template">How to Create a Security Group using a CloudFormation Template</h3>
<p>This process is similar to creating an EC2 instance, except we'll replace the type from <code>Instance</code> to <code>SecurityGroup</code>.</p>
<pre><code>SampleNodejsDeploySG:
    Type: AWS::EC2::SecurityGroup
    <span class="hljs-attr">Properties</span>:
      GroupDescription: <span class="hljs-keyword">for</span> the app nodes that allow ssh, http, <span class="hljs-number">8000</span>
      <span class="hljs-attr">SecurityGroupIngress</span>:
      - IpProtocol: tcp
        <span class="hljs-attr">FromPort</span>: <span class="hljs-string">'80'</span>
        <span class="hljs-attr">ToPort</span>: <span class="hljs-string">'80'</span>
        <span class="hljs-attr">CidrIp</span>: <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>/<span class="hljs-number">0</span>
      - IpProtocol: tcp
        <span class="hljs-attr">FromPort</span>: <span class="hljs-string">'22'</span>
        <span class="hljs-attr">ToPort</span>: <span class="hljs-string">'22'</span>
        <span class="hljs-attr">CidrIp</span>: <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>/<span class="hljs-number">0</span>
      - IpProtocol: tcp
        <span class="hljs-attr">FromPort</span>: <span class="hljs-string">'8000'</span>
        <span class="hljs-attr">ToPort</span>: <span class="hljs-string">'8000'</span>
        <span class="hljs-attr">CidrIp</span>: <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>/<span class="hljs-number">0</span>
</code></pre><p>The above code should be pretty self explanatory – we defined a Security group, allowing ports 22 (SSH port), 80 (HTTP port), and 8000 (NodeJS). We named the Resource as <code>SampleNodejsDeploySG</code>. </p>
<h3 id="heading-how-to-attach-the-security-group-to-ec2">How to Attach the Security Group to EC2</h3>
<p>You may be wondering – "We've created a template for creating a Security group but how will this be linked to the EC2 instance?"</p>
<p>The solution is simple. CloudFormation provides an intrinsic function called <code>!Ref</code> that allows us to reference a resource or parameter within a CloudFormation template.</p>
<pre><code>Resources:
  SampleNodejsDeploy:
    Type: AWS::EC2::Instance
    <span class="hljs-attr">Properties</span>:
      InstanceType: t2.micro
      <span class="hljs-attr">ImageId</span>: ami<span class="hljs-number">-014</span>d05e6b24240371
      <span class="hljs-attr">SecurityGroups</span>:
        - !Ref SampleNodejsDeploySG
      <span class="hljs-attr">UserData</span>: 
        Fn::Base64:
          |
          #!<span class="hljs-regexp">/bin/</span>bash 
          set -e
          curl -sL https:<span class="hljs-comment">//deb.nodesource.com/setup_16.x | bash -</span>
          sudo apt install nodejs
          node -v
          npm -v
          curl -sS https:<span class="hljs-comment">//dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -</span>
          echo <span class="hljs-string">"deb https://dl.yarnpkg.com/debian/ stable main"</span> | sudo tee /etc/apt/sources.list.d/yarn.list
          sudo apt update &amp;&amp; sudo apt install yarn
          yarn --version
          sudo -i -u ubuntu bash &lt;&lt; EOF
          set -e
          cd /home/ubuntu
          sudo npm install -g pm2
          git clone https:<span class="hljs-comment">//github.com/5minslearn/node_with_docker.git</span>
          cd node_with_docker
          yarn install 
          pm2 start yarn --time --interpreter bash --name sample_node -- start -p <span class="hljs-number">8000</span>
          EOF

  <span class="hljs-attr">SampleNodejsDeploySG</span>:
    Type: AWS::EC2::SecurityGroup
    <span class="hljs-attr">Properties</span>:
      GroupDescription: <span class="hljs-keyword">for</span> the app nodes that allow ssh, http 
      <span class="hljs-attr">SecurityGroupIngress</span>:
      - IpProtocol: tcp
        <span class="hljs-attr">FromPort</span>: <span class="hljs-string">'80'</span>
        <span class="hljs-attr">ToPort</span>: <span class="hljs-string">'80'</span>
        <span class="hljs-attr">CidrIp</span>: <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>/<span class="hljs-number">0</span>
      - IpProtocol: tcp
        <span class="hljs-attr">FromPort</span>: <span class="hljs-string">'22'</span>
        <span class="hljs-attr">ToPort</span>: <span class="hljs-string">'22'</span>
        <span class="hljs-attr">CidrIp</span>: <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>/<span class="hljs-number">0</span>
      - IpProtocol: tcp
        <span class="hljs-attr">FromPort</span>: <span class="hljs-string">'8000'</span>
        <span class="hljs-attr">ToPort</span>: <span class="hljs-string">'8000'</span>
        <span class="hljs-attr">CidrIp</span>: <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>/<span class="hljs-number">0</span>
</code></pre><p>You can see that the <code>SecurityGroups</code> property is added to the EC2 instance and the created Security Group configuration is linked to the EC2 instance by using the <code>!Ref</code> parameter. </p>
<p>Now we have the CloudFormation template. But we're not yet finished. We're still missing one more thing. Can you figure it out? We created an EC2 instance, and we allowed an SSH port...but to log in using SSH we need to attach a key-value pair, right? Let's do that. </p>
<p>We can attach the key-value pair name directly to the template. For example, let's assume your key-value pair name is <code>5minslearn</code> you can attach the property <code>KeyName</code> directly to the EC2 resource block like what's shown below or we can pass it in via parameters. </p>
<pre><code>Resources:
  SampleNodejsDeploy:
    Type: AWS::EC2::Instance
    <span class="hljs-attr">Properties</span>:
      InstanceType: t2.micro
      <span class="hljs-attr">ImageId</span>: ami<span class="hljs-number">-014</span>d05e6b24240371
      <span class="hljs-attr">KeyName</span>: <span class="hljs-number">5</span>minslearn
      <span class="hljs-attr">SecurityGroups</span>:
        - !Ref SampleNodejsDeploySG
</code></pre><h3 id="heading-how-to-use-parameters-in-the-cloudformation-template">How to use parameters in the CloudFormation template</h3>
<p>We can use parameters to get the name of the key-value pair from the user while creating the stack. Basically, parameters allow us to pass input values into CloudFormation templates at runtime. Let's see how to do that. </p>
<pre><code>Parameters:
  SSHKey:
    Type: AWS::EC2::KeyPair::KeyName
    <span class="hljs-attr">Description</span>: name <span class="hljs-keyword">of</span> the key pair to ssh into the instance
<span class="hljs-attr">Resources</span>:
  SampleNodejsDeploy:
    Type: AWS::EC2::Instance
    <span class="hljs-attr">Properties</span>:
      InstanceType: t2.micro
      <span class="hljs-attr">ImageId</span>: ami<span class="hljs-number">-014</span>d05e6b24240371
      <span class="hljs-attr">KeyName</span>: !Ref SSHKey
      <span class="hljs-attr">SecurityGroups</span>:
        - !Ref SampleNodejsDeploySG
      <span class="hljs-attr">UserData</span>: 
        Fn::Base64:
          |
          #!<span class="hljs-regexp">/bin/</span>bash 
          set -e
          curl -sL https:<span class="hljs-comment">//deb.nodesource.com/setup_16.x | bash -</span>
          sudo apt install nodejs
          node -v
          npm -v
          curl -sS https:<span class="hljs-comment">//dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -</span>
          echo <span class="hljs-string">"deb https://dl.yarnpkg.com/debian/ stable main"</span> | sudo tee /etc/apt/sources.list.d/yarn.list
          sudo apt update &amp;&amp; sudo apt install yarn
          yarn --version
          sudo -i -u ubuntu bash &lt;&lt; EOF
          set -e
          cd /home/ubuntu
          sudo npm install -g pm2
          git clone https:<span class="hljs-comment">//github.com/5minslearn/node_with_docker.git</span>
          cd node_with_docker
          yarn install 
          pm2 start yarn --time --interpreter bash --name sample_node -- start -p <span class="hljs-number">8000</span>
          EOF

  <span class="hljs-attr">SampleNodejsDeploySG</span>:
    Type: AWS::EC2::SecurityGroup
    <span class="hljs-attr">Properties</span>:
      GroupDescription: <span class="hljs-keyword">for</span> the app nodes that allow ssh, http 
      <span class="hljs-attr">SecurityGroupIngress</span>:
      - IpProtocol: tcp
        <span class="hljs-attr">FromPort</span>: <span class="hljs-string">'80'</span>
        <span class="hljs-attr">ToPort</span>: <span class="hljs-string">'80'</span>
        <span class="hljs-attr">CidrIp</span>: <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>/<span class="hljs-number">0</span>
      - IpProtocol: tcp
        <span class="hljs-attr">FromPort</span>: <span class="hljs-string">'22'</span>
        <span class="hljs-attr">ToPort</span>: <span class="hljs-string">'22'</span>
        <span class="hljs-attr">CidrIp</span>: <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>/<span class="hljs-number">0</span>
      - IpProtocol: tcp
        <span class="hljs-attr">FromPort</span>: <span class="hljs-string">'8000'</span>
        <span class="hljs-attr">ToPort</span>: <span class="hljs-string">'8000'</span>
        <span class="hljs-attr">CidrIp</span>: <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>/<span class="hljs-number">0</span>
</code></pre><p>In the above template, we added a parameter to get the key pair name and referenced it to <code>KeyName</code> property. </p>
<p>Great! We successfully created a CloudFormation template to create an EC2 instance and security group. In addition to that, we also added a script to deploy the NodeJS app. Now it's time to create a CloudFormation stack.</p>
<h2 id="heading-how-to-create-a-cloudformation-stack">How to Create a CloudFormation Stack</h2>
<p>The first step is to log in to the AWS console and search for CloudFormation in the search bar (see the below screenshot). Click on stacks in the left sidebar to get started with CloudFormation. </p>
<p><img src="https://lh6.googleusercontent.com/tIzQQwxjsDLgPxI65f8l9jcAtw90UVVCRakld4M9h8ZUJrMvMhPVxPuSHm_Pdr-UZO1YPeAFTSP_6CU9fNx7a99Hjp04LnhkmmzG9ZdhEvi-o9mqil-vr6yKFYkdDv21AK1s13rKAVQue6l09MOFEpU" alt="Image" width="600" height="400" loading="lazy">
<em>CloudFormation Getting Started</em></p>
<p>Click on the create stack button to create the CloudFormation stack.</p>
<p><img src="https://lh4.googleusercontent.com/64WKWRSq7334K9DEXzOmuE_u-sDWUcSO3ZqpAhhJqFOnLC0Alp7NbP38PWjB0fj_qZw5sookagPnANLkJfjVASZrCwF4OODljGNdLdMKeaSrQfGg7BiyHmopUWBEQcIh1JuRWHZlvYgnFqxzyfTACpo" alt="Image" width="600" height="400" loading="lazy">
<em>Create CloudFormation Stack</em></p>
<p>As we have our template ready, select "Template is ready" and choose "Upload a template file" in the Template source section, and upload the template file.</p>
<p><img src="https://lh5.googleusercontent.com/KsaSLPVYV3UbphozR2kSzWR9ICXWnW1O6w2H5ooT_AmfxWknCCkfZ3km3fT2nscCsekhxgz6zrcphBY5l8olGTzPX5ZcmxoAwGFXPg92B4W9N1BVbUwUGdLq43gfD1FGIdj9O60vpO25wI9-3DJvBok" alt="Image" width="600" height="400" loading="lazy">
<em>Deploying CloudFormation Template</em></p>
<p>Once you upload the file, the "View in Designer" button will be enabled. Click on it to view your template design.</p>
<h2 id="heading-how-to-validate-the-cloudformation-template">How to Validate the CloudFormation Template</h2>
<p><img src="https://lh3.googleusercontent.com/Ddg61T-pDsR33QjMFGyVk7sIhDDs7qQ9nVQd6P1vOn5RY7DtlquWnEWFrzmDHH_4Ny78jzuAlmOg49ONtKw0XcxcDDjJtAqAEALC3RNsSuhwuFgkgQz_UzldzSHwPfwoGhEAnwALs8jlcq9_FyKUglU" alt="Image" width="600" height="400" loading="lazy">
<em>Validate CloudFormation Template</em></p>
<p>To validate our template click on the "Tick" icon on top left in the designer. It will validate and show us errors if any. Once the validation is done, click on the "Cloud" icon to the left of "Tick" icon. It will take you to the create stack page.</p>
<p>In the stack details page, enter the stack name and select your key-value pair. If you don't have key-value pair, create one and select it.</p>
<p><img src="https://lh4.googleusercontent.com/o9myUy3ijGaRzsqsISNq0eoMB6_JyvmJyF2JiwkKxbCoDPFKPTOHSiC5I5ioZP1CXQAyraUYLT72u17sKtZfIaRyHWnJLojFqumkaeEXeFXhMwBL1-rnmvZOSpemDDZ-axzGtxmfYAm0RQi1Pf7VUu8" alt="Image" width="600" height="400" loading="lazy">
<em>Specify CloudFormation stack details</em></p>
<p>Leave the Configure stack options section as it is, and click continue since we don't need any IAM permissions or advanced options.</p>
<p>Finally, review the page and submit the template. The template will start creating the resources. </p>
<p><img src="https://lh4.googleusercontent.com/wsD_CWoQk3P90rku7vPiC0uozKlj6fwYdmoZfP3SggCDOwLs5g1hshhK3crKMoDkvvTILf8206AktFBDQ1IeVDAPQ5ksPmYDAhu7v2h7R9Rg7mb9qSETOYQHhEoXNvOFyTD8sgf_AbHGO7MaGTNIjIE" alt="Image" width="600" height="400" loading="lazy">
<em>CloudFormation stack creating resources</em></p>
<p>Once that's done, click on the resources tab. You'll be able to see the resources we created (EC2 and Security group resources).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Resources created by CloudFormation Template</em></p>
<p>Click on the EC2 instance, and you can see that our instance will be up and running. Copy the public IPv4 address. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/2.png" alt="Image" width="600" height="400" loading="lazy">
<em>EC2 instance up and running</em></p>
<p>Open your browser and hit <code>http://&lt;ip_address&gt;:8000</code> (In my case it is <code>http://54.176.19.18:8000/</code>). You should be able to see a page similar to the one below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Screenshot-from-2023-04-14-02-35-22.png" alt="Image" width="600" height="400" loading="lazy">
<em>NodeJS app running</em></p>
<p>This represents that our NodeJS app is successfully deployed! </p>
<p><strong>Note:</strong> EC2 user data will take some time to install dependencies. So for the first time, the page will take long time to load. Just be patient until the site is loaded. </p>
<h2 id="heading-how-to-delete-the-cloudformation-stack">How to Delete the CloudFormation Stack</h2>
<p>If you no longer need the stack, you can delete it from the CloudFormation console. </p>
<p>Select the stack you want to delete, click "Delete Stack," and confirm the action. This action will delete all resources created using this stack. In our case, it'll delete both EC2 and Security Group. You don't need to delete the EC2 instance and Security Group individually.</p>
<p><img src="https://lh5.googleusercontent.com/qIonqqdC9U22tCeGsJXtcLG6U5LaiCnbNATAzNBKA8bKXttf9GLhHRMa28F9oMYE_W1OjeoPCdrDnlUk569rwnPlMFgcVKjLOc-oKYQxHYKA_SkrzI4UBjgTlf5gCrGukTTDuXR61pa8I5OWDMSd5Gg" alt="Image" width="600" height="400" loading="lazy">
<em>Deleting CloudFormation stack</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we learned about CloudFormation, how it works, and how to create and delete a template stack. </p>
<p>Hope you enjoyed reading this article! If you are stuck at any point feel free to drop your queries to me at my <a target="_blank" href="mailto:arun@gogosoon.com">email</a>. I’ll be happy to help you.</p>
<p>If you wish to learn more about AWS, subscribe to my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_cloud_formation">newsletter</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_cloud_formation">https://5minslearn.gogosoon.com/</a>) and follow me on social media. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Get Started with Docker using NodeJS ]]>
                </title>
                <description>
                    <![CDATA[ You might have seen a tool with the logo of a whale lifting some square containers. Yes, I am talking about Docker.  The Docker logo actually symbolizes software that brings together a huge amount of organized information, hinting at its convenience.... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-get-started-with-docker-using-nodejs/</link>
                <guid isPermaLink="false">66ba10c1256f04965e2bd0de</guid>
                
                    <category>
                        <![CDATA[ container ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Mon, 20 Mar 2023 14:28:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/How-to-get-started-with-Docker-using-NodeJS.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>You might have seen a tool with the logo of a whale lifting some square containers. Yes, I am talking about Docker. </p>
<p>The Docker logo actually symbolizes software that brings together a huge amount of organized information, hinting at its convenience.</p>
<p>Many enterprise applications use Docker-based deployments (also called containerized deployments) these days. So it's a good skill to have as a developer.</p>
<p>This tutorial will be the best fit for those who know nothing apart from the term "Docker".</p>
<p>In this article, you'll learn about the fundamentals of Docker, build your own Docker image, and publish it to the Docker Hub.</p>
<h2 id="heading-why-do-you-need-docker">Why Do You Need Docker?</h2>
<p>Let's understand why we need Docker with a simple example.</p>
<p>Let's assume you're joining a new company and you have been assigned to an extremely huge project to work on. You received a brand new laptop and are ready to put on your development shoes. </p>
<p>The first step whenever you are onboarded into a project is to set up the development environment. Since it's a huge enterprise project, it consumes a bunch of time to set up the development environment. You may need to install project-specific dependencies, tools, and many more. </p>
<p>In the middle, you may face errors that you can mostly solve by following the README guide, but a couple of them might happen for the first time (might happen due to laptop configuration) and you have to solve them on your own.</p>
<p>Imagine if you have to follow the same process for large teams with tons of members. It would be horrible to handle right?</p>
<p>This is where Docker comes in really handy. Docker will create containerized applications that run on any type of environment that have all the dependencies within it. So setting up the development environment is just one command away. Docker has many use cases – this scenario is just one of them.</p>
<p>By using Docker we can standardize application operations, ship code faster, and seamlessly deploy to production.</p>
<h2 id="heading-how-does-docker-work">How Does Docker Work?</h2>
<p>Docker provides a standardized way to develop, test, and deploy code.</p>
<p>You can think about Docker as a super-powered advanced virtual machine. Let’s learn more about it with an example.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-171.png" alt="Image" width="600" height="400" loading="lazy">
<em>Comparison between Virtual Machine and Docker</em></p>
<p>Before getting started to work on Docker, we should understand some fundamentals of how it works. They are:</p>
<ol>
<li>Docker Engine</li>
<li>Docker Container</li>
<li>Docker Image</li>
</ol>
<h3 id="heading-what-is-docker-engine">What is Docker Engine?</h3>
<p>The Docker engine is an open-source containerization technology you can use to build a containerizing application. W</p>
<p>e can use the Docker engine on a variety of platforms through Docker Desktop or Binary Installation. To simplify, the software that hosts the containers is called Docker Engine.</p>
<h3 id="heading-what-is-a-docker-container">What is a Docker Container?</h3>
<p>A container is a standard unit of software that packages up the code and all required dependencies needed to run an application on different platforms or computing environments.</p>
<p>Containers are fully isolated from the computing environment, so applications run quickly and reliably from one computing environment to another.</p>
<p>Docker containers are built from container images.</p>
<h3 id="heading-what-is-a-docker-image">What is a Docker image?</h3>
<p>A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application. It includes code, runtime, system tools, system libraries, and settings.</p>
<p>As we discussed, containers are built from images. Images become containers when they starts running on a Docker Engine.</p>
<h3 id="heading-use-cases-for-docker">Use Cases for Docker</h3>
<p>Docker gives you the ability to run an application in any type of environment which is completely isolated from the current environment. This isolated environment is called a container. </p>
<p>This isolation and security allow us to run as many containers as we want in a host. Docker helps developers to work in a standardized environment using local containers which provide all the packages and dependencies to run an application.</p>
<p>Let's see a few use cases of Docker:</p>
<ol>
<li>Developers can write code locally and share their work using Docker containers</li>
<li>You can use Docker to deploy your applications into a test/production environment and execute automated and manual tests</li>
<li>When developers need to fix something, they can easily make the changes and push the Docker image to the testing or production environment</li>
</ol>
<p>Just like Git, we can use Docker when we're making changes to our projects. If we make any changes we can just push the Docker images and pull them into the host machine. No more changes need to be done in the host server.</p>
<p>Here are the deployment steps you'd go through if you're not using Docker:</p>
<ol>
<li>Pull/clone the code from Git</li>
<li>Install dependencies, run migrations, and so on in the host machine.</li>
<li>Start the application</li>
</ol>
<p>These steps have to be repeated on every server whether it is a testing or production environment.</p>
<p>Here is the deployment steps using Docker:</p>
<ol>
<li>Pull the docker image (<code>docker pull</code>)</li>
<li>Run the container in the host machine (<code>docker run</code>)</li>
</ol>
<h3 id="heading-what-is-docker-hub">What is Docker Hub?</h3>
<p>Docker Hub is the largest community for Docker images. It allows you to share the container images among your team, or the Docker community. Docker Hub is sort of like GitHub. Here, Docker images reside instead of the project's code.</p>
<p>You can pull the open-source Docker images also. To use this you have to create an account in Docker <a target="_blank" href="https://hub.docker.com">hub</a>.</p>
<p>Now that you know a bit about how Docker works and why it's useful, let's learn how to containerize an application.</p>
<h2 id="heading-how-to-containerize-a-nodejs-application-using-docker"><strong>How to Containerize a NodeJS Application using Docker</strong></h2>
<h3 id="heading-prerequisites">Prerequisites:</h3>
<ol>
<li>A Basic understanding of NodeJS Applications</li>
<li>Docker desktop application</li>
</ol>
<p>You can install the Docker Desktop application by following their original <a target="_blank" href="https://docs.docker.com/desktop/install/windows-install/">documentation</a>.</p>
<p>You can verify if Docker is installed on your machine by querying it's version like this:</p>
<pre><code class="lang-bash">docker -v
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-172.png" alt="Image" width="600" height="400" loading="lazy">
<em>Find Docker Version</em></p>
<p>Let's start our implementation.</p>
<p>Instead of starting over from scratch, I have created a super simple Express API that exposes only one endpoint. I pushed the code to a public repo on GitHub. You can clone the repo by running the below command:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/5minslearn/node_with_docker.git
</code></pre>
<p>This is the project's structure:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-168.png" alt="Image" width="600" height="400" loading="lazy">
<em>Simple NodeJS Project Structure</em></p>
<p>I have created only one endpoint ("/") and calling it will return "Greeting from 5minslearn". I've simplified this as much as possible to allow us to focus more on Docker.</p>
<h2 id="heading-how-to-create-a-dockerfile">How to Create a Dockerfile</h2>
<p>Now, you'll need to create a file named "Dockerfile" in the root directory. It is the default file name for the Docker engine. Paste the following code into the file:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> node:latest
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . /app</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">8000</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"npm"</span>,<span class="hljs-string">"start"</span>]</span>
</code></pre>
<p>Let's understand these commands line by line.</p>
<p>Defining the parent image is the first step of Docker engine. You have to define the parent image from which you're building the project. In our case it's Node. </p>
<p>There are a lot of parent images available in Docker Hub. You have to define the Image Variant next to the parent image. I always prefer to use the latest node image.</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> node:latest
</code></pre>
<p>The second step is to define the working directory in Docker. Let's define our working directory as the <code>app</code> directory.</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
</code></pre>
<p>Copy the project to the <code>app</code> directory. Make sure you exclude the <code>node_modules</code> directory. We will see how to ignore files/folders in the upcoming steps.</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">COPY</span><span class="bash"> . /app</span>
</code></pre>
<p>In the above command, the <code>.</code> indicates that all the files and directories are to be copied to the <code>app</code> folder.</p>
<p>The next step is to install the required dependencies with this command:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">RUN</span><span class="bash"> npm install</span>
</code></pre>
<p>RUN is an image build step. The state of the container after a RUN command will be committed to the container image. A Dockerfile can have many RUN steps that can layer on top of one another to build the image.</p>
<p>Expose the port in which application should run.</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">8000</span>
</code></pre>
<p>The EXPOSE instruction informs Docker that the container listens on the specified network ports at runtime.</p>
<p>Finally run the execution command:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">CMD</span><span class="bash"> ts-node src/index.ts</span>
</code></pre>
<p>CMD is the command the container executes by default when we launch the built image.</p>
<p><strong>Tip:</strong> I recommend that you install the <code>Docker</code> extension if you're using VS Code. It'll help you with its solid suggestions.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-174.png" alt="Image" width="600" height="400" loading="lazy">
<em>VS Code <code>Docker</code> extension</em></p>
<h2 id="heading-how-to-ignore-files-so-theyre-not-copied-into-the-docker-container">How to Ignore Files So They're Not Copied into the Docker Container</h2>
<p>You have to exclude the unwanted files from being copied into the container. The <code>.dockerignore</code> file helps you with that. It works like <code>.gitignore</code> for Git.</p>
<p>You can define all the files you have to ignore and don't want to copy.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-169.png" alt="Image" width="600" height="400" loading="lazy">
<em>Using <code>.dockerignore</code> to exclude the unwanted files from being copied to the container</em></p>
<p>Great! You've completed the Docker configuration. Let's run the application.</p>
<h2 id="heading-how-to-build-docker-images">How to Build Docker Images</h2>
<p>You can build a Docker image by running the <code>docker build</code> command. Here's the syntax for it:</p>
<pre><code class="lang-bash">docker build -t image_name:version_number .
</code></pre>
<p><code>image_name</code> indicates the container image name and <code>version_number</code> indicates the image version. Did you notice the dot (<code>.</code>) at the end of the command? It indicates that the Docker image should be built from the current directory.</p>
<p>I decided to set the image name as <code>node_with_docker</code>. Remember that the image name has to be prefixed with the Docker hub username. I've created my Docker hub account with the <code>aanandggs</code> username. So, my image name is <code>aanandggs/node_with_docker</code>. You may choose to enter whatever you want. </p>
<pre><code class="lang-bash">docker build -t aanandggs/node_with_docker:0.0.1 .
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-175.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sample output of building docker image</em></p>
<p>Once you've built your Docker image, you'll be able to see it on your Docker Desktop.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-178.png" alt="Image" width="600" height="400" loading="lazy">
<em>Docker Image in Docker Desktop</em></p>
<h2 id="heading-how-to-run-the-docker-image">How to Run the Docker Image</h2>
<p>After we build the Docker image, the next step is to run it. When an image starts running on a Docker Engine, it'll become a container.</p>
<p>Let's run our image which we built in the previous step:</p>
<pre><code class="lang-bash">docker container run -d --name &lt;name_of_app&gt; -p &lt;local_port&gt;:&lt;docker_port&gt; &lt;image_name&gt;:&lt;version&gt;
</code></pre>
<pre><code class="lang-bash">docker container run -d --name docker_with_node -p 8000:8000 aanandggs/node_with_docker:0.0.1
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-179.png" alt="Image" width="600" height="400" loading="lazy">
<em>Docker Command to create and run a container</em></p>
<p>Let's understand the above command.</p>
<p>We use the <code>docker container run</code> command to create and run a new container from an image.</p>
<p>The <code>-d</code> flag instructs the container to run in the background (detach). It prints the container id.</p>
<p>The <code>--name</code> parameter gives a name to our container.</p>
<p>We use the <code>-p</code> parameter to publish a container’s port to the host. It'll bind the port <code>8000</code> of your local machine with the port <code>8000</code> of the Docker container.</p>
<p><code>image_name:version</code> indicates the image and its version that this container should run.</p>
<p>You can have a look at the running containers in the Docker Desktop app.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-180.png" alt="Image" width="600" height="400" loading="lazy">
<em>Running Container in Docker Desktop</em></p>
<p>The Dashboard shows that our app is running. Let's check the output on the browser by trying to access the "/" endpoint. Hit <code>locahost:8000/</code> on your browser. You should see a message similar to the one in the below screenshot:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-181.png" alt="Image" width="600" height="400" loading="lazy">
<em>NodeJS App running output</em></p>
<p>You have successfully run an app with a Docker container.</p>
<p><strong>Note:</strong> You can bind any local port to the Docker port. Ensure your local port is not used by any other process.</p>
<h2 id="heading-how-to-push-the-image-to-the-docker-hub">How to Push the Image to the Docker Hub</h2>
<p>Create your profile on Docker Hub. Come back to terminal and run the below command to login to Docker CLI:</p>
<pre><code class="lang-bash">docker login
</code></pre>
<p>If you face any issues with login, follow this <a target="_blank" href="https://docs.docker.com/desktop/get-started/#credentials-management-for-linux-users">doc</a> to login to the Dockerhub on your machine.</p>
<p>After a successful login, you can push the image to Docker hub.</p>
<pre><code class="lang-bash">docker push &lt;docker_image&gt;:&lt;image_version&gt;
</code></pre>
<pre><code class="lang-bash">docker push aanandggs/node_with_docker:0.0.1
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-182.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sample output of pushing image to docker</em></p>
<p>Hurray! Docker images are uploaded to Docker hub.</p>
<p>You'll be able to see them in the Docker hub console.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-184.png" alt="Image" width="600" height="400" loading="lazy">
<em>Pushed Docker image in DockerHub</em></p>
<p>Since our image is public, anyone on the internet can pull the image and run it on their machines without any third-party installation.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we have learnt the very basics of Docker. Docker is an ocean of information. To fully learn it, you'll need to do more than just reading – you'll need to practice working with it.</p>
<p>Hope you folks enjoyed reading this one. Will see you in another interesting tutorial. Feel free to reach out to me on LinkedIn if you have any queries. </p>
<p>To learn more about Docker, subscribe to my email newsletter on my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_docker_getting_started">site</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_docker_getting_started">https://5minslearn.gogosoon.com</a>) and follow me on social media. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ MERN App Development – How to Build a CI/CD Pipeline with Jenkins ]]>
                </title>
                <description>
                    <![CDATA[ By Rakesh Potnuru As you continue to develop your software, you must also continue to integrate it with previous code and deploy it to servers.  Manually doing this is a time-consuming process that can occasionally result in errors. So we need to do ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/automate-mern-app-deployment-with-jenkins/</link>
                <guid isPermaLink="false">66d460c5d14641365a05095d</guid>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Continuous Integration ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Jenkins ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongo ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 08 Mar 2023 17:42:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/CICD-Pipeline-with-Jenkins.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rakesh Potnuru</p>
<p>As you continue to develop your software, you must also continue to integrate it with previous code and deploy it to servers. </p>
<p>Manually doing this is a time-consuming process that can occasionally result in errors. So we need to do this in a continuous and automated manner – which is what you will learn in this article.</p>
<p>We'll go over how you can improve your MERN (MongoDB, Express, React, and NodeJs) app development process by setting up a CI/CD pipeline with Jenkins. You'll see how to automate deployment for faster, more efficient releases.</p>
<h2 id="heading-lets-get-started">Let's Get Started</h2>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Basic understanding of MERN stack technologies.</li>
<li>Basic understanding of Docker.</li>
<li>Get source code from <a target="_blank" href="https://github.com/itsrakeshhq/productivity-app">GitHub</a></li>
</ul>
<h2 id="heading-the-problem">The Problem</h2>
<p>Consider this <a target="_blank" href="https://github.com/itsrakeshhq/productivity-app">productivity app</a> – it's a MERN project that we are going to use in this article. There are numerous steps we must complete, from building the application to pushing it to the Docker hub. </p>
<p>First, we must run tests with a command to determine whether all tests pass or not. If all tests pass, we build the Docker images and then push those images to Docker Hub. If your application is extremely complex, you may need to take additional steps. </p>
<p>Now, imagine that we're doing everything manually, which takes time and can lead to mistakes.</p>
<p><img src="https://i.imgur.com/iWAmMm4.jpg" alt="Waiting for deployment without devops meme" width="1600" height="840" loading="lazy">
<em>Waiting for deployment without devops meme</em></p>
<h2 id="heading-the-solution">The Solution</h2>
<p>To address this problem, we can create a CI/CD <strong>Pipeline</strong>. So, whenever you add a feature or fix a bug, this pipeline gets triggered. This automatically performs all of the steps from testing to deploying.</p>
<h2 id="heading-what-is-cicd-and-why-is-it-important">What is CI/CD and Why is it Important?</h2>
<p><strong>C</strong>ontinuous <strong>I</strong>ntegration and <strong>C</strong>ontinuous <strong>D</strong>eployment is a series of steps performed to automate software integration and deployment. CI/CD is the heart of DevOps.</p>
<p><img src="https://i.imgur.com/uMFtPwJ.png" alt="ci cd steps" width="1920" height="1080" loading="lazy">
<em>CI/CD steps</em></p>
<p>From development to deployment, our MERN app goes through four major stages: testing, building Docker images, pushing to a registry, and deploying to a cloud provider. All of this is done manually by running various commands. And we need to do this every time a new feature is added or a bug is fixed. </p>
<p>But this will significantly reduce developer productivity, which is why CI/CD can be so helpful in automating this process. In this article, we will cover the steps up until pushing to the registry.</p>
<p><img src="https://i.imgur.com/g2omESy.png" alt="ci cd meme" width="1600" height="840" loading="lazy">
<em>CI/CD meme</em></p>
<h2 id="heading-the-project">The Project</h2>
<p>The project we are going to use in this tutorial is a very simple full-stack MERN application.</p>
<p><img src="https://i.imgur.com/GSvRlQ0.gif" alt="project demo" width="600" height="338" loading="lazy">
<em>Project demo</em></p>
<p>It contains two microservices.</p>
<ol>
<li>Frontend</li>
<li>Backend</li>
</ol>
<p>You can learn more about the project <a target="_blank" href="https://blog.itsrakesh.co/lets-build-and-deploy-a-full-stack-mern-web-application">here</a>.</p>
<p>Both of these applications contains a Dockerfile. You can learn how to dockerize a MERN application <a target="_blank" href="https://blog.itsrakesh.co/dockerizing-your-mern-stack-app-a-step-by-step-guide">here</a>.</p>
<h2 id="heading-what-is-jenkins">What is Jenkins?</h2>
<p>To run a CI/CD pipeline, we need a CI/CD server. This is where all of the steps written in a pipeline run. </p>
<p>There are numerous services available on the market, including GitHub Actions, Travis CI, Circle CI, GitLab CI/CD, AWS CodePipeline, Azure DevOps, and Google Cloud Build. Jenkins is one of the popular CI/CD tools, and it's what we'll use here.</p>
<h2 id="heading-how-to-set-up-jenkins-server-on-azure">How to Set Up Jenkins Server on Azure</h2>
<p>Because Jenkins is open source and it doesn't provide a cloud solution, we must either run it locally or self-host on a cloud provider. Now, running locally can be difficult, particularly for Windows users. As a result, I've chosen to self-host it on Azure for this demo.</p>
<p>If you want to run locally or self-host somewhere other than Azure (follow <a target="_blank" href="https://www.jenkins.io/doc/book/installing/">these</a> guides by Jenkins), skip this section and proceed to the <strong>How to Configure Jenkins</strong> section.</p>
<p>First, you'll need to sign in to your <a target="_blank" href="https://Azure.microsoft.com?wt.mc_id=studentamb_90351">Azure</a> account (Create one if you don't have one already). Open Azure Cloud Shell.</p>
<p><img src="https://i.imgur.com/IN6RXAe.png" alt="opening azure cloud shell" width="2120" height="467" loading="lazy">
<em>Opening Azure Cloud Shell</em></p>
<p>Then create a directory called <code>jenkins</code> to store all the Jenkins config, and switch to that directory:</p>
<pre><code class="lang-bash">mkdir jenkins
<span class="hljs-built_in">cd</span> jenkins
</code></pre>
<p>Create a file called <code>cloud-init-jenkins.txt</code>. Open with nano or vim,</p>
<pre><code class="lang-bash">touch cloud-init-jenkins.txt
nano cloud-init-jenkins.txt
</code></pre>
<p>and paste this code into it:</p>
<pre><code class="lang-bash"><span class="hljs-comment">#cloud-config</span>
package_upgrade: <span class="hljs-literal">true</span>
runcmd:
  - sudo apt install openjdk-11-jre -y
  - wget -qO - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -
  - sh -c <span class="hljs-string">'echo deb https://pkg.jenkins.io/debian-stable binary/ &gt; /etc/apt/sources.list.d/jenkins.list'</span>
  - sudo apt-get update &amp;&amp; sudo apt-get install jenkins -y
  - sudo service jenkins restart
</code></pre>
<p>Here, we'll use this file to install Jenkins after creating a virtual machine. First, we install openjdk, which is required for Jenkins to function. The Jenkins service is then restarted after we install it.</p>
<p>Next, create a resource group. (A resource group in Azure is like a container that holds all the related resources of a project in one group. Learn more about resource groups <a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal#what-is-a-resource-group?wt.mc_id=studentamb_90351">here</a>.)</p>
<pre><code class="lang-bash">az group create --name jenkins-rg --location centralindia
</code></pre>
<p><strong>Note:</strong> make sure to change the location to the one closest to you.</p>
<p>Now, create a virtual machine.</p>
<pre><code class="lang-bash">az vm create \
--resource-group jenkins-rg \
--name jenkins-vm \
--image UbuntuLTS \
--admin-username <span class="hljs-string">"azureuser"</span> \
--generate-ssh-keys \
--public-ip-sku Standard \
--custom-data cloud-init-jenkins.txt
</code></pre>
<p>You can verify the VM installation with this command:</p>
<pre><code class="lang-bash">az vm list -d -o table --query <span class="hljs-string">"[?name=='jenkins-vm']"</span>
</code></pre>
<p>Don't be confused. This command simply displays JSON data in a tabular format for easy verification.</p>
<p>Jenkins server runs on port <code>8080</code>, so we need to expose this port on our VM. You can do that like this:</p>
<pre><code class="lang-bash">az vm open-port \
--resource-group jenkins-rg \
--name jenkins-vm  \
--port 8080 --priority 1010
</code></pre>
<p>Now we can access the Jenkins dashboard in the browser with the URL <code>http://&lt;your-vm-ip&gt;:8080</code>. Use this command to get the VM IP address:</p>
<pre><code class="lang-bash">az vm show \
--resource-group jenkins-rg \
--name jenkins-vm -d \
--query [publicIps] \
--output tsv
</code></pre>
<p>You can now see the Jenkins application in your browser.</p>
<p><img src="https://i.imgur.com/Sy1Glar.png" alt="jenkins dashboard" width="2007" height="1025" loading="lazy">
<em>Jenkins dashboard</em></p>
<p>As you'll notice, Jenkins is asking us to provide an admin password which is automatically generated during its installation.</p>
<p>But first let's SSH into our virtual machine where Jenkins is installed.</p>
<pre><code class="lang-bash">ssh azureuser@&lt;ip_address&gt;
</code></pre>
<p>Now, type in the below command to get the password:</p>
<pre><code class="lang-bash">sudo cat /var/lib/jenkins/secrets/initialAdminPassword
</code></pre>
<p>Copy and paste it. Then click <strong>Continue</strong>.</p>
<h2 id="heading-how-to-configure-jenkins">How to Configure Jenkins</h2>
<p>First, you'll need to click <strong>Install suggested plugins</strong>. It will take some time to install all the plugins.</p>
<p><img src="https://i.imgur.com/vDaaqE3.png" alt="installing suggested plugins" width="2010" height="1095" loading="lazy">
<em>Installing suggested plugins</em></p>
<p>An admin user is needed to restrict access to Jenkins. So go ahead and create one. After finishing, click <strong>Save and continue</strong>.</p>
<p><img src="https://i.imgur.com/qqkwQN6.png" alt="create an admin user" width="2010" height="1036" loading="lazy">
<em>Create an admin user</em></p>
<p>Now you will be presented with the Jenkins dashboard.</p>
<p>The first step is to install the "Blue Ocean" plugin. Jenkins has a very old interface, which may make it difficult for some people to use. This blue ocean plugin provides a modern interface for some Jenkins components (like creating a pipeline).</p>
<p>To install plugins, go to <strong>Manage Jenkins</strong> -&gt; click <strong>Manage Plugins</strong> under "System Configuration" -&gt; <strong>Available plugins</strong>. Search for "Blue Ocean" -&gt; check the box and click <strong>Download now and install after restart</strong>.</p>
<p><img src="https://i.imgur.com/dAKBLiq.png" alt="blue ocean" width="1920" height="1080" loading="lazy">
<em>Blue ocean</em></p>
<p>Great, we're all set. Now let's create a pipeline.</p>
<h2 id="heading-how-to-write-a-jenkinsfile">How to Write a Jenkinsfile</h2>
<p>To create a pipeline, we need a <strong>Jenkinsfile</strong>. This file contains all the pipeline configurations – stages, steps, and so on. Jenkinsfile is to Jenkins as a Dockerfile is to Docker.</p>
<p>Jenkinsfile uses the <strong>Groovy</strong> syntax. The syntax is very simple. You can understand everything by just looking at it.</p>
<p>Let's start by writing:</p>
<pre><code class="lang-groovy">pipeline {

}
</code></pre>
<p>The word 'agent' should be the first thing you mention in the pipeline. An agent is similar to a container or environment in which jobs run. You can use multiple agents to run jobs in parallel. You can find more information about Jenkins agents can <a target="_blank" href="https://www.jenkins.io/doc/book/using/using-agents/">here</a>.</p>
<pre><code class="lang-groovy">pipeline {
    agent any
}
</code></pre>
<p>Here we are telling Jenkins to use any available agent.</p>
<p>We have a total of 5 stages in our pipeline:</p>
<p><img src="https://i.imgur.com/ezvdElo.png" alt="ci cd pipeline stages" width="1920" height="1080" loading="lazy">
<em>CI/CD pipeline stages</em></p>
<h3 id="heading-stage-1-checkout-code">Stage 1: Checkout code</h3>
<p>Different CI/CD tools use different naming conventions. In Jenkins, these are referred to as stages. In each stage we write various steps.</p>
<p>Our first stage is checking out code from a source code management system (in our case, GitHub).</p>
<pre><code class="lang-groovy">pipeline {
    agent any

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
    }
}
</code></pre>
<p>Commit the changes and push to your GitHub repo.</p>
<p>Since we haven't created any pipelines yet, let's do that now.</p>
<p>Before we begin, we must ensure that Git is installed on our system. If you followed my previous steps to install Jenkins on an Azure VM, Git is already installed. </p>
<p>You can test it by running the following command (make you are still SSHed into the VM):</p>
<pre><code class="lang-bash">git --version
</code></pre>
<p>If it isn't already installed, you can do so with:</p>
<pre><code class="lang-bash">sudo apt install git
</code></pre>
<p>Open blue ocean. Click <strong>Create new pipeline</strong>.</p>
<p><img src="https://i.imgur.com/FNffT6p.png" alt="creating new pipeline" width="2010" height="1036" loading="lazy">
<em>Creating new pipeline</em></p>
<p>Then select your source code management system. If you chose GitHub, you must provide an access token for Jenkins to access your repository. I recommend clicking on <strong>Create an access token here</strong> because it is a template with all of the necessary permissions. Then click <strong>Connect</strong>.</p>
<p><img src="https://i.imgur.com/H9TUsHV.png" alt="selecting scm" width="2010" height="1036" loading="lazy">
<em>Selecting scm</em></p>
<p>After that, a pipeline will be created. Since our repository already contains a Jenkinsfile, Jenkins automatically detects it and runs the stages and steps we mentioned in the pipeline.</p>
<p>If everything went well, the entire page will turn green. (Other colors: <strong>blue</strong> indicates that the pipeline is running, <strong>red</strong> indicates that something went wrong in the pipeline, and <strong>gray</strong> indicates that we stopped the pipeline.)</p>
<p><img src="https://i.imgur.com/FtvJlND.png" alt="stage one successful" width="1884" height="486" loading="lazy">
<em>Stage one successful</em></p>
<h3 id="heading-stage-2-run-frontend-tests">Stage 2: Run frontend tests</h3>
<p>In general, all the CI/CD pipelines contains some tests that needs to be run before deploying. So I added simple tests to both the frontend and backend. Let's start with the frontend tests.</p>
<pre><code class="lang-groovy">stage('Client Tests') {
    steps {
        dir('client') {
            sh 'npm install'
            sh 'npm test'
        }
    }
}
</code></pre>
<p>We're changing the directory to <code>client/</code> because that's where the frontend code is. And then install the dependencies with <code>npm install</code> and run the tests with <code>npm test</code> in a shell.</p>
<p>Again, before we restart the pipeline, we have to make sure node and npm are installed or not. Install node and npm with these commands in the virtual machine:</p>
<pre><code class="lang-bash">curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
</code></pre>
<p>After that, run the following:</p>
<pre><code class="lang-bash">sudo apt-get install -y nodejs
</code></pre>
<p>Now, commit the code and restart the pipeline.</p>
<p><img src="https://i.imgur.com/OWYcdDu.png" alt="run client tests" width="1886" height="438" loading="lazy">
<em>Run client tests</em></p>
<h3 id="heading-stage-3-run-backend-tests">Stage 3: Run backend tests</h3>
<p>Now do the same thing for the backend tests.</p>
<p>But there is one thing we need to do before we proceed. If you take a look at the codebase and <code>activity.test.js</code>, we are using a few environment variables. So let's add these environment varibales in Jenkins.</p>
<h4 id="heading-how-to-add-environment-variables-in-jenkins">How to add environment variables in Jenkins</h4>
<p>To add environment variables, go to <strong>Manage Jenkins</strong> -&gt; click <strong>Manage Credentials</strong> under "Security" -&gt;  <strong>System</strong> -&gt; <strong>Global credentials (unrestricted)</strong> -&gt; click <strong>+ Add Credentials</strong>.</p>
<p>For <strong>Kind</strong> select "Secret text", leave <strong>Scope</strong> default, and for <strong>Secret</strong> write the secret value and <strong>ID</strong>. This is what we use when using these environment variables in the Jenkinsfile.</p>
<p>Add the following env variables:</p>
<p><img src="https://i.imgur.com/xGjg2mG.png" alt="environment variables" width="2091" height="796" loading="lazy">
<em>Environment variables</em></p>
<p>Then in the Jenkinsfile, use these env variables:</p>
<pre><code class="lang-groovy">environment {
    MONGODB_URI = credentials('mongodb-uri')
    TOKEN_KEY = credentials('token-key')
    EMAIL = credentials('email')
    PASSWORD = credentials('password')
}
</code></pre>
<p>Add a stage to install dependencies, set these variables in the Jenkins environment, and run the tests:</p>
<pre><code class="lang-groovy">stage('Server Tests') {
    steps {
        dir('server') {
            sh 'npm install'
            sh 'export MONGODB_URI=$MONGODB_URI'
            sh 'export TOKEN_KEY=$TOKEN_KEY'
            sh 'export EMAIL=$EMAIL'
            sh 'export PASSWORD=$PASSWORD'
            sh 'npm test'
        }
    }
}
</code></pre>
<p>Again, commit the code and restart the pipeline.</p>
<p><img src="https://i.imgur.com/hpjMUyT.png" alt="run server tests" width="1059" height="595" loading="lazy">
<em>Run server tests</em></p>
<h3 id="heading-stage-4-build-docker-images">Stage 4: Build Docker images</h3>
<p>Now, we have to specify a step to build the Docker images from the Dockerfiles.</p>
<p>Before we proceed, install Docker in the VM (if you don't already have it installed).</p>
<p>To install Docker:</p>
<pre><code class="lang-bash">sudo apt install docker.io
</code></pre>
<p>Add the user <code>jenkins</code> to the <code>docker</code> group so that Jenkins can access the Docker daemon – otherwise you'll get a permission denied error.</p>
<pre><code class="lang-bash">sudo usermod -a -G docker jenkins
</code></pre>
<p>Then restart the <code>jenkins</code> service.</p>
<pre><code class="lang-bash">sudo systemctl restart jenkins
</code></pre>
<p>Add a stage in the Jenkinsfile.</p>
<pre><code class="lang-groovy">stage('Build Images') {
    steps {
        sh 'docker build -t rakeshpotnuru/productivity-app:client-latest client'
        sh 'docker build -t rakeshpotnuru/productivity-app:server-latest server'
    }
}
</code></pre>
<p>Commit the code and restart the pipeline.</p>
<p><img src="https://i.imgur.com/USh63SD.png" alt="build docker images" width="1984" height="914" loading="lazy">
<em>Build docker images</em></p>
<h3 id="heading-stage-5-push-images-to-the-registry">Stage 5: Push images to the registry</h3>
<p>As a final stage, we will push the images to Docker hub.</p>
<p>Before that, add your docker hub username and password to the Jenkins credentials manager, but for <strong>Kind</strong> choose "Username with password".</p>
<p><img src="https://i.imgur.com/ue0MMKM.png" alt="username with password type credential" width="2010" height="1095" loading="lazy">
<em>Username with password type credential</em></p>
<p>Add the final stage where we login and push images to Docker hub.</p>
<pre><code class="lang-groovy">stage('Push Images to DockerHub') {
    steps {
        withCredentials([usernamePassword(credentialsId: 'dockerhub', passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
            sh 'docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD'
            sh 'docker push rakeshpotnuru/productivity-app:client-latest'
            sh 'docker push rakeshpotnuru/productivity-app:server-latest'
        }
    }
}
</code></pre>
<p><img src="https://i.imgur.com/copfIou.png" alt="push images to dockerhub" width="1991" height="919" loading="lazy">
<em>Push images to dockerhub</em></p>
<p>Here is the complete Jenkinsfile:</p>
<pre><code class="lang-groovy">// This is a Jenkinsfile. It is a script that Jenkins will run when a build is triggered.
pipeline {
    // Telling Jenkins to run the pipeline on any available agent.
    agent any

    // Setting environment variables for the build.
    environment {
        MONGODB_URI = credentials('mongodb-uri')
        TOKEN_KEY = credentials('token-key')
        EMAIL = credentials('email')
        PASSWORD = credentials('password')
    }

    // This is the pipeline. It is a series of stages that Jenkins will run.
    stages {
        // This state is telling Jenkins to checkout the source code from the source control management system.
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        // This stage is telling Jenkins to run the tests in the client directory.
        stage('Client Tests') {
            steps {
                dir('client') {
                    sh 'npm install'
                    sh 'npm test'
                }
            }
        }

        // This stage is telling Jenkins to run the tests in the server directory.
        stage('Server Tests') {
            steps {
                dir('server') {
                    sh 'npm install'
                    sh 'export MONGODB_URI=$MONGODB_URI'
                    sh 'export TOKEN_KEY=$TOKEN_KEY'
                    sh 'export EMAIL=$EMAIL'
                    sh 'export PASSWORD=$PASSWORD'
                    sh 'npm test'
                }
            }
        }

        // This stage is telling Jenkins to build the images for the client and server.
        stage('Build Images') {
            steps {
                sh 'docker build -t rakeshpotnuru/productivity-app:client-latest client'
                sh 'docker build -t rakeshpotnuru/productivity-app:server-latest server'
            }
        }

        // This stage is telling Jenkins to push the images to DockerHub.
        stage('Push Images to DockerHub') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'dockerhub', passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
                    sh 'docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD'
                    sh 'docker push rakeshpotnuru/productivity-app:client-latest'
                    sh 'docker push rakeshpotnuru/productivity-app:server-latest'
                }
            }
        }
    }
}
</code></pre>
<p><img src="https://i.imgur.com/NQxFXhO.png" alt="pipeline ran successfully" width="2120" height="1155" loading="lazy">
<em>Pipeline ran successfully</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In summary, let's review what we've covered:</p>
<ul>
<li>We explored the significance of implementing Continuous Integration and Continuous Deployment (CI/CD) in software development.</li>
<li>We delved into the fundamentals of Jenkins and acquired knowledge on how to deploy a Jenkins server on the Azure cloud platform.</li>
<li>We customized Jenkins to meet our specific requirements.</li>
<li>Lastly, we wrote a Jenkinsfile and built a pipeline utilizing the user-friendly interface of Jenkins Blue Ocean.</li>
</ul>
<p>That's all for now! Thanks for reading 🙂.</p>
<p>Connect with me on <a target="_blank" href="https://twitter.com/rakesh_at_tweet">twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Callbacks Work in Node.js ]]>
                </title>
                <description>
                    <![CDATA[ By Aditya Gupta Node.js callbacks are a special type of function passed as an argument to another function.  They're called when the function that contains the callback as an argument completes its execution, and allows the code in the callback to ru... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/nodejs-callbacks/</link>
                <guid isPermaLink="false">66d45d5dc17d4b8ace5b9eac</guid>
                
                    <category>
                        <![CDATA[ callbacks ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 28 Feb 2023 22:53:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/pexels-chepte--cormani-1416530.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Aditya Gupta</p>
<p>Node.js callbacks are a special type of function passed as an argument to another function. </p>
<p>They're called when the function that contains the callback as an argument completes its execution, and allows the code in the callback to run in the meantime.</p>
<p>Callbacks help us make asynchronous calls. Even Node.js APIs are written in a way that supports callbacks.</p>
<p><strong>Here's the syntax of a callback in Node:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">function_name</span>(<span class="hljs-params">argument, callback</span>)</span>
</code></pre>
<h2 id="heading-how-to-use-callbacks-in-node"><strong>How to Use Callbacks in Node</strong></h2>
<p>The callback is used to define what happens when the function containing the callback as an argument completes its execution.</p>
<p>For example, we can define a callback to print the error and result after the function execution.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">function_name</span>(<span class="hljs-params">argument, function (error, result){ if(error){ console.log(error) } else { console.log(result) } }</span>)</span>
</code></pre>
<h2 id="heading-how-to-write-callbacks"><strong>How to Write Callbacks</strong></h2>
<p>You can write a callback function in two ways: as an arrow function, and as a standard function without a name. Both ways will give you the same result.</p>
<h3 id="heading-how-to-write-a-callback-as-a-standard-function-without-a-name">How to write a callback as a standard function without a name</h3>
<p>You can write a callback as a regular function. You do that using a function keyword then the argument inside round brackets. Then you use curly brackets where you can define the callback body. It is not required to define the function name since it is automatically called.</p>
<p><strong>Syntax:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">function_name</span>(<span class="hljs-params">argument, function (callback_argument){
    <span class="hljs-regexp">//</span> callback body 
}</span>)</span>
</code></pre>
<p>Let’s see an example of a callback using the setTimeout function. You can use this method to define a callback function that runs after a definite time.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">setTimeout</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">'Callback as Standard Function'</span>); 
}, <span class="hljs-number">1000</span>);
</code></pre>
<p>Here we define a callback that runs after 1000 milliseconds which is equivalent to 1 second.</p>
<p><strong>Output:</strong></p>
<p><img src="https://codeforgeek.com/wp-content/uploads/2022/11/callback-standard.png" alt="Callback Standard" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-write-a-callback-as-an-arrow-function">How to write a callback as an arrow function</h3>
<p>It may be confusing to have multiple function keywords in a block of code. To eliminate the function keyword in the callback, you can use an arrow function. The arrow function was introduced in ES6 and helps you write cleaner code by removing the function keyword.</p>
<p><strong>Syntax:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">function_name</span>(<span class="hljs-params">argument, (callback_argument) =&gt; { 
    <span class="hljs-regexp">//</span> callback body 
}</span>)</span>
</code></pre>
<p>Let’s rewrite the same example we wrote in the above section using an arrow function. Here we change the string to "Callback as Arrow Function".</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> { 
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Callback as Arrow Function'</span>); 
}, <span class="hljs-number">1000</span>);
</code></pre>
<p><strong>Output:</strong></p>
<p><img src="https://codeforgeek.com/wp-content/uploads/2022/11/callback-as-arrow-function.png" alt="Callback As Arrow Function" width="600" height="400" loading="lazy"></p>
<h2 id="heading-asynchronous-programming-using-callbacks">Asynchronous Programming Using Callbacks</h2>
<p>Asynchronous programming is an approach to running multiple processes at a time without blocking the other part(s) of the code.</p>
<p>By using callbacks, we can write asynchronous code in a better way. For example, we can define a callback that prints the result after the parent function completes its execution. Then there is no need to block other blocks of the code in order to print the result.</p>
<p>Let’s take the example of a file system module which used to interact with files in Node.js. For reading a file, we can use the <code>readFileSync</code> method.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);

<span class="hljs-keyword">const</span> data = fs.readFileSync(<span class="hljs-string">'hello.txt'</span>, <span class="hljs-string">'utf-8'</span>); <span class="hljs-built_in">console</span>.log(data);
</code></pre>
<p><strong>Output:</strong></p>
<p><img src="https://codeforgeek.com/wp-content/uploads/2022/11/output-read-sync.png" alt="Output Read Sync" width="600" height="400" loading="lazy"></p>
<p>But this way our code holds up the execution of the rest of the program until it finishes its execution and prints the result. </p>
<p>Luckily, we can use a callback to write the code asynchronously without blocking the rest of the execution using the readFile method. When the reading of the file is done, then the callback gets triggered and prints the result.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>); 

<span class="hljs-keyword">const</span> data = fs.readFile(<span class="hljs-string">'hello.txt'</span>, <span class="hljs-string">'utf-8'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">err, result</span>)</span>{ 
    <span class="hljs-keyword">if</span>(err){ 
        <span class="hljs-built_in">console</span>.log(err) 
    } <span class="hljs-keyword">else</span> { 
        <span class="hljs-built_in">console</span>.log(result) 
    } 
});
</code></pre>
<p><strong>Output:</strong></p>
<p><img src="https://codeforgeek.com/wp-content/uploads/2022/11/output-read-sync-1.png" alt="Output Read Async" width="600" height="400" loading="lazy"></p>
<h2 id="heading-summary"><strong>Summary</strong></h2>
<p>NodeJS callbacks are a special type of function you can use to write asynchronous code. They give you a way to execute a block of code in the meantime after the execution of a function. You can define whether it prints a result, error, or performs the extra operation of the function result. </p>
<p>There are two ways to write a function: without a function name, or in the form of an arrow function. The arrow function is more convenient and results in cleaner code by removing the use of annoying function keywords. </p>
<p>I hope this article helps you understand Node.js callbacks.</p>
<p>You can <a target="_blank" href="https://nodejs.org/en/knowledge/getting-started/control-flow/what-are-callbacks/">have a look at the docs here</a> if you want to learn more.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Your Own E-Commerce Site with Medusa ]]>
                </title>
                <description>
                    <![CDATA[ In today's digital age, having an online presence is crucial for businesses of all sizes.  Whether you're an established retailer or an aspiring entrepreneur, an ecommerce site can provide you with a platform to reach a global audience and sell your ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-your-own-e-commerce-site-with-medusa/</link>
                <guid isPermaLink="false">66ba0e86f602a81788fe2189</guid>
                
                    <category>
                        <![CDATA[ ecommerce ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 27 Feb 2023 15:36:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/medusa.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In today's digital age, having an online presence is crucial for businesses of all sizes. </p>
<p>Whether you're an established retailer or an aspiring entrepreneur, an ecommerce site can provide you with a platform to reach a global audience and sell your products or services around the clock.</p>
<p>Building an ecommerce site may seem like a daunting task, but with the right tools and guidance, anyone can create a professional and functional online store. </p>
<p>In this tutorial, you'll learn how to build your own e-commerce site with Medusa.</p>
<h2 id="heading-what-is-medusa">What is Medusa?</h2>
<p><a target="_blank" href="https://medusajs.com">Medusa</a> is an <em>open source</em>, <em>composable</em> commerce platform that's perfect for developers who want to create a customized ecommerce solution. With its flexible architecture and powerful features, Medusa offers a seamless and straightforward way to build a robust and scalable ecommerce site.</p>
<p>Medusa offers a variety of features, including order management with automated swaps, returns, and claims. It also enables customer management and assignment to customer groups, along with product customization and collection sorting. </p>
<p>With the ability to manage multiple regions and currencies, users can integrate various plugins and third-party services, create advanced pricing and discount rules, configure taxes, and set up multiple sales channels. </p>
<p>Additionally, Medusa offers bulk import and export strategies, and complete customization capabilities to create custom endpoints, services, subscribers, batch job strategies, and more.</p>
<p>In just over a year since its launch, this platform has quickly risen to become the <a target="_blank" href="https://medusajs.com/blog/nodejs-ecommerce-backend/">#1 Node.js ecommerce solution</a>, garnering over 17K+ stars on <a target="_blank" href="https://github.com/medusajs/medusa">GitHub</a> due to its immense popularity.</p>
<h2 id="heading-architecture-of-medusa">Architecture of Medusa</h2>
<p>With a composable architecture, Medusa's frontend and backend components are loosely coupled. The platform consists of three different components: the <strong>headless backend</strong>, the <strong>admin dashboard</strong>, and the <strong>storefront</strong>.</p>
<p>You can choose to use the complete Medusa platform or just the parts that you require for your store. </p>
<p>Additionally, with the backend decoupled from the frontend, developers can focus on their respective areas of expertise. Backend developers can concentrate on the Medusa server, while frontend developers can focus on either the storefront or admin.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/medusa-arch.png" alt="Image" width="600" height="400" loading="lazy">
<em>Medusa Architecture</em></p>
<p>In the upcoming sections, you will see how Medusa delivers most ecommerce store functionalities right out of the box, with the ability to configure these features to your specific use case.</p>
<h3 id="heading-medusa-server"><strong>Medusa Server</strong></h3>
<p>The Medusa server, which is a Node.js ecommerce backend, serves as a core component of the platform. It contains all the store's data and logic, and the other two components use its REST APIs to create, retrieve, and modify data.</p>
<p>The server provides most of the features related to an ecommerce workflow. These functionalities include managing products, carts, and orders, as well as integrating with shipping and payment providers and managing users. </p>
<p>In addition to that, you can configure your store including your store’s region, tax rules, discounts, gift cards, and more.</p>
<p>Since Medusa is highly extensible, it allows developers to build custom features such as <a target="_blank" href="https://medusajs.com/blog/customer-group-automation/">automating customer group assignments</a> and <a target="_blank" href="https://medusajs.com/blog/chatgpt-medusa/">integrating ChatGPT to automate writing product descriptions</a>. </p>
<p>In addition to that, you can also integrate third-party services into Medusa using <a target="_blank" href="https://docs.medusajs.com/advanced/backend/plugins/overview">Plugins</a>. You can find both official and community plugins to assist you with your common needs. Learn more about these plugins <a target="_blank" href="https://docs.medusajs.com/advanced/backend/plugins/overview/">here</a>.</p>
<p>Medusa also allows you to extend its functionalities with new endpoints, business logic, and database entities. Additionally, you can create subscribers that listen to events and trigger specific actions.</p>
<h3 id="heading-medusa-storefront">Medusa Storefront</h3>
<p>The storefront serves as the main presentation layer or frontend of your ecommerce store where customers can view and purchase your products. These storefronts can be in the form of progressive web applications or mobile apps.</p>
<p>Medusa offers two storefront starters built with <a target="_blank" href="https://docs.medusajs.com/starters/nextjs-medusa-starter">Next.js</a> and <a target="_blank" href="https://docs.medusajs.com/starters/gatsby-medusa-starter/">Gatsby</a>, respectively. The storefront includes several features such as product listing and detail pages, customer authentication and profile functionalities, and a full checkout flow supporting shipping details and methods. It also comes with search capabilities ready for integration with top solutions like Algolia and MeiliSearch.</p>
<p>Below is a demonstration of what the Next.js storefront looks like:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/TmV2xNbNs4w" 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>In addition to the provided storefront starters, you have the freedom to create your own custom storefront using the <a target="_blank" href="https://docs.medusajs.com/api/store/">Storefront REST APIs</a>.</p>
<h3 id="heading-medusa-admin"><strong>Medusa Admin</strong></h3>
<p>An ecommerce store's essential component is the Admin dashboard, which enables merchants to view, create, and modify data such as products and orders.</p>
<p>With the Medusa Admin dashboard, Medusa provides functionalities for store management, including product management, order management, and user management. You can manage your orders from various regions and channels using a single dashboard.</p>
<p>For merchants migrating their stores from other platforms, the admin dashboard provides easy import and export functionalities for large datasets of products, orders, and customers. The dashboard also offers customer-group functionality to create customized pricing lists, discounts, and gift cards.</p>
<p>This is what the Medusa Admin Dashboard looks like:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/Z6uoN7TR0Z0" 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>However, if you are not satisfied with the existing admin dashboard, you can utilize the Admin REST APIs to extend it beyond.</p>
<h2 id="heading-how-to-set-up-an-ecommerce-store-using-medusa">How to Set Up an Ecommerce Store Using Medusa</h2>
<p>In this section, you'll set up the three components of your Medusa ecommerce store.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>Before you get started with the tutorial, you should have installed:</p>
<ul>
<li><a target="_blank" href="https://docs.medusajs.com/tutorial/set-up-your-development-environment#nodejs">Node.js(V14 or later)</a></li>
<li><a target="_blank" href="https://docs.medusajs.com/tutorial/set-up-your-development-environment/#git">Git</a></li>
<li><a target="_blank" href="https://docs.medusajs.com/tutorial/set-up-your-development-environment#medusa-cli">Medusa CLI</a></li>
</ul>
<h3 id="heading-how-to-set-up-the-medusa-server">How to Set Up the Medusa Server</h3>
<p>Creating a new Medusa server is a simple process using the Medusa CLI. Navigate to the directory where you want to create your Medusa server and run the following command to create a new Medusa server with the name <code>my-medusa-store</code>:</p>
<pre><code class="lang-bash">medusa new my-medusa-store --seed
</code></pre>
<p>This command will create a new Medusa server with the specified name. The <code>--seed</code> option tells the Medusa CLI to seed the data after creating the server. The seed data includes sample data such as products, categories, and more.</p>
<p>Once the command finishes executing, navigate to the <code>my-medusa-store</code> directory and start the server by running the following command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-medusa-store
medusa develop
</code></pre>
<p>In a couple of minutes, the server will start running on the default <code>9000</code> port. You can test it out by sending a request using a tool like Postman or through the command line:</p>
<pre><code class="lang-bash">curl localhost:9000/store/products
</code></pre>
<p>If your server is successfully set up, you will see a list of products and other details as below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/curl-output.png" alt="Image" width="600" height="400" loading="lazy">
<em>Output of cURL command</em></p>
<h3 id="heading-how-to-set-up-the-nextjs-storefront">How to Set Up the Next.js Storefront</h3>
<p>Now that your Medusa server is up and running, it's time to configure your storefront. In this section, you'll set up the Next.js storefront.</p>
<p>Create a new Next.js project using the <a target="_blank" href="https://github.com/medusajs/nextjs-starter-medusa">Medusa Next.js starter template</a>:</p>
<pre><code class="lang-bash">npx create-next-app -e https://github.com/medusajs/nextjs-starter-medusa my-medusa-storefront
</code></pre>
<p>Navigate to the newly created directory <code>my-medusa-storefront</code> folder and rename the template environment variable file to use environment variables in development:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-medusa-storefront
mv .env.template .env.local
</code></pre>
<p>Make sure the Medusa server is running, then run the local Next.js server:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Your Next.js storefront will now be running on its default port <code>8000</code>.</p>
<p>Note: Medusa also provides you with the <a target="_blank" href="https://docs.medusajs.com/starters/gatsby-medusa-starter/">Gatsby starter template</a> to create the storefront.</p>
<h3 id="heading-how-to-set-up-the-medusa-admin-dashboard">How to Set Up the Medusa Admin Dashboard</h3>
<p>Since the Medusa Admin uses the Medusa server, make sure your server is up and running.</p>
<p>Start by cloning the <a target="_blank" href="https://github.com/medusajs/admin">Admin GitHub repository</a>:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/medusajs/admin my-medusa-admin
</code></pre>
<p>Navigate to the cloned <code>my-medusa-admin</code> folder and install all the dependencies:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-medusa-admin
npm install
</code></pre>
<p>Run the development server:</p>
<pre><code class="lang-bash">npm run start
</code></pre>
<p>In a couple of minutes, the admin will start running on the default <code>7000</code> port. So, in your browser, go to <code>localhost:7000</code> to view your admin.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/medusa-admin.png" alt="Image" width="600" height="400" loading="lazy">
<em>Medusa Admin Login</em></p>
<p>If you had already seeded the data in your Medusa server, you can use the email <code>admin@medusa-test.com</code> and password <code>supersecret</code> to log in. If you hadn't, you can <a target="_blank" href="https://docs.medusajs.com/admin/quickstart#create-a-new-admin-user">create a new admin user</a>.</p>
<h2 id="heading-how-to-set-up-medusa-with-create-medusa-app">How to Set Up Medusa with <code>create-medusa-app</code></h2>
<p>Up to this point, you have seen how to set up individual components of a Medusa project. But in this section, you will learn how to set up a complete Medusa project with all three components using a single command.</p>
<p>Medusa now provides you with a <code>create-medusa-app</code> command to set up a project. This command provides an interactive prompt that guides you through the setup process.</p>
<p>To use <code>create-medusa-app</code>, simply run the following command:</p>
<pre><code class="lang-bash">npx create-medusa-app
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/create-medusa-app.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Creating Medusa Project Using create-medusa-app</em></p>
<p>In this interactive setup, you will be prompted to enter the name of the directory where you want to install the Medusa project. The default name is <code>my-medusa-store</code>, but you can choose to name it something else.</p>
<p>Next, you will be asked to select a Medusa server starter from the available options, which include the default starter, the Contentful starter, and the option to enter a custom starter URL. The server will be installed in the <code>backend</code> directory of your project, and a demo SQLite database will be created within it.</p>
<p>Following the Medusa server setup, you will be prompted to choose a storefront starter from the available options. If you choose to install a storefront, it will be installed in the <code>storefront</code> directory of your project. If you choose "None", no storefront will be installed.</p>
<p>The admin is set up automatically inside the <code>admin</code> directory of your project.</p>
<p>Once the setup is complete, you will receive instructions on how to start each component of the Medusa project.</p>
<pre><code class="lang-bash">Your project is ready. The available commands are:

Medusa API
<span class="hljs-built_in">cd</span> my-medusa-store/backend
yarn start

Admin
<span class="hljs-built_in">cd</span> my-medusa-store/admin
yarn start

Storefront
<span class="hljs-built_in">cd</span> my-medusa-store/storefront
yarn develop <span class="hljs-comment"># for Gatsby storefront</span>
yarn dev <span class="hljs-comment"># for Next.js storefront</span>
</code></pre>
<p>Just keep in mind that the commands can differ based on your choices in previous prompts.</p>
<h3 id="heading-project-directory-structure">Project Directory Structure</h3>
<p>Inside the root project directory (which was specified at the beginning of the installation process – <code>my-medusa-store</code> in this case) you’ll find the following directory structure:</p>
<pre><code class="lang-bash">my-medusa-store
  ├── admin
  ├── backend
  └── storefront
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we've explored Medusa, an open-source e-commerce platform that provides a robust set of features for building online stores. We've looked at the architecture of Medusa, its key features, and how to set up the server, admin dashboard, and storefront.</p>
<p>One of the strengths of Medusa is its flexibility and extensibility. With a variety of plugins and extensions, you can customize your e-commerce site to meet your specific needs. You can also create your own plugins or themes, making it easy to build a site that reflects your brand.</p>
<p>If you're looking to build an e-commerce site, Medusa is a solid choice that offers a lot of functionality out of the box. With its user-friendly interface, setting up an online store is a straightforward process. Plus, since it's an open-source platform, you have the freedom to modify and extend it as needed.</p>
<h3 id="heading-additional-resources">Additional Resources</h3>
<p>Here are some resources that you can use to extend the functionalities:</p>
<ul>
<li>Integrate <a target="_blank" href="https://docs.medusajs.com/add-plugins/sendgrid">SendGrid</a> as a notification provider.</li>
<li>Integrate <a target="_blank" href="https://docs.medusajs.com/add-plugins/stripe">Stripe</a> as a payment provider.</li>
<li><a target="_blank" href="https://docs.medusajs.com/advanced/backend/services/create-service">Create a service</a>.</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create and Publish an NPM Package – a Step-by-Step Guide ]]>
                </title>
                <description>
                    <![CDATA[ NPM is the largest software registry on the internet. There are over a million packages in the NPM Library. Developers publish packages on NPM to share their code with others. And organisations also use NPM to share code internally. In this article, ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-and-publish-your-first-npm-package/</link>
                <guid isPermaLink="false">66d45ddaa3a4f04fb2dd2e33</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ modules ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ npm ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Benjamin Semah ]]>
                </dc:creator>
                <pubDate>Wed, 01 Feb 2023 21:36:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/npm-package-article-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>NPM is the largest software registry on the internet. There are over a million packages in the NPM Library.</p>
<p>Developers publish packages on NPM to share their code with others. And organisations also use NPM to share code internally.</p>
<p>In this article, you will learn how to create a package. And you will also learn how to publish your package on NPM so others can download and use it.</p>
<p>Let's get started!</p>
<h2 id="heading-how-to-choose-a-name-for-your-npm-package">How to Choose a Name For Your NPM Package</h2>
<p>The first thing you need to do before creating your package is to choose a name. This is important because your package needs to have a unique name. You should choose a name that has not been used already.</p>
<p>When you decide on a name, go to the <a target="_blank" href="https://www.npmjs.com/">NPM registry</a> and run a search. Be sure there's no exact match to the name you chose (or a match that is too similar).</p>
<p>For example, if there's a package called <code>hellonpmpackage</code> and you decide to call yours <code>hello-npm-package</code>, NPM will throw an error when you attempt to publish it.</p>
<p>If there's already a package in the NPM registry with the same you want to use, then you have two options.</p>
<ol>
<li><p>You can choose a different name.</p>
</li>
<li><p>You can publish your package as a scoped package (see the section "Publishing scoped packages" below).</p>
</li>
</ol>
<h2 id="heading-how-to-create-a-npm-package">How to Create a NPM Package</h2>
<p>Follow the steps below to create your package.</p>
<h3 id="heading-1-install-node">1. Install Node</h3>
<p>If you do not already have Node installed, you should go ahead and install it. You can visit the official website to <a target="_blank" href="https://nodejs.org/en/download/">download and install Node.js</a>. NPM comes pre-installed with Node.</p>
<h3 id="heading-2-initialize-a-git-repository">2. Initialize a Git Repository</h3>
<p>Create a new project folder for your package and navigate into the folder. Then, run the following command in your terminal:</p>
<pre><code class="lang-json">git init
</code></pre>
<p>This will help you track the changes you make to your package. Also, make sure you have a remote version of your repository on GitHub (or your preferred hosting service).</p>
<h3 id="heading-3-initialize-npm-in-your-project">3. Initialize NPM in Your Project</h3>
<p>To do this, navigate to the root directory of your project and run the following command:</p>
<pre><code class="lang-json">npm init
</code></pre>
<p>This command will create a <code>package.json</code> file. You will get prompts to provide the following information:</p>
<ul>
<li><p><code>package-name</code>: As you learned earlier in this tutorial, the name of your package must be unique. Also it must be lowercase. It may include hyphens.</p>
</li>
<li><p><code>version</code>: The initial value is 1.0.0. You update the number when you update your package using <a target="_blank" href="https://www.freecodecamp.org/news/semantic-versioning-1fd6f57749f7/">semantic versioning</a>.</p>
</li>
<li><p><code>description</code>: You can provide a description of your package here. Indicate what your package does and how to use it.</p>
</li>
<li><p><code>entry point</code>: The entry file for your code. The default value is <code>index.js</code>.</p>
</li>
<li><p><code>test command</code>: Here, you can add the command you want to run when a user runs <code>npm run test</code>.</p>
</li>
<li><p><code>git repository</code>: The link to your remote repository on GitHub.</p>
</li>
<li><p><code>keywords</code>: Add relevant keywords that will help others find your package on the NPM registry.</p>
</li>
<li><p><code>author</code>: Add your name.</p>
</li>
<li><p><code>license</code>: You can add a license or use the default license (Internet Systems Consortium (ISC) License).</p>
</li>
</ul>
<p>See the screenshot below for an example of how to answer the prompt questions:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/npm-image1.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating a package.json file</em></p>
<p><em>Note: I left the</em> <code>test command</code> blank because there is no test command for the package in this tutorial.</p>
<h3 id="heading-4-add-your-code">4. Add Your Code</h3>
<p>Now, you can go ahead and add the code for your package.</p>
<p>First, you need to create the file that will be loaded when your module is required by another application. For this tutorial, that will be the <code>index.js</code> file.</p>
<p>Inside the <code>index.js</code> file, add the code for your package.</p>
<p>For this tutorial, I will be creating a simple package called <code>first-hello-npm</code>. This package returns the string <code>"Hello NPM!"</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//index.js</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">helloNpm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-string">"hello NPM"</span>
}

<span class="hljs-built_in">module</span>.exports = helloNpm
</code></pre>
<p>After creating your function, you should export it like in the example above. That way, anyone who downloads your package can load and use it in their code.</p>
<p>If you have been following along, you should now have your package created. But before you publish, you need to test your package. Testing your package reduces the chances of publishing bugs to the NPM registry.</p>
<h2 id="heading-how-to-test-your-npm-package">How to Test Your NPM Package</h2>
<p>Testing ensures that your NPM package works as expected. There are many ways to test your package. In this tutorial, you will learn one of the simplest ways of testing.</p>
<p>First, navigate to the root of your <code>package</code> project. Then, run the following command:</p>
<pre><code class="lang-json">npm link
</code></pre>
<p>This will make your package available globally. And you can require the package in a different project to test it out.</p>
<p>Create a <code>test</code> folder. And inside that test folder, add a <code>script.js</code> file.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/npm-image2.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Example of a test folder with a script.js file</em></p>
<p>In the example above, the test folder contains only the <code>script.js</code> file. It does not yet contain the package. To add the package you created to your test folder, run the command below:</p>
<pre><code class="lang-json">npm link &lt;name-of-package&gt;
</code></pre>
<p>In the case of the test folder for this tutorial, I will run the following command:</p>
<pre><code class="lang-json">npm link first-hello-npm
</code></pre>
<p>This will create a <code>node-modules</code> folder. And it'll add all the files and folders from your package – see the screenshot below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/npm-image3.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In the <code>script.js</code> file, you can now require your package and use it for the test.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// test/script.js</span>

<span class="hljs-keyword">const</span> helloNpm = <span class="hljs-built_in">require</span>(<span class="hljs-string">'first-hello-npm'</span>)

<span class="hljs-built_in">console</span>.log(helloNpm())
</code></pre>
<p>The <code>first-hello-npm</code> package is expected to return the string <code>"hello NPM!"</code>. As you can see from the screenshot below, the package works as expected when I run the script.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/npm-image4.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Test result for first-hello-npm package</em></p>
<p>After testing your package and ensuring it works as expected, you can now publish it on the NPM registry.</p>
<h2 id="heading-how-to-publish-your-npm-package">How to Publish Your NPM Package</h2>
<p>To publish your package on the NPM registry, you need to have an account. If you don't have an account, visit the <a target="_blank" href="https://www.npmjs.com/signup">NPM sign up page</a> to create one.</p>
<p>After creating the account, open your terminal and run the following command in the root of your package:</p>
<pre><code class="lang-json">npm login
</code></pre>
<p>You will get a prompt to enter your <code>username</code> and <code>password</code>. If login is successful, you should see a message like this:</p>
<p><code>Logged in as &lt;your-username&gt; on https://registry.npmjs.org/.</code></p>
<p>You can now run the following command to publish your package on the NPM registry:</p>
<pre><code class="lang-json">npm publish
</code></pre>
<p>If all goes well, you should get results similar to the screenshot below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/npm-image7.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Notice indicating that the package is published successfully.</em></p>
<p>If you have been following along, then congratulations! You just published your first NPM package.</p>
<p>You can visit the <a target="_blank" href="https://www.npmjs.com/">NPM website</a> and run a search for your package. You should see your package show up in the search results.</p>
<p>For example, from the screenshot below, you can see the <code>first-hello-npm</code> package is now available on NPM.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/package-available.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>The first-hello-npm package is now available on NPM</em></p>
<h2 id="heading-how-to-publish-scoped-npm-packages">How to Publish Scoped NPM Packages</h2>
<p>If an existing package has the same name you would like to use, the workaround is to publish a scoped package.</p>
<p>When you publish a scoped package, you have the option to make it public or private. If it's private, you can choose who you want to share the package with.</p>
<h3 id="heading-how-to-create-a-scoped-npm-package">How to Create a Scoped NPM Package</h3>
<p>To create a scoped package, first navigate to the root of your package directory.</p>
<p>Then, run the <code>npm init</code> command and pass your <code>username</code> as the value to the <code>scope</code> flag:</p>
<pre><code class="lang-json">npm init --scope=@your-username
</code></pre>
<p>Respond to the prompts to create a <code>package.json</code> file. For your package name, the format should be <code>@your-username/package-name</code>.</p>
<p>For example <code>@benjaminsemah/first-hello-npm</code>.</p>
<p>You can now add the code for your package and test it. The process is the same as already explained above.</p>
<p>Then, to publish your scoped package, run the following command in your terminal.</p>
<pre><code class="lang-json">npm publish --access public
</code></pre>
<p>You can change from <code>public</code> to <code>private</code> if you don't want to make the package available for public use.</p>
<p>You should see a response similar to this.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/scoped-package-published.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Scoped package published successfully.</em></p>
<p>Congratulations if you followed along. You've published your scoped package. You should see your scoped package on NPM if you search for it. For example in the screenshot below, you can see the scoped package I created in this tutorial.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/scoped-package-available.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Scoped package is now available on NPM</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Packages helps developers work faster. And they also improve collaboration. When you figure out a smarter way of doing things, one way you can share with the community is to create and publish your solution as a package.</p>
<p>In this article, you learned what packages are and why they are useful. You also learned how to create and publish packages on the NPM registry. The developer community awaits all the beautiful packages you will create and share.</p>
<p>Thanks for reading. And happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What Are Node Modules and How Do You Use Them? ]]>
                </title>
                <description>
                    <![CDATA[ Every Node.js application has modules. These modules form part of the building blocks of the application. They help developers work faster and write more structured code. In this tutorial, you will learn what node modules are. You will also learn abo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-are-node-modules/</link>
                <guid isPermaLink="false">66d45df0182810487e0ce11d</guid>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ modules ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ npm ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Benjamin Semah ]]>
                </dc:creator>
                <pubDate>Tue, 06 Dec 2022 17:54:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/stock.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Every Node.js application has modules. These modules form part of the building blocks of the application. They help developers work faster and write more structured code.</p>
<p>In this tutorial, you will learn what node modules are. You will also learn about the three types of node modules. And we'll go over the right way to use them in your applications.</p>
<h2 id="heading-what-is-a-module-in-javascript">What is a Module in JavaScript?</h2>
<p>In simple terms, a module is a piece of reusable JavaScript code. It could be a <code>.js</code> file or a directory containing <code>.js</code> files. You can export the content of these files and use them in other files.</p>
<p>Modules help developers adhere to the DRY (Don't Repeat Yourself) principle in programming. They also help to break down complex logic into small, simple, and manageable chunks.</p>
<h2 id="heading-types-of-node-modules">Types of Node Modules</h2>
<p>There are three main types of Node modules that you will work with as a Node.js developer. They include the following.</p>
<ul>
<li><p>Built-in modules</p>
</li>
<li><p>Local modules</p>
</li>
<li><p>Third-party modules</p>
</li>
</ul>
<h3 id="heading-built-in-modules">Built-in Modules</h3>
<p>Node.js comes with some modules out of the box. These modules are available for use when you install Node.js. Some common examples of built-in Node modules are the following:</p>
<ul>
<li><p>http</p>
</li>
<li><p>url</p>
</li>
<li><p>path</p>
</li>
<li><p>fs</p>
</li>
<li><p>os</p>
</li>
</ul>
<p>You can use the built-in modules with the syntax below.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> someVariable = <span class="hljs-built_in">require</span>(<span class="hljs-string">'nameOfModule'</span>)
</code></pre>
<p>You load the module with the <code>require</code> function. You need to pass the name of the module you're loading as an argument to the <code>require</code> function.</p>
<p><strong>Note:</strong> The name of the module must be in quotation marks. Also, using <code>const</code> to declare the variable ensures that you do not overwrite the value when calling it.</p>
<p>You also need to save the returned value from the <code>require</code> function in <code>someVariable</code>. You can name that variable anything you want. But often, you will see programmers give the same to the variable as the name of the module (see example below).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>) 

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

server.listen(<span class="hljs-number">3000</span>)
</code></pre>
<p>You use the <code>require</code> function to load the built-in <code>http</code> module. Then, you save the returned value in a variable named <code>http</code>.</p>
<p>The returned value from the <code>http</code> module is an object. Since you've loaded it using the <code>require</code> function, you can now use it in your code. For example, call the <code>.createServer</code> property to create a server.</p>
<h3 id="heading-local-modules">Local Modules</h3>
<p>When you work with Node.js, you create local modules that you load and use in your program. Let's see how to do that.</p>
<p>Create a simple <code>sayHello</code> module. It takes a <code>userName</code> as a parameter and prints "hello" and the user's name.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sayHello</span>(<span class="hljs-params">userName</span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello <span class="hljs-subst">${userName}</span>!`</span>)
}

<span class="hljs-built_in">module</span>.exports = sayHello
</code></pre>
<p>First, you need to create the function. Then you export it using the syntax <code>module.exports</code>. It doesn't have to be a function, though. Your module can export an object, array, or any data type.</p>
<h4 id="heading-how-to-load-your-local-modules">How to load your local modules</h4>
<p>You can load your local modules and use them in other files. To do so, you use the <code>require</code> function as you did for the built-in modules.</p>
<p>But with your custom functions, you need to provide the path of the file as an argument. In this case, the path is <code>'./sayHello</code>' (which is referencing the <code>sayHello.js</code> file).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> sayHello = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./sayHello'</span>)
sayHello(<span class="hljs-string">"Maria"</span>) <span class="hljs-comment">// Hello Maria!</span>
</code></pre>
<p>Once you've loaded your module, you can make a reference to it in your code.</p>
<h3 id="heading-third-party-modules">Third-Party Modules</h3>
<p>A cool thing about using modules in Node.js is that you can share them with others. The Node Package Manager (NPM) makes that possible. When you install Node.js, NPM comes along with it.</p>
<p>With NPM, you can share your modules as packages via <a target="_blank" href="https://www.npmjs.com/">the NPM registry.</a> And you can also use packages others have shared.</p>
<h4 id="heading-how-to-use-third-party-packages">How to use third-party packages</h4>
<p>To use a third-party package in your application, you first need to install it. You can run the command below to install a package.</p>
<pre><code class="lang-javascript">npm install &lt;name-<span class="hljs-keyword">of</span>-package&gt;
</code></pre>
<p>For example, there's a package called <code>capitalize</code>. It performs functions like capitalizing the first letter of a word.</p>
<p>Running the command below will install the capitalize package:</p>
<pre><code class="lang-javascript">npm install capitalize
</code></pre>
<p>To use the installed package, you need to load it with the <code>require</code> function.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> capitalize = <span class="hljs-built_in">require</span>(<span class="hljs-string">'capitalize)</span>
</code></pre>
<p>And then you can use it in your code, like this for example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> capitalize = <span class="hljs-built_in">require</span>(<span class="hljs-string">'capitalize'</span>)
<span class="hljs-built_in">console</span>.log(capitalize(<span class="hljs-string">"hello"</span>)) <span class="hljs-comment">// Hello</span>
</code></pre>
<p>This is a simple example. But there are packages that perform more complex tasks and can save you loads of time.</p>
<p>For example, you can use the Express.js package which is a Node.js framework. It makes building apps faster and simple. To learn more about NPM, read this <a target="_blank" href="https://www.freecodecamp.org/news/what-is-npm-a-node-package-manager-tutorial-for-beginners/">freeCodeCamp article on the Node Package Manager</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned about what Node modules are and the three types of node modules. You also learned about how to use the different types in your application.</p>
<p>Thanks for reading. And happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
