<?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[ Joseph Mawa - 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[ Joseph Mawa - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 15 Jun 2026 23:29:35 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/josephmawa/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a React Admin Panel with Refine ]]>
                </title>
                <description>
                    <![CDATA[ React is a popular front-end framework for building interactive user interfaces. It has helped revolutionize the development of data-intensive front-end applications. React's declarative nature makes building user interfaces intuitive. And reusable R... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-an-react-admin-panel-with-refine/</link>
                <guid isPermaLink="false">66d45f69052ad259f07e4b06</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joseph Mawa ]]>
                </dc:creator>
                <pubDate>Fri, 03 Feb 2023 23:46:01 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/database-admin.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>React is a popular front-end framework for building interactive user interfaces. It has helped revolutionize the development of data-intensive front-end applications.</p>
<p>React's declarative nature makes building user interfaces intuitive. And reusable React components increase development speed and reduce time to production.</p>
<p>To further improve the development experience when building user interfaces, several React frameworks have emerged. One such framework is <a target="_blank" href="https://github.com/refinedev/refine">refine</a>.</p>
<p>refine is a React-based framework for building web applications. It is similar to <a target="_blank" href="https://marmelab.com/react-admin/">React-admin</a>, <a target="_blank" href="https://redwoodjs.com/">Redwood</a>, and <a target="_blank" href="https://retool.com/">Retool</a>.</p>
<p>The refine ecosystem comes with out-of-the-box integrations for user authentication, routing, networking, internalization, and more.</p>
<p>In this article, you will learn refine by building a simple admin panel. This will help highlight the main building blocks of the refine framework. We will also explore the main features and possible use cases of refine.</p>
<h2 id="heading-what-is-refine">What is refine?</h2>
<p>refine is an open-source, MIT-licensed React-based framework for building front-end applications. It is similar to React-admin, Retool, and Redwood. refine is a "headless" React framework. It is not opinionated about your styling and design choices.</p>
<p>This means that you can use refine with a custom design or a UI component library. It ships with integrations for the most popular component libraries and design systems, such as Material UI, Chakra UI, and Ant design.</p>
<p>refine has built-in router providers for the most popular routing libraries, such as React Router, Remix Router, Next.js Router, and React Location. You can choose a routing library that meets your project's requirements.</p>
<p>You can use refine to build data-intensive applications such as admin panels, dashboards, internal tools, and storefronts. The command line tool, which is part of the React ecosystem, can help you set up a refine application fast.</p>
<p>You can get up and running fast if you have beginner to intermediate knowledge of React, since refine is a React-based framework. You can also use refine with other React frameworks like Next and Remix.</p>
<h2 id="heading-prerequisites-development-tools">Prerequisites – Development Tools</h2>
<p>You will need the following tools to run some of the examples in this article.</p>
<h3 id="heading-the-node-runtime-environment">The Node runtime environment</h3>
<p>If you don't have Node, download and install it from the <a target="_blank" href="https://nodejs.org/en/download/">Node downloads</a> page. After installation, run the command below on the command line to check if the installation was successful.</p>
<pre><code class="lang-sh">node -v
</code></pre>
<p>The command above will display the Node version on your machine if the installation is successful.</p>
<p>Recent versions of Node also ship with <code>npm</code>. Run the command below on the terminal to be sure you have <code>npm</code>. It should display the version of <code>npm</code> that you installed with Node.</p>
<pre><code class="lang-sh">npm -v
</code></pre>
<h3 id="heading-a-text-editor">A text editor</h3>
<p>You will need a text editor like VS Code or Sublime Text. My favorite is VS Code. You can download it from the <a target="_blank" href="https://code.visualstudio.com/download">VS Code downloads</a> page. Alternatively, download Sublime Text for your system from the <a target="_blank" href="https://www.sublimetext.com/download">Sublime Text downloads</a> page.</p>
<h2 id="heading-how-to-set-up-a-refine-application">How to Set Up a refine Application</h2>
<p>You can set up a custom refine application or use the refine command line utility to bootstrap a refine application fast. If you are just starting out, I recommend you use the refine command line tool for a quick project setup.</p>
<p>The command line tool will create a refine project with all the required configurations. Follow the steps below to create a simple refine project using the command line tool. You should have the development tools I highlighted in the previous section to follow the steps below.</p>
<h3 id="heading-step-1-create-a-refine-application">Step 1 — Create a refine application</h3>
<p>Navigate to the directory where you want to create the refine application and run the command below on the command line. I am using <code>npm</code> as a package manager. But you can also use a different package manager.</p>
<p>Also note that if it is your first time creating a refine project, the command below will prompt you to install the <code>create-refine-app</code> package.</p>
<pre><code class="lang-sh">npm create refine-app@latest
</code></pre>
<p>The command above will launch the installation process. Respond to the prompts during the installation. I chose the <code>refine-react</code> project template, RESTful back-end integration, and Material UI as the UI framework for this project.</p>
<p>You will notice I have opted out of the other setup configurations.</p>
<pre><code class="lang-txt">✔ Downloaded remote source successfully.
✔ Choose a project template · refine-react
✔ What would you like to name your project?: · refine-demo
✔ Choose your backend service to connect: · data-provider-custom-json-rest
✔ Do you want to use a UI Framework?: · mui
✔ Do you want to add example pages?: · no
✔ Do you want to add dark mode support?: · no
✔ Do you want to customize the Material UI theme?: · no
✔ Do you want to customize the Material UI layout?: · no
✔ Do you need any Authentication logic?: · none
✔ Do you need i18n (Internationalization) support?: · no
✔ Do you want to add kbar command interface support?: · no
✔ Choose a package manager: · npm
✔ Would you mind sending us your choices so that we can improve superplate? · no
</code></pre>
<h3 id="heading-step-2-open-the-project-in-a-text-editor">Step 2 — Open the project in a text editor</h3>
<p>Once the installation is complete, open the project directory in a text editor. If you are using VS Code, use the <code>code</code> global command with the name of the project directory to open the project directory in VS Code.</p>
<p>The command below assumes that the name of your project directory is <code>refine-demo</code>.</p>
<pre><code class="lang-sh">code refine-demo
</code></pre>
<h3 id="heading-step-3-launch-the-development-server">Step 3 — Launch the development server</h3>
<p>You can start the development server by running the command below on the command line.</p>
<pre><code class="lang-sh">npm run dev
</code></pre>
<p>The above command will launch the development sever for your refine project in your default browser on localhost, port 3000. The welcome page should look like the screenshot below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/refine-project-template-landing-page.png" alt="refine project template landing page" width="600" height="400" loading="lazy"></p>
<h2 id="heading-main-concepts-in-refine">Main Concepts in refine</h2>
<p>You will encounter several possibly unfamiliar concepts when working with refine. Below are the explanations of some of these common concepts you might encounter.</p>
<h3 id="heading-data-providers">Data providers</h3>
<p>More often than not, you have to communicate with an API when building data-intensive front-end applications with React. Unlike React, refine abstracts HTTP requests to APIs in data providers.</p>
<p>A data provider makes network requests to an API and forwards the response to the component that needs it.</p>
<p>The refine ecosystem has data providers for REST API, GraphQL API, cloud databases like Firebase, and some of the popular headless content management systems like Strapi.</p>
<p>You can declare a custom data provider if you don't intend to use the data providers in the refine ecosystem. A refine data provider needs to have the shape and methods below.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> dataProvider = {
    create: <span class="hljs-function">(<span class="hljs-params">{ resource, variables, metaData }</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>,
    createMany: <span class="hljs-function">(<span class="hljs-params">{ resource, variables, metaData }</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>,
    deleteOne: <span class="hljs-function">(<span class="hljs-params">{ resource, id, variables, metaData }</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>,
    deleteMany: <span class="hljs-function">(<span class="hljs-params">{ resource, ids, variables, metaData }</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>,
    getList: <span class="hljs-function">(<span class="hljs-params">{
        resource,
        pagination,
        hasPagination,
        sort,
        filters,
        metaData,
    }</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>,
    getMany: <span class="hljs-function">(<span class="hljs-params">{ resource, ids, metaData }</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>,
    getOne: <span class="hljs-function">(<span class="hljs-params">{ resource, id, metaData }</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>,
    update: <span class="hljs-function">(<span class="hljs-params">{ resource, id, variables, metaData }</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>,
    updateMany: <span class="hljs-function">(<span class="hljs-params">{ resource, ids, variables, metaData }</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>,
    custom: <span class="hljs-function">(<span class="hljs-params">{
        url,
        method,
        sort,
        filters,
        payload,
        query,
        headers,
        metaData,
    }</span>) =&gt;</span> <span class="hljs-built_in">Promise</span>,
    getApiUrl: <span class="hljs-function">() =&gt;</span> <span class="hljs-string">""</span>,
};
</code></pre>
<p>The method names in a data provider are self-explanatory. The <code>create</code> method creates an item in a resource like its name suggests and returns a promise. And it takes several parameters. The other method names are self-descriptive too.</p>
<p>Your refine application interacts with data providers via data hooks. To perform a CRUD operation, you can trigger the methods in your data provider using data hooks.</p>
<h3 id="heading-data-hooks">Data hooks</h3>
<p>As pointed out above, you can trigger any of the methods in the data provider from a component using data hooks. Each method in a data provider has a corresponding data hook. For example, the <code>useCreate</code> hook triggers the <code>create</code> method in your data provider.</p>
<p>You can use the <code>useCreate</code> hook in your component like so:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { useCreate } <span class="hljs-keyword">from</span> <span class="hljs-string">"@pankod/refine-core"</span>;

<span class="hljs-keyword">const</span> MyComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { mutate } = useCreate();
  <span class="hljs-keyword">const</span> clickHandler = <span class="hljs-function">() =&gt;</span> {
    mutate({ resource: <span class="hljs-string">"posts"</span>, values: { title: <span class="hljs-string">"Refine hello world!"</span> } });
  };
  <span class="hljs-keyword">return</span> &lt;button onClick={clickHandler}&gt;Click to Create an item&lt;/button&gt;;
};
</code></pre>
<p>Though the <code>useCreate</code> hook returns an object with several properties, we are interested in the <code>mutate</code> function in the above example.</p>
<p>Invoking the <code>mutate</code> function like we did triggers the <code>create</code> method in your data provider. After that, the <code>create</code> method makes a network request to your API and forwards the response to your component.</p>
<p>There are several data hooks that you can look up in the <a target="_blank" href="https://refine.dev/docs/">Refine documentation</a>.</p>
<h3 id="heading-resources">Resources</h3>
<p>As hinted above, working with APIs is inevitable when building front-end applications. The API usually consists of resources you can access via endpoints and perform CRUD operations on.</p>
<p>The <code>Refine</code> component is the entry point for any refine application. When you create any refine application using <code>create-refine-app</code>, the <code>App.tsx</code> component will always render the <code>Refine</code> component like in the example below.</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;Refine
      dataProvider={dataProvider(apiUrl)}
      routerProvider={routerProvider}
      resources={[
        {
          name: <span class="hljs-string">"users"</span>,
          list: List,
          show: Show,
          create: Create,
          edit: Edit,
        },
      ]}
    /&gt;
  );
}
</code></pre>
<p>One of the props you pass to the<code>Refine</code> component is the <code>resources</code> prop. The value of the <code>resources</code> prop is an array of resource objects. Each resource object needs to have a <code>name</code> property.</p>
<p>As in the example above, you can pass additional properties such as <code>list</code>, <code>show</code>, <code>create</code>, and <code>edit</code>.</p>
<p>The values of <code>list</code>, <code>show</code>, <code>create</code>, and <code>edit</code> are components. In the example above, the value of the <code>name</code> field is <code>"users"</code>.</p>
<p>The <code>name</code> field determines the routes in your front-end application. When you navigate to the <code>/users</code> route in your app, refine will render the <code>List</code> component.</p>
<p>Similarly, when you navigate to the <code>/users/show</code> route, refine will render the <code>Show</code> component. The table below summarizes the relationship between the fields in the above resource object and the routes in your application.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Resource object property</td><td>Route</td><td>Rendered component</td></tr>
</thead>
<tbody>
<tr>
<td><code>list</code></td><td><code>/users</code></td><td><code>List</code></td></tr>
<tr>
<td><code>show</code></td><td><code>/users/show</code></td><td><code>Show</code></td></tr>
<tr>
<td><code>create</code></td><td><code>/users/create</code></td><td><code>Create</code></td></tr>
<tr>
<td><code>edit</code></td><td><code>/users/edit</code></td><td><code>Edit</code></td></tr>
</tbody>
</table>
</div><p>Instead of creating components from scratch, you can also generate them based on your resources using an <a target="_blank" href="https://refine.dev/docs/api-reference/mui/components/inferencer/">Inferencer</a>.</p>
<h3 id="heading-inferencer">Inferencer</h3>
<p><a target="_blank" href="https://refine.dev/docs/api-reference/mui/components/inferencer/">Inferencer</a> is one of the packages in the refine ecosystem of packages. It increases your development speed by generating CRUD pages after analyzing your data model. You can then customize the auto-generated components to meet the requirements of your project.</p>
<p>Instead of setting the values of the resource object properties <code>list</code>, <code>show</code>, <code>create</code>, and <code>edit</code> to a custom component like in the previous sub-section, the inferencer can generate the components for you. You can then customize the components to your needs.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { HeadlessInferencer } <span class="hljs-keyword">from</span> <span class="hljs-string">"@pankod/refine-inferencer/headless"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;Refine
      dataProvider={dataProvider(apiUrl)}
      routerProvider={routerProvider}
      resources={[
        {
          name: <span class="hljs-string">"topics"</span>,
          list: HeadlessInferencer,
          show: HeadlessInferencer,
          create: HeadlessInferencer,
          edit: HeadlessInferencer,
        },
      ]}
    /&gt;
  );
}
</code></pre>
<p>The code above assumes you are using <code>HeadlessInferencer</code>. You can also use <code>MuiInferencer</code> if you are using Material UI.</p>
<p>The Inferencer relies on the <code>@pankod/refine-react-hook-form</code> and <code>@pankod/refine-react-table</code> packages internally to generate forms and tables. So be sure to install them.</p>
<pre><code class="lang-sh">npm i @pankod/refine-react-table @pankod/refine-react-hook-form
</code></pre>
<h2 id="heading-how-to-build-an-admin-panel-with-refine">How to Build an Admin Panel with refine</h2>
<p>In this section, you will build a simple admin panel by modifying the refine app you created above.</p>
<p>Remember, we chose the RESTful API back-end integration while bootstrapping the app using <code>create-refine-app</code>. So we will use a <a target="_blank" href="https://api.fake-rest.refine.dev/">fake RESTful API</a> for this illustration.</p>
<p>In a real-world application, you will work with a different back-end integration. It can be a RESTful API, GraphQL API, cloud databases like Firebase, or a Content Management System like Strapi.</p>
<p>You need to read the <a target="_blank" href="https://refine.dev/docs/">refine documentation</a> on using the different back-end integrations available in the refine ecosystem.</p>
<p>The fake RESTful API has several endpoints for accessing the available resources. We will build an admin panel for the <a target="_blank" href="https://api.fake-rest.refine.dev/users">users</a> resource. Follow the steps below if you have opened the refine project we created at the beginning of this article in a text editor.</p>
<h3 id="heading-step-1-install-inferencer-dependencies">Step 1 — Install Inferencer dependencies</h3>
<p>We will use <code>MuiInferencer</code> to generate CRUD pages. The Inferencer relies on <code>@pankod/refine-react-hook-form</code> and <code>@pankod/refine-react-table</code> packages internally. Run the command below on the terminal to install them.</p>
<pre><code class="lang-sh">npm i @pankod/refine-react-table @pankod/refine-react-hook-form
</code></pre>
<h3 id="heading-step-2-import-muiinferencer">Step 2 — Import <code>MuiInferencer</code></h3>
<p>After successfully installing the required dependencies, open the <code>src/App.tsx</code> file and add the following import statement at the top:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { MuiInferencer } <span class="hljs-keyword">from</span> <span class="hljs-string">"@pankod/refine-inferencer/mui"</span>;
</code></pre>
<h3 id="heading-step-3-generate-components-using-inferencer">Step 3 — Generate components using Inferencer</h3>
<p>As explained under the "Main concepts" section, the values of the <code>list</code>, <code>show</code>, <code>create</code>, and <code>edit</code> properties of the <code>resource</code> object are components. You can create these components from scratch or generate them using Inferencer. In this example, we will use the <code>MuiInferencer</code> to create them.</p>
<p>In the <code>src/App.tsx</code> file, the <code>App</code> component renders the <code>Refine</code> built-in component. <code>Refine</code> is the entry point for any refine application. Add the <code>resources</code> prop to your <code>Refine</code> component so that the <code>App</code> component looks like so:</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;ThemeProvider theme={LightTheme}&gt;
      &lt;CssBaseline /&gt;
      &lt;GlobalStyles styles={{ html: { WebkitFontSmoothing: <span class="hljs-string">"auto"</span> } }} /&gt;
      &lt;RefineSnackbarProvider&gt;
        &lt;Refine
          dataProvider={dataProvider(<span class="hljs-string">"https://api.fake-rest.refine.dev"</span>)}
          notificationProvider={notificationProvider}
          Layout={Layout}
          ReadyPage={ReadyPage}
          catchAll={&lt;ErrorComponent /&gt;}
          routerProvider={routerProvider}
          resources = {[
            {
              name: <span class="hljs-string">'users'</span>,
              list: MuiInferencer,
              show: MuiInferencer,
              create: MuiInferencer,
              edit: MuiInferencer

            }
          ]}
        /&gt;
      &lt;/RefineSnackbarProvider&gt;
    &lt;/ThemeProvider&gt;
  );
}
}
</code></pre>
<h3 id="heading-step-4-preview-the-changes">Step 4 — Preview the changes</h3>
<h4 id="heading-view-the-list-of-users">View the list of users</h4>
<p>After saving the above changes, refine will generate the CRUD pages and redirect to the <code>/users</code> route. Your welcome page should look like the image below. The component generated by the Inferencer renders a table of users from the <code>users</code> resource.</p>
<p>The table has several columns, some of which are hidden from view if you use a small screen. Scroll horizontally to see all of them.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/users-list-page.png" alt="users list page" width="600" height="400" loading="lazy"></p>
<h4 id="heading-create-a-new-user">Create a new user</h4>
<p>You can also navigate to the <code>users/create</code> route to create a new user by clicking the "CREATE" button. refine will render the component generated by the Inferencer. It has a form that looks like the image below for creating a new user.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/create-new-user-page.png" alt="create new user page" width="600" height="400" loading="lazy"></p>
<h4 id="heading-update-an-existing-user">Update an existing user</h4>
<p>To update an existing resource, navigate to the <code>/users/edit/:id</code> route. The <code>id</code> route parameter should be the <code>id</code> of an object in the <code>users</code> resource.</p>
<p>To edit the details of the user whose <code>id</code> is 1, navigate to the <code>/users/edit/1</code> endpoint by clicking the edit button of the first record in the users table.</p>
<p>The edit button is under the last column labeled "Actions". The edit page should look like the image below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/edit-an-existing-user-page.png" alt="update an existing user page" width="600" height="400" loading="lazy"></p>
<h4 id="heading-view-a-specific-user">View a specific user</h4>
<p>To view the details of a user with a specific <code>id</code>, navigate to the <code>/users/show/:id</code> route. The <code>id</code> should be that of an existing object in the <code>users</code> resource.</p>
<p>To view the details of the first user, click the show button of the first record in the users table. The show button is under the last column labeled "Actions".</p>
<p>When you navigate to the <code>/users/show/1</code> endpoint, you should see the details of the first user whose <code>id</code> is 1.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/show-user-page.png" alt="view user page" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-5-view-the-code-generated-by-inferencer">Step 5 — View the code generated by Inferencer</h3>
<p>The Inferencer created components for us using the response from the <code>/users</code> endpoint of our fake RESTful API. In each of the pages you visited above, there is a button at the bottom right with the label "SHOW CODE".</p>
<p>Click it to display the code generated by the Inferencer for each page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/view-generated-code.png" alt="view code generated by Inferencer" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-6-customize-the-generated-components">Step 6 — Customize the generated components</h3>
<p>In the previous steps, you generated CRUD pages using <code>MuiInferencer</code>. Using <code>MuiInferencer</code> will get you up and running by generating the boilerplate code. But in a real-world application, you almost always want to customize the components to suit your needs.</p>
<p>To customize the generated code, create a <code>src/users</code> directory. In the <code>src/users</code> directory, create four files with the following names. You can name them differently if you want.</p>
<ul>
<li><p><code>List.tsx</code></p>
</li>
<li><p><code>Create.tsx</code></p>
</li>
<li><p><code>Edit.tsx</code></p>
</li>
<li><p><code>Show.tsx</code></p>
</li>
</ul>
<p>In the previous step, you learned how to view the generated code for each page.</p>
<p>Copy and paste the code for <code>/users</code> page in the <code>List.tsx</code> file you have created. In the same way, copy and paste the code for the <code>/users/create</code> page in the <code>Create.tsx</code> file. You do the same for the other pages and their corresponding components.</p>
<p>Import the components you have created above in your <code>App.tsx</code> like so:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { UserList } <span class="hljs-keyword">from</span> <span class="hljs-string">"users/List"</span>;
<span class="hljs-keyword">import</span> { UserCreate } <span class="hljs-keyword">from</span> <span class="hljs-string">"users/Create"</span>;
<span class="hljs-keyword">import</span> { UserShow  } <span class="hljs-keyword">from</span> <span class="hljs-string">"users/Show"</span>;
<span class="hljs-keyword">import</span> { UserEdit } <span class="hljs-keyword">from</span> <span class="hljs-string">"users/Edit"</span>;
</code></pre>
<p>In the <code>App.tsx</code> file, the <code>App</code> component renders the built-in <code>Refine</code> component. Modify the <code>resources</code> prop you are passing to the <code>Refine</code> component to look like so:</p>
<pre><code class="lang-ts">&lt;Refine
  ...
  resources={[
    {
      name: <span class="hljs-string">"users"</span>,
      list: UserList,
      show: UserShow,
      create: UserCreate,
      edit: UserEdit,
    },
  ]}
/&gt;;
</code></pre>
<p>Hopefully, you noticed how the values of the <code>list</code>, <code>show</code>, <code>create</code>, and <code>edit</code> properties of the resource object have changed from <code>MuiInferencer</code> to <code>UserList</code>, <code>UserShow</code>, <code>UserCreate</code>, and <code>UserEdit</code>, respectively. You can now modify the code in the components you have created.</p>
<p>That is just about how easy it is to create dashboards and admin panels with refine.</p>
<p>Within a few minutes, you have bootstrapped a project template based on your data model. You can then customize it further. Bootstrapping such a project from scratch would require a lot of work.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>refine is an open-source MIT-licensed React-based framework for building front-end applications. It comes in handy when building dashboards, admin panels, internal tools, and storefronts. You can use it pretty much in any application that uses React.</p>
<p>refine comes with out-of-the-box functionalities for networking, authentication, routing, and internationalization. It also has integrations for the most popular cloud databases, such as Firebase and Supabase, and content management systems, like Strapi.</p>
<p>If you are looking to start using refine, use the command line tool. With the command line tool, you can choose a headless setup or use one of the built-in component or design systems such as Material UI and Ant design.</p>
<p>Hopefully, this article has introduced you to the very basics of refine. refine has several other features and use cases that I haven't highlighted here. Check out the <a target="_blank" href="https://refine.dev/docs/">documentation</a> to fully understand refine and its capabilities.</p>
<h2 id="heading-further-reading">Further reading</h2>
<ul>
<li><p><a target="_blank" href="https://refine.dev/docs/">Refine documentation</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/refinedev">Refine project GitHub repository</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add a "Skip to Main Content" Link to Your Website ]]>
                </title>
                <description>
                    <![CDATA[ Websites and web applications have increasingly become more complex. But it's still our responsibility, as web developers, to strive for the highest level of accessibility we possibly can. This isn't always easy, as the range of user accessibility ne... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-skip-to-main-content-links-to-a-website/</link>
                <guid isPermaLink="false">66d45f67052ad259f07e4b02</guid>
                
                    <category>
                        <![CDATA[ a11y ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ best practices ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joseph Mawa ]]>
                </dc:creator>
                <pubDate>Wed, 20 Jul 2022 16:30:05 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/07/man-sitting-infront-of-conputer.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Websites and web applications have increasingly become more complex. But it's still our responsibility, as web developers, to strive for the highest level of accessibility we possibly can.</p>
<p>This isn't always easy, as the range of user accessibility needs can complicate things even further.</p>
<p>Thankfully, various guidelines exist for designing and building more accessible websites and web applications. This article will look at the seemingly mundane, lesser-known, and often overlooked web accessibility feature: the "skip to main content" link.</p>
<p>Because they are invisible by default, many users navigating a website using the usual point-and-click method won't even notice skip-to-main-content links. But these links are critical, as they make navigating complex and large websites simpler for keyboard-only and some screen reader users.</p>
<p>In the section below, we shall have a detailed look at "skip to main content" links and why you should consider implementing them in your website or web application.</p>
<h2 id="heading-what-are-skip-to-main-content-links">What are "Skip to Main Content" Links?</h2>
<p>Most websites usually come with navigation menus to make navigation easier. But although they make your website or web application navigable for the point-and-click users, navigation menus can also cause a poor user experience for keyboard-only and some screen reader users.</p>
<p>It is not uncommon for a typical website to have a navigation menu with up to ten menu items at the top of each web page. So a keyboard-only user will needlessly tab through all the navigation links before accessing the main content on pages they visit.</p>
<p>Some screen reader users may undergo a similar experience by traversing all the menu items before reaching the main content.</p>
<p>This creates a negative experience for your users. Adding skip-to-content links can make navigating such complex sites easier and less laborious for keyboard-only and some screen reader users.</p>
<p>A "skip to content" link is an ordinary link, usually before the main navigation menu at the top, linking to the main content on the web page. Since a point-and-click user doesn't need it, a "skip to main content link" is usually hidden and made visible when it is in focus.</p>
<p>It helps keyboard-only and screen reader users skip to the main content instead of traversing all the menu items. And this greatly improves their browsing experience.</p>
<p>The image below shows the skip-to-main-content link for the <a target="_blank" href="https://www.a11yproject.com/">a11y project</a>. As mentioned above, the skip-to-main-content link is visible only after being focused on.</p>
<p>To test it, navigate to <a target="_blank" href="https://www.a11yproject.com/">a11yproject.com</a> and hit the Tab key. The skip-to-main-content link immediately becomes visible. After that, you can hit the Enter key to skip the navigation menu.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/skip-to-main-content-link.png" alt="Skip to main content link on a11y project website" width="600" height="400" loading="lazy"></p>
<p><em>Skip to main content link on a11y project website</em></p>
<p>In the next section, we shall implement a simple skip-to-main-content link.</p>
<h2 id="heading-how-to-add-a-skip-to-main-content-link-to-your-site">How to Add a Skip to Main Content Link to Your Site</h2>
<p>Now that we know what "skip to main content" links are, let's look at how to implement them and some best practices when using them.</p>
<p>As already mentioned in the introduction, skip-to-main-content links are ordinary links.</p>
<p>But again, they are usually not visible to an ordinary point-and-click user. You can change the visibility of the skip-to-main-content link for the keyboard user when it is in focus.</p>
<p>The code below shows the markup for a typical navigation menu. A real-world application may be more complex with nested menu items in addition to the top-level menu items. But I have kept it simple in the example below.</p>
<pre><code class="lang-html">  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#main"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"skip-to-main-content-link"</span>&gt;</span>Skip to main content<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/about.html"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/blog.html"</span>&gt;</span>Blog<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/contact.html"</span>&gt;</span>Contact<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/portfolio.html"</span>&gt;</span>Portfolio<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"main"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Your sweet heading<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

      <span class="hljs-comment">&lt;!-- Page content goes here! --&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p>The first element of the <code>&lt;body&gt;</code> tag in the above example is the skip-to-main-content link. Its <code>href</code> attribute points to the <code>main</code> element via its <code>id</code> attribute. Clicking or pressing the Enter key when the skip-to-main-content link is in focus will scroll the main content into view in the viewport.</p>
<p>As pointed out in the previous section, the skip-to-main-content link is primarily for keyboard-only and some screen reader users. So we need to apply some styling to hide it from view when out of focus and display it when it receives focus.</p>
<p>So we select it using the given class and apply the styling below. You can hide and display the skip link with different styling. It doesn't have to be the same code as below.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.skip-to-main-content-link</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">left</span>: -<span class="hljs-number">9999px</span>;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">999</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
  <span class="hljs-attribute">background-color</span>: black;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
}
<span class="hljs-selector-class">.skip-to-main-content-link</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(-<span class="hljs-number">50%</span>);
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
}
</code></pre>
<p>You can also apply transition animation to your skip-to-main-content link, though I haven't included it in the example above.</p>
<h2 id="heading-good-practices-when-adding-a-skip-to-main-content-link">Good Practices When Adding a Skip to Main Content Link</h2>
<p>Though skip-to-main-content links are easy to implement, there are some potential problems that can easily slip by you.</p>
<p>Follow what I consider good practices below when implementing skip-to-main-content links. I have picked them up from the <a target="_blank" href="https://www.w3.org/TR/WCAG20-TECHS/G1.html">WCAG techniques</a>.</p>
<ul>
<li><p>If the skip to main content link is for skipping the main navigation menu at the top of a web page, it should be the first focusable element on the web page.</p>
</li>
<li><p>The text of the skip link should describe the intent. The text "Skip to main content" will usually suffice.</p>
</li>
<li><p>It is a requirement that the skip-to-content link is either always visible or visible when in focus. Since our skip-to-content link is for keyboard-only and some screen reader users, you can hide it and make it visible as we did in the example above.</p>
</li>
<li><p>The focus should shift to the main content after activating the skip link.</p>
</li>
</ul>
<p>It is worth pointing out that using skip links is not only limited to navigation menus. You can also implement links to help users skip focusable elements that are difficult or laborious to navigate with the keyboard.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>A navigation menu is a handy feature for navigating to different sections or pages of a website. And although it's meant to provide a better user experience, a navigation menu can become an accessibility obstacle for some users who only use the keyboard or who use a screen reader.</p>
<p>This is why it's a good idea to add skip-to-main-content links on each page. When users need to traverse the navigation menu items, they can use that link to bypass the navigation menu.</p>
<p>The skip-to-main-content link is an ordinary link that's invisible to the point-and-click user. It is visible to screen reader users and when in focus. Clicking it will shift focus to the main content on the web page.</p>
<p>Hopefully, this article has given you insights on skip-to-main-content links and how to implement them in your website or web application.</p>
<p>Accessibility is a journey. Every step you take in the right direction makes your site or web application more accessible. Implementing skip-to-main-content links is one such step. Take that step and make the web more accessible if you haven't. By doing so, you are enriching the digital experience for your clients.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ React Accessibility Tools – How to Build More Accessible React Apps ]]>
                </title>
                <description>
                    <![CDATA[ Making a website or web app accessible improves the user experience for people with disabilities and for all users as well. Since developers deal with tight deadlines and competing priorities, it is easy to accidentally ship unresolved accessibility ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/react-accessibility-tools-build-accessible-react-apps/</link>
                <guid isPermaLink="false">66d45f7051f567b42d9f846b</guid>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joseph Mawa ]]>
                </dc:creator>
                <pubDate>Mon, 27 Sep 2021 14:18:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/09/tool-box.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Making a website or web app accessible improves the user experience for people with disabilities and for all users as well.</p>
<p>Since developers deal with tight deadlines and competing priorities, it is easy to accidentally ship unresolved accessibility issues to production. And things becomes even more complex when working with JavaScript frameworks such as React which involves writing JSX.</p>
<p>But fortunately, there are tools that you can take advantage of to lint or evaluate common accessibility issues in your text editor or the browser.</p>
<p>This article will shed light on these existing accessibility tools and how you can use them to build more accessible React applications.</p>
<h2 id="heading-what-is-web-accessibility">What is web accessibility?</h2>
<p>A website or web app is said to be accessible if it doesn’t exclude people with disabilities from using it on account of their disability.</p>
<p>Having an accessible website removes barriers and ensures that both disabled and non-disabled persons have equal access to the web content and functionality.</p>
<p>The benefits of making your website accessible to people with disabilities will extend to all users including non-disabled persons.</p>
<h2 id="heading-why-you-should-pay-attention-to-accessibility">Why you should pay attention to accessibility</h2>
<p>I can't emphasize the importance of accessibility enough. If you don't pay attention to it right from the beginning of your project, you risk turning accessibility into a burden and an expensive one in the future if you start retrofitting.</p>
<p>Making your site accessible should be an integral part of your project right from the word go. It should not be an afterthought.</p>
<p>I have highlighted below why you need to focus on accessibility right from the beginning:</p>
<h3 id="heading-follows-seo-best-practices">Follows SEO best practices</h3>
<p>Some of the basic accessibility requirements such as using semantic HTML elements, proper use of heading elements, and adding descriptive <code>alt</code> attributes to <code>img</code> tags are also SEO best practices.</p>
<h3 id="heading-improves-ux-for-all-users">Improves UX for all users</h3>
<p>Improving accessibility for people with disabilities will improve the experience for all your users.</p>
<p>For example, adding a sufficient contrast ratio is not only helpful for people with low vision, color blindness, or cognitive impairment but it's also helpful to people working in different lighting conditions.</p>
<p>Similarly adding an <code>alt</code> attribute with appropriate text will help people using screen readers as well as those with slow internet connections when the image fails to load or takes too long to load.</p>
<h3 id="heading-its-the-right-thing-to-do">It's the right thing to do</h3>
<p>By making your website accessible, you are doing the right thing. They too have the right to access the service you are offering and some are your clients. Besides, it won’t be good for you or your business if you are accused of discrimination because your site is inaccessible to PWDs. It will damage your brand and reputation.</p>
<h3 id="heading-avoids-legal-issues">Avoids legal issues</h3>
<p>Finally, you might run into legal accessibility requirements depending on where you live and work. Some countries have legislation that requires websites to be accessible to people with disabilities.</p>
<h2 id="heading-accessibility-standards-and-guidelines">Accessibility standards and guidelines</h2>
<p>There are several different accessibility standards and guidelines. The most notable and widely recognized standards were developed by the <a target="_blank" href="https://www.w3.org/Consortium/">World Wide Web Consortium (W3C)</a> through its <a target="_blank" href="https://www.w3.org/WAI/about/">Web Accessibility Initiative (WAI)</a>.</p>
<p>I have highlighted some of these standards and guidelines in the sub-sections below.</p>
<h3 id="heading-web-content-accessibility-guidelines-wcag-21httpswwww3orgwaistandards-guidelineswcag"><a target="_blank" href="https://www.w3.org/WAI/standards-guidelines/wcag/">Web Content Accessibility Guidelines (WCAG) 2.1</a></h3>
<p>WCAG is one of the internationally recognized standards for web content accessibility.</p>
<p>It was developed by W3C through a participatory process with input from a number of individual and institutional stakeholders from around the world.</p>
<p>This standard explains how to make web content more accessible to people with disabilities. It has also been <a target="_blank" href="https://www.iso.org/standard/58625.html">ISO approved</a>.</p>
<p>According to W3C, WCAG was created primarily to serve as a go-to standard for individuals, organizations, and governments internationally on matters of web content accessibility.</p>
<h3 id="heading-authoring-tools-accessibility-guidelines-atag-20httpswwww3orgwaistandards-guidelinesatag"><a target="_blank" href="https://www.w3.org/WAI/standards-guidelines/atag/">Authoring Tools Accessibility Guidelines (ATAG) 2.0</a></h3>
<p>ATAG is a set of accessibility guidelines that you can use for designing tools for authoring web content.</p>
<p>This guideline helps you make sure that you produce authoring tools that are accessible to people with disabilities. The tools should, in turn, help authors create accessible web content.</p>
<h3 id="heading-user-agent-accessibility-guidelines-uaag-20httpswwww3orgwaistandards-guidelinesuaag"><a target="_blank" href="https://www.w3.org/WAI/standards-guidelines/uaag/">User Agent Accessibility Guidelines (UAAG) 2.0</a></h3>
<p>The UAAG 2.0 is a sister to the WCAG. This set of guidelines spell out how you can make browsers, browser extensions, media players, and other user agents accessible to people with disabilities.</p>
<p>It is used by browser vendors and browser extension makers to address certain accessibility issues such as text customization in the browser.</p>
<p>In the next section, we shall highlight a couple of tools that can help you flag basic accessibility issues in your React applications.</p>
<h2 id="heading-accessibility-tools-for-your-react-applications">Accessibility Tools for Your React Applications</h2>
<p>It is easy to unintentionally ship accessibility issues to production despite your best efforts to do otherwise. In this section, we'll shed light on some tools you can use to highlight common accessibility issues.</p>
<p>It might be tempting to omit certain accessibility features if you are dealing with tight deadlines. So it's helpful to have accessibility tools in your setup that notify you of accessibility defects you might have missed.</p>
<p>This is is by no means an exhaustive list of accessibility tools. If there are other tools that you think are useful but are not included here, do get in touch with me on <a target="_blank" href="https://twitter.com/mjmawa">Twitter</a>. I will be happy to update this article. Someone might find them useful too.</p>
<p>Though these tools will catch some common accessibility issues that you can measure programmatically, they won't do your job for you. It is your responsibility to make a deliberate effort to develop more accessible and inclusive digital products right from the project's conception.</p>
<p>I have categorized the tools we are going to cover into two categories, namely:</p>
<ul>
<li><p>Accessibility tools you can integrate into your React project that have been developed with React in mind.</p>
</li>
<li><p>General accessibility audit tools which you can use to audit sites built with or without React.</p>
</li>
</ul>
<p>In the sub-sections below, I'll highlight the tools that you can use in your React projects. They are purposely created for use with React or JSX.</p>
<h3 id="heading-accessibility-tools-built-for-react">Accessibility Tools Built for React</h3>
<h4 id="heading-eslint-plugin-jsx-a11yhttpsgithubcomjsx-eslinteslint-plugin-jsx-a11y"><a target="_blank" href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y">eslint-plugin-jsx-a11y</a></h4>
<p>You can use this tool for linting accessibility issues on JSX elements in your React projects. You can use it in conjunction with tools such as eslint for linting your project for accessibility standards right in your text editor.</p>
<p>Since it is distributed via npm, you can install it by running the command below in your project:</p>
<pre><code class="lang-sh"><span class="hljs-comment"># using npm as package manager</span>

npm install eslint-plugin-jsx-a11y --save-dev

<span class="hljs-comment"># using yarn as package manager</span>

yarn add eslint-plugin-jsx-a11y --dev
</code></pre>
<p>Any React project which you've created using <code>create-react-app</code> comes with this tool already configured – but it has only a subset of the configurable accessibility rules enabled by default.</p>
<p>You can enable additional rules by creating an <code>.eslintrc</code> configuration file in your project and adding the following code to it. The code below activates the recommended rules:</p>
<pre><code class="lang-js">
{
  <span class="hljs-string">"extends"</span>: [<span class="hljs-string">"react-app"</span>, <span class="hljs-string">"plugin:jsx-a11y/recommended"</span>],
  <span class="hljs-string">"plugins"</span>: [<span class="hljs-string">"jsx-a11y"</span>]
}
</code></pre>
<p>If you want to flag accessibility issues in a custom React project, you need to install <code>eslint</code> and add <code>"jsx-a11y"</code> to the plugins field of your <code>.eslintrc</code> configuration file.</p>
<p>It will then flag accessibility issues that it can identify programmatically and warn you right in your text editor depending on your configuration.</p>
<pre><code class="lang-js">
{  <span class="hljs-string">"plugins"</span>: [    <span class="hljs-string">"jsx-a11y"</span>  ]}
</code></pre>
<p>For more info about how to configure this linting tool in a custom React project, check the project <a target="_blank" href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#readme">README</a> on GitHub.</p>
<h4 id="heading-axe-accessibility-linterhttpsmarketplacevisualstudiocomitemsitemnamedeque-systemsvscode-axe-linter"><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=deque-systems.vscode-axe-linter">axe accessibility linter</a></h4>
<p>Axe accessibility linter is a Visual Studio Code extension that you can use for linting React, HTML, Vue, and Markdown for some common accessibility defects.</p>
<p>It checks for accessibility issues in <code>.js</code>, <code>.jsx</code>, <code>.ts</code>, <code>.tsx</code>, <code>.vue</code>, <code>.html</code>, <code>.htm</code>, <code>.md</code> and <code>.markdown</code> files.</p>
<p>You don’t need configuration to start using axe accessibility linter after installation. You install it from VS code marketplace and it automatically starts linting compatible files for accessibility defects out of the box without the need for additional configuration.</p>
<p>For a complete list of rules used by axe accessibility linter, check the extension page on VS Code marketplace.</p>
<p>You can also go ahead and configure the tool if you wish by turning some rules on and off by adding the <code>axe-linter.yml</code> configuration file at the root of your project.</p>
<p>You have an option of disabling accessibility rules individually or in a group using the WCAG standard. Using this feature in your project will ensure all members of your team adhere to the same accessibility standard.</p>
<p>You can add the following to your <code>axe-linter.yml</code> file to enable or disable certain rules individually. For a complete list of configurable rules, check the axe accessibility linter extension page at the VS Code marketplace.</p>
<pre><code class="lang-yml">
<span class="hljs-comment"># To enable/disable rules at individual level</span>
<span class="hljs-attr">rules:</span>
  <span class="hljs-attr">accessibility-rule:</span> <span class="hljs-literal">false</span> <span class="hljs-comment"># turn off rule</span>
  <span class="hljs-attr">another-accessibility-rule:</span> <span class="hljs-literal">true</span> <span class="hljs-comment"># turn on rule</span>
</code></pre>
<p>Alternatively, you can add the following to your <code>axe-linter.yml</code> configuration file to disable rules as a group using specific WCAG standards.</p>
<p>For a complete list of the configurable WCAG standards, check the axe accessibility linter extension page at the VS Code marketplace.</p>
<pre><code class="lang-yml">

<span class="hljs-comment"># To enable/disable rules at group level based on WCAG standard</span>

<span class="hljs-attr">tags:</span> 
  <span class="hljs-bullet">-</span> <span class="hljs-string">wcag2a</span> <span class="hljs-comment"># Disable all rules for WCAG 2.0 level A</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">wcag21a</span> <span class="hljs-comment"># Disable all rules for WCAG 2.1 level A</span>
</code></pre>
<h4 id="heading-axe-core-reacthttpswwwnpmjscompackageaxe-corereact"><a target="_blank" href="https://www.npmjs.com/package/@axe-core/react">axe-core-react</a></h4>
<p>This accessibility testing tool is developed and maintained by <a target="_blank" href="https://www.deque.com/">Deque Labs</a>, the same folks behind axe accessibility linter.</p>
<p><code>axe-core-react</code> was originally referred to as <code>react-axe</code>. You can run it in your React project in development and accessibility defects are highlighted in the Chrome DevTools console whenever your component updates.</p>
<p>It can really help you catch some accessibility issues early in development. At the moment, <code>axe-core-react</code> works best with Google chrome. Unlike the first two, it tests the accessibility of the rendered DOM instead of the JSX element you write in the React components.</p>
<pre><code class="lang-js">
npm install @axe-core/react --save-dev
</code></pre>
<p>You can then run the package in development after the installation.</p>
<p>The code below illustrates how you can run <code>axe-core-react</code> in your React application using the most basic configuration. There are additional configuration options which you can read about on the package <a target="_blank" href="https://github.com/dequelabs/axe-core-npm/blob/develop/packages/react/README.md">README</a> on GitHub.</p>
<pre><code class="lang-js">
<span class="hljs-keyword">const</span> React = <span class="hljs-built_in">require</span>(<span class="hljs-string">'react'</span>);
<span class="hljs-keyword">const</span> ReactDOM = <span class="hljs-built_in">require</span>(<span class="hljs-string">'react-dom'</span>);

<span class="hljs-comment">// Make sure to run @axe-core/react in development</span>

<span class="hljs-keyword">if</span> (process.env.NODE_ENV !== <span class="hljs-string">'production'</span>) {
  <span class="hljs-keyword">const</span> axe = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@axe-core/react'</span>);
  axe(React, ReactDOM, <span class="hljs-number">1000</span>);
}

ReactDOM.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</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">React.StrictMode</span>&gt;</span></span>,
  <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)
);
</code></pre>
<p>You can use the tools mentioned above directly in your React application to catch and fix common accessibility issues.</p>
<p>In the next section, we will look at a few other accessibility tools that are not directly related to React but are useful for identifying basic accessibility defects in a React application.</p>
<h3 id="heading-other-accessibility-tools">Other accessibility tools</h3>
<p>There are a number of tools out there that you can use to detect common accessibility issues in the browser. I have highlighted a couple of these tools below.</p>
<h4 id="heading-axe-devtools-browser-extensionhttpswwwdequecomaxe"><a target="_blank" href="https://www.deque.com/axe/">Axe DevTools browser extension</a></h4>
<p>This is a browser extension you can use for conducting a simple audit of your web page for common accessibility issues.</p>
<p>Your app needs to be hosted somewhere before using this browser extension to check for accessibility issues. It categorizes accessibility defects into critical, serious, moderate, and minor.</p>
<h4 id="heading-wave-evaluation-tool-browser-extensionhttpswavewebaimorgextension"><a target="_blank" href="https://wave.webaim.org/extension/">WAVE Evaluation Tool browser extension</a></h4>
<p>This is another chrome browser extension you can use to identify accessibility issues in your website.</p>
<p>Just like the Axe DevTools chrome browser extension, this extension requires you to host the app before you use it for auditing your web app for accessibility defects.</p>
<h4 id="heading-googles-lighthouse-in-chrome-devtoolshttpsdevelopersgooglecomwebtoolslighthouse"><a target="_blank" href="https://developers.google.com/web/tools/lighthouse">Google’s Lighthouse in Chrome DevTools</a></h4>
<p>You can use Google’s Lighthouse Chrome DevTools to audit your website for accessibility issues. It generates a report which you can use to fix defects in your website.</p>
<p>There is an endless list of general web accessibility evaluation tools out there. You can pick the one that meets your needs.</p>
<p>For a comprehensive list, you can check the <a target="_blank" href="https://www.w3.org/WAI/ER/tools/">web accessibility evaluation tools list by W3C</a> or <a target="_blank" href="https://www.a11yproject.com/resources/#tools">accessibility tools by a11y project</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Using tools such as eslint-plugin-jsx-a11y, axe accessibility linter, and axe-core-react in your project will go a long way in helping you develop more accessible and inclusive products using React.</p>
<p>Though they come in handy, the tools mentioned here will only flag a certain percentage of accessibility defects – mainly those that are possible to detect programmatically.</p>
<p>So it's really important to integrate automated testing, manual testing, and actual user testing in your development because automated testing alone may not be able to detect even 50 percent of accessibility issues in your project.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Scrape Websites with Node.js and Cheerio ]]>
                </title>
                <description>
                    <![CDATA[ There might be times when a website has data you want to analyze but the site doesn't expose an API for accessing those data. To get the data, you'll have to resort to web scraping. In this article, I'll go over how to scrape websites with Node.js an... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-scrape-websites-with-node-js-and-cheerio/</link>
                <guid isPermaLink="false">66d45f6da326133d12440a09</guid>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web scraping ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joseph Mawa ]]>
                </dc:creator>
                <pubDate>Mon, 19 Jul 2021 16:50:30 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/07/scraping-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>There might be times when a website has data you want to analyze but the site doesn't expose an API for accessing those data.</p>
<p>To get the data, you'll have to resort to <a target="_blank" href="https://en.wikipedia.org/wiki/Web_scraping">web scraping</a>.</p>
<p>In this article, I'll go over how to scrape websites with <a target="_blank" href="https://nodejs.dev/">Node.js</a> and <a target="_blank" href="https://cheerio.js.org/">Cheerio</a>.</p>
<p>Before we start, you should be aware that there are some <a target="_blank" href="https://monashdatafluency.github.io/python-web-scraping/section-5-legal-and-ethical-considerations/">legal and ethical issues</a> you should consider before scraping a site. It's your responsibility to make sure that it's okay to scrape a site before doing so.</p>
<p>The sites used in the examples throughout this article all allow scraping, so feel free to follow along.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Here are some things you'll need for this tutorial:</p>
<ul>
<li><p>You need to have <a target="_blank" href="https://nodejs.dev">Node.js</a> installed. If you don't have Node, just make sure you download it for your system from the <a target="_blank" href="https://nodejs.dev/download/">Node.js downloads page</a></p>
</li>
<li><p>You need to have a text editor like <a target="_blank" href="https://code.visualstudio.com/">VSCode</a> or <a target="_blank" href="https://atom.io/">Atom</a> installed on your machine</p>
</li>
<li><p>You should have at least a basic understanding of JavaScript, Node.js, and the Document Object Model (DOM). But you can still follow along even if you are a total beginner with these technologies. Feel free to ask questions on the <a target="_blank" href="https://forum.freecodecamp.org/">freeCodeCamp forum</a> if you get stuck</p>
</li>
</ul>
<h2 id="heading-what-is-web-scraping">What is Web Scraping?</h2>
<blockquote>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Web_scraping">Web scraping</a> is the process of extracting data from a web page. Though you can do web scraping manually, the term usually refers to automated data extraction from websites - <a target="_blank" href="\(https://en.wikipedia.org/wiki/Web_scraping\)">Wikipedia</a>.</p>
</blockquote>
<h2 id="heading-what-is-cheerio">What is Cheerio?</h2>
<p>Cheerio is a tool for parsing HTML and XML in Node.js, and is very popular with over <a target="_blank" href="https://github.com/cheeriojs/cheerio">23k stars</a> on GitHub.</p>
<p>It is fast, flexible, and easy to use. Since it implements a subset of JQuery, it's easy to start using Cheerio if you're already familiar with JQuery.</p>
<p>According to the <a target="_blank" href="https://cheerio.js.org/">documentation</a>, Cheerio parses markup and provides an API for manipulating the resulting data structure but does not interpret the result like a web browser.</p>
<blockquote>
<p>The major difference between cheerio and a web browser is that cheerio does not produce visual rendering, load CSS, load external resources or execute JavaScript. It simply parses markup and provides an API for manipulating the resulting data structure. That explains why it is also very fast - <a target="_blank" href="https://cheerio.js.org/">cheerio documentation</a>.</p>
</blockquote>
<p>If you want to use cheerio for scraping a web page, you need to first fetch the markup using packages like <a target="_blank" href="https://axios-http.com/docs/intro">axios</a> or <a target="_blank" href="https://www.npmjs.com/package/node-fetch">node-fetch</a> among others.</p>
<h2 id="heading-how-to-scrape-a-web-page-in-node-using-cheerio">How to Scrape a Web Page in Node Using Cheerio</h2>
<p>In this section, you will learn how to scrape a web page using cheerio. It is important to point out that before scraping a website, make sure you have permission to do so – or you might find yourself violating terms of service, breaching copyright, or violating privacy.</p>
<p>In this example, we will scrape the <a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3#:~:text=ISO%203166%2D1%20alpha%2D3%20codes%20are%20three%2Dletter,special%20areas%20of%20geographical%20interest.">ISO 3166-1 alpha-3 codes</a> for all countries and other jurisdictions as listed on <a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3">this Wikipedia page</a>. It is under the <strong>Current codes</strong> section of the <a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3">ISO 3166-1 alpha-3</a> page.</p>
<p>This is what the list of countries/jurisdictions and their corresponding codes look like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/007-05-list-of-countries.png" alt="list of countries and corresponding codes" width="600" height="400" loading="lazy"></p>
<p>You can follow the steps below to scrape the data in the above list.</p>
<h3 id="heading-step-1-create-a-working-directory">Step 1 - Create a Working Directory</h3>
<p>In this step, you will create a directory for your project by running the command below on the terminal. The command will create a directory called <code>learn-cheerio</code>. You can give it a different name if you wish.</p>
<pre><code class="lang-sh">mkdir learn-cheerio
</code></pre>
<p>You should be able to see a folder named <code>learn-cheerio</code> created after successfully running the above command.</p>
<p>In the next step, you will open the directory you have just created in your favorite text editor and initialize the project.</p>
<h3 id="heading-step-2-initialize-the-project">Step 2 - Initialize the Project</h3>
<p>In this step, you will navigate to your project directory and initialize the project. Open the directory you created in the previous step in your favorite text editor and initialize the project by running the command below.</p>
<pre><code class="lang-js">npm init -y
</code></pre>
<p>Successfully running the above command will create a <code>package.json</code> file at the root of your project directory.</p>
<p>In the next step, you will install project dependencies.</p>
<h3 id="heading-step-3-install-dependencies">Step 3 - Install Dependencies</h3>
<p>In this step, you will install project dependencies by running the command below. This will take a couple of minutes, so just be patient.</p>
<pre><code class="lang-js">npm i axios cheerio pretty
</code></pre>
<p>Successfully running the above command will register three dependencies in the <code>package.json</code> file under the <code>dependencies</code> field. The first dependency is <code>axios</code>, the second is <code>cheerio</code>, and the third is <code>pretty</code>.</p>
<p><a target="_blank" href="https://axios-http.com/docs/intro">axios</a> is a very popular <a target="_blank" href="https://stackoverflow.com/questions/49950973/difference-between-http-client-and-rest-client">http client</a> which works in node and in the browser. We need it because cheerio is a markup parser.</p>
<p>For cheerio to parse the markup and scrape the data you need, we need to use <code>axios</code> for fetching the markup from the website. You can use another HTTP client to fetch the markup if you wish. It doesn't necessarily have to be <code>axios</code>.</p>
<p><a target="_blank" href="https://www.npmjs.com/package/pretty">pretty</a> is npm package for beautifying the markup so that it is readable when printed on the terminal.</p>
<p>In the next section, you will inspect the markup you will scrape data from.</p>
<h3 id="heading-step-4-inspect-the-web-page-you-want-to-scrape">Step 4 - Inspect the Web Page You Want to Scrape</h3>
<p>Before you scrape data from a web page, it is very important to understand the HTML structure of the page.</p>
<p>In this step, you will inspect the HTML structure of the web page you are going to scrape data from.</p>
<p>Navigate to <a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3">ISO 3166-1 alpha-3 codes</a> page on Wikipedia. Under the "Current codes" section, there is a list of countries and their corresponding codes. You can open the DevTools by pressing the key combination <code>CTRL + SHIFT + I</code> on chrome or right-click and then select "Inspect" option.</p>
<p>This is what the list looks like for me in chrome DevTools:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/007-04-dev-tool.png" alt="List in chrome devtools" width="600" height="400" loading="lazy"></p>
<p>In the next section, you will write code for scraping the web page.</p>
<h3 id="heading-step-5-write-the-code-to-scrape-the-data">Step 5 - Write the Code to Scrape the Data</h3>
<p>In this section, you will write code for scraping the data we are interested in. Start by running the command below which will create the <code>app.js</code> file.</p>
<pre><code class="lang-js">touch app.js
</code></pre>
<p>Successfully running the above command will create an <code>app.js</code> file at the root of the project directory.</p>
<p>Like any other Node package, you must first <em>require</em> <code>axios</code>, <code>cheerio</code>, and <code>pretty</code> before you start using them. You can do so by adding the code below at the top of the <code>app.js</code> file you have just created.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);
<span class="hljs-keyword">const</span> cheerio = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cheerio"</span>);
<span class="hljs-keyword">const</span> pretty = <span class="hljs-built_in">require</span>(<span class="hljs-string">"pretty"</span>);
</code></pre>
<p>Before we write code for scraping our data, we need to learn the basics of <code>cheerio</code>. We'll parse the markup below and try manipulating the resulting data structure. This will help us learn cheerio syntax and its most common methods.</p>
<p>The markup below is the <code>ul</code> element containing our <code>li</code> elements.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> markup = <span class="hljs-string">`
&lt;ul class="fruits"&gt;
  &lt;li class="fruits__mango"&gt; Mango &lt;/li&gt;
  &lt;li class="fruits__apple"&gt; Apple &lt;/li&gt;
&lt;/ul&gt;
`</span>;
</code></pre>
<p>Add the above variable declaration to the <code>app.js</code> file</p>
<h2 id="heading-how-to-load-markup-in-cheerio">How to Load Markup in Cheerio</h2>
<p>You can load markup in <code>cheerio</code> using the <code>cheerio.load</code> method. The method takes the markup as an argument. It also takes two more optional arguments. You can read more about them <a target="_blank" href="https://cheerio.js.org/">in the documentation</a> if you are interested.</p>
<p>Below, we are passing the first and the only required argument and storing the returned value in the <code>$</code> variable. We are using the <code>$</code> variable because of cheerio's similarity to <a target="_blank" href="https://jquery.com/">Jquery</a>. You can use a different variable name if you wish.</p>
<p>Add the code below to your <code>app.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> $ = cheerio.load(markup);
<span class="hljs-built_in">console</span>.log(pretty($.html()));
</code></pre>
<p>If you now execute the code in your <code>app.js</code> file by running the command <code>node app.js</code> on the terminal, you should be able to see the markup on the terminal. This is what I see on my terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/007-01-cheerio-html.png" alt="Markup terminal output" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-select-an-element-in-cheerio">How to Select an Element in Cheerio</h2>
<p>Cheerio supports most of the common CSS selectors such as the <code>class</code>, <code>id</code>, and <code>element</code> selectors among others. In the code below, we are selecting the element with class <code>fruits__mango</code> and then logging the selected element to the console. Add the code below to your <code>app.js</code> file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> mango = $(<span class="hljs-string">".fruits__mango"</span>);
<span class="hljs-built_in">console</span>.log(mango.html()); <span class="hljs-comment">// Mango</span>
</code></pre>
<p>The above lines of code will log the text <code>Mango</code> on the terminal if you execute <code>app.js</code> using the command <code>node app.js</code>.</p>
<h2 id="heading-how-to-get-the-attribute-of-an-element-in-cheerio">How to Get the Attribute of an Element in Cheerio</h2>
<p>You can also select an element and get a specific attribute such as the <code>class</code>, <code>id</code>, or all the attributes and their corresponding values.</p>
<p>Add the code below to your <code>app.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> apple = $(<span class="hljs-string">".fruits__apple"</span>);
<span class="hljs-built_in">console</span>.log(apple.attr(<span class="hljs-string">"class"</span>)); <span class="hljs-comment">//fruits__apple</span>
</code></pre>
<p>The above code will log <code>fruits__apple</code> on the terminal. <code>fruits__apple</code> is the class of the selected element.</p>
<h2 id="heading-how-to-loop-through-a-list-of-elements-in-cheerio">How to Loop Through a List of Elements in Cheerio</h2>
<p>Cheerio provides the <code>.each</code> method for looping through several selected elements.</p>
<p>Below, we are selecting all the <code>li</code> elements and looping through them using the <code>.each</code> method. We log the text content of each list item on the terminal.</p>
<p>Add the code below to your <code>app.js</code> file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> listItems = $(<span class="hljs-string">"li"</span>);
<span class="hljs-built_in">console</span>.log(listItems.length); <span class="hljs-comment">// 2</span>
listItems.each(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">idx, el</span>) </span>{
  <span class="hljs-built_in">console</span>.log($(el).text());
});
<span class="hljs-comment">// Mango</span>
<span class="hljs-comment">// Apple</span>
</code></pre>
<p>The above code will log <code>2</code>, which is the length of the list items, and the text <code>Mango</code> and <code>Apple</code> on the terminal after executing the code in <code>app.js</code>.</p>
<h2 id="heading-how-to-append-or-prepend-an-element-to-a-markup-in-cheerio">How to Append or Prepend an Element to a Markup in Cheerio</h2>
<p>Cheerio provides a method for appending or prepending an element to a markup.</p>
<p>The <code>append</code> method will add the element passed as an argument after the last child of the selected element. On the other hand, <code>prepend</code> will add the passed element before the first child of the selected element.</p>
<p>Add the code below to your <code>app.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ul = $(<span class="hljs-string">"ul"</span>);
ul.append(<span class="hljs-string">"&lt;li&gt;Banana&lt;/li&gt;"</span>);
ul.prepend(<span class="hljs-string">"&lt;li&gt;Pineapple&lt;/li&gt;"</span>);
<span class="hljs-built_in">console</span>.log(pretty($.html()));
</code></pre>
<p>After appending and prepending elements to the markup, this is what I see when I log <code>$.html()</code> on the terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/007-02-append-prepend.png" alt="Append or prepend terminal output" width="600" height="400" loading="lazy"></p>
<p>Those are the basics of cheerio that can get you started with web scraping.</p>
<p>To scrape the data we described at the beginning of this article from Wikipedia, copy and paste the code below in the <code>app.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Loading the dependencies. We don't need pretty</span>
<span class="hljs-comment">// because we shall not log html to the terminal</span>
<span class="hljs-keyword">const</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);
<span class="hljs-keyword">const</span> cheerio = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cheerio"</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">// URL of the page we want to scrape</span>
<span class="hljs-keyword">const</span> url = <span class="hljs-string">"https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3"</span>;

<span class="hljs-comment">// Async function which scrapes the data</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scrapeData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Fetch HTML of the page we want to scrape</span>
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(url);
    <span class="hljs-comment">// Load HTML we fetched in the previous line</span>
    <span class="hljs-keyword">const</span> $ = cheerio.load(data);
    <span class="hljs-comment">// Select all the list items in plainlist class</span>
    <span class="hljs-keyword">const</span> listItems = $(<span class="hljs-string">".plainlist ul li"</span>);
    <span class="hljs-comment">// Stores data for all countries</span>
    <span class="hljs-keyword">const</span> countries = [];
    <span class="hljs-comment">// Use .each method to loop through the li we selected</span>
    listItems.each(<span class="hljs-function">(<span class="hljs-params">idx, el</span>) =&gt;</span> {
      <span class="hljs-comment">// Object holding data for each country/jurisdiction</span>
      <span class="hljs-keyword">const</span> country = { <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>, <span class="hljs-attr">iso3</span>: <span class="hljs-string">""</span> };
      <span class="hljs-comment">// Select the text content of a and span elements</span>
      <span class="hljs-comment">// Store the textcontent in the above object</span>
      country.name = $(el).children(<span class="hljs-string">"a"</span>).text();
      country.iso3 = $(el).children(<span class="hljs-string">"span"</span>).text();
      <span class="hljs-comment">// Populate countries array with country data</span>
      countries.push(country);
    });
    <span class="hljs-comment">// Logs countries array to the console</span>
    <span class="hljs-built_in">console</span>.dir(countries);
    <span class="hljs-comment">// Write countries array in countries.json file</span>
    fs.writeFile(<span class="hljs-string">"coutries.json"</span>, <span class="hljs-built_in">JSON</span>.stringify(countries, <span class="hljs-literal">null</span>, <span class="hljs-number">2</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>.error(err);
        <span class="hljs-keyword">return</span>;
      }
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Successfully written data to file"</span>);
    });
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err);
  }
}
<span class="hljs-comment">// Invoke the above function</span>
scrapeData();
</code></pre>
<p>Do you understand what is happening by reading the code? If not, I'll go into some detail now. I have also made comments on each line of code to help you understand.</p>
<p>In the above code, we <strong>require</strong> all the dependencies at the top of the <code>app.js</code> file and then we declared the <code>scrapeData</code> function. Inside the function, the markup is fetched using <code>axios</code>. The fetched HTML of the page we need to scrape is then loaded in <code>cheerio</code>.</p>
<p>The list of countries/jurisdictions and their corresponding <code>iso3</code> codes are nested in a <code>div</code> element with a class of <code>plainlist</code>. The <code>li</code> elements are selected and then we loop through them using the <code>.each</code> method. The data for each country is scraped and stored in an array.</p>
<p>After running the code above using the command <code>node app.js</code>, the scraped data is written to the <code>countries.json</code> file and printed on the terminal. This is part of what I see on my terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/007-03-terminal-output.png" alt="Terminal output" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Thank you for reading this article and reaching the end! We have covered the basics of web scraping using <code>cheerio</code>. You can head over to the <a target="_blank" href="https://cheerio.js.org/">cheerio documentation</a> if you want to dive deeper and fully understand how it works.</p>
<p>Feel free to ask questions on the <a target="_blank" href="https://forum.freecodecamp.org/">freeCodeCamp forum</a> if there is anything you don't understand in this article.</p>
<p>Finally, remember to consider the <a target="_blank" href="https://towardsdatascience.com/ethics-in-web-scraping-b96b18136f01">ethical concerns</a> as you learn web scraping.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Schedule a Job in Node Using node-cron ]]>
                </title>
                <description>
                    <![CDATA[ In this article, you will learn how to schedule a job in Node using node-cron. Node-cron is a handy npm package which you can use to schedule jobs to run at specific times or intervals. It is most suitable for scheduling repetitive jobs such as email... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/schedule-a-job-in-node-with-nodecron/</link>
                <guid isPermaLink="false">66d45f73264384a65d5a956c</guid>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joseph Mawa ]]>
                </dc:creator>
                <pubDate>Tue, 06 Jul 2021 14:27:26 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/07/schedule.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, you will learn how to schedule a job in Node using <a target="_blank" href="\(https://www.npmjs.com/package/node-cron\)">node-cron</a>.</p>
<p>Node-cron is a handy <a target="_blank" href="https://www.npmjs.com/package/package">npm package</a> which you can use to schedule jobs to run at specific times or intervals. It is most suitable for scheduling repetitive jobs such as email notifications, file downloads, and database backups.</p>
<p>Even if you are not interested in scheduling a job in Node, you may still find the knowledge you gain from this article about cron syntax very useful.</p>
<p>For example, Github Actions uses <a target="_blank" href="https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#onschedule">cron syntax</a> when scheduling a workflow to run at a specific time. Similarly, cloud platforms such as Google Cloud require <a target="_blank" href="https://cloud.google.com/scheduler/docs/configuring/cron-job-schedules">cron syntax</a> when describing job schedules.</p>
<p>Node-cron is written for <a target="_blank" href="https://nodejs.dev/">node</a> in pure JavaScript and it is based on <a target="_blank" href="https://www.gnu.org/software/mcron/manual/html_node/Crontab-file.html">GNU crontab</a> syntax. Though it is based on crontab, our focus in this article will be on learning node-cron and cron syntax.</p>
<p>For more about cron, crontab, and how they are used in Unix-like operating systems, you can take a look at <a target="_blank" href="https://en.wikipedia.org/wiki/Cron">this Wikipedia article</a> on the topic (but you don't have to know it to follow along with this article).</p>
<h2 id="heading-what-you-will-learn-in-this-article">What you will learn in this article</h2>
<p>By the end of this article, you will be able to do the following:</p>
<ul>
<li><p>Explain the <a target="_blank" href="https://en.wikipedia.org/wiki/Cron">cron</a> syntax</p>
</li>
<li><p>Schedule jobs using node-cron</p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before proceeding, make sure you have the prerequisites completed that are outlined below.</p>
<ul>
<li><p>You need to have the JavaScript runtime environment <a target="_blank" href="https://nodejs.dev/download">Node</a> installed on your machine.</p>
</li>
<li><p>You should have at least a basic understanding of JavaScript and Node. If you are a total beginner with Node and JavaScript, you can ask questions on the <a target="_blank" href="https://forum.freecodecamp.org/">freeCodeCamp forum</a> if you get stuck. We shall be happy to help.</p>
</li>
</ul>
<h2 id="heading-how-to-use-node-cron-to-schedule-a-job">How to Use <code>node-cron</code> to Schedule a Job</h2>
<p>As I already mentioned above, <a target="_blank" href="https://www.npmjs.com/package/node-cron"><code>node-cron</code></a> was written for Node and is distributed via <a target="_blank" href="https://www.npmjs.com/">npm</a>. After installation using the command <code>npm i node-cron</code>, it must be <em>required</em> into the project like any other Node package:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> nodeCron = <span class="hljs-built_in">require</span>(<span class="hljs-string">"node-cron"</span>);
</code></pre>
<p>To schedule a job, you need to invoke the <code>nodeCron.schedule</code> method with two arguments. There is a third optional argument that you can pass to the method for additional configuration.</p>
<p>Below is the function signature for the <code>nodeCron.schedule</code> method.</p>
<pre><code class="lang-js">nodeCron.schedule(expression, <span class="hljs-function"><span class="hljs-keyword">function</span>, <span class="hljs-title">options</span>);</span>
</code></pre>
<p>The code snippet below is an example of how you can invoke the <code>schedule</code> method.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> job = nodeCron.schedule(<span class="hljs-string">"* * * * * *"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">jobYouNeedToExecute</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Do whatever you want in here. Send email, Make  database backup or download data.</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString());
});
</code></pre>
<p>The first argument you need to pass to <code>nodeCron.schedule</code> is the cron expression. You use this expression to specify the time (or times) at which the job should be executed.</p>
<p>This expression should be in the <code>* * * * * *</code> format. You can replace each <code>*</code> field with an appropriate number (or characters where possible) so that the expression describes the time at which the job should be executed.</p>
<p>If you pass <code>"* * * * * *"</code> without replacing any <code>*</code>, like in the above example, the job gets executed every second. For a detailed explanation of how to come up with a cron expression, read the "How to understand cron expressions" sub-section below.</p>
<p>The second argument is a function and it is the job that gets executed when the expression in the first argument ticks.</p>
<p>You can do whatever you want in this function. You can send an email, make a database backup, or download data. This function gets executed when the current system time is the same as the time provided in the first argument. In the above example, I am just printing the current date.</p>
<p>And the third argument is an optional configuration object for job scheduling. I didn't pass the third argument in the above example since it is optional.</p>
<p>Below is an example of what the third argument looks like.</p>
<pre><code class="lang-js">{
   <span class="hljs-attr">scheduled</span>: <span class="hljs-literal">false</span>,
   <span class="hljs-attr">timezone</span>: <span class="hljs-string">"America/Sao_Paulo"</span>
}
</code></pre>
<p>By default <code>scheduled</code> is <code>true</code>. If you set it to <code>false</code>, you will have to schedule the job by invoking the <code>start</code> method on the <code>job</code> object. <code>job</code> is the object returned by a call to the <code>schedule</code> method.</p>
<pre><code class="lang-js">job.start();
</code></pre>
<p>The default <code>timezone</code> we use is for the system on which the job is scheduled. You can pass a different <code>timezone</code> if you wish.</p>
<h2 id="heading-how-to-understand-cron-expressions">How to Understand Cron Expressions</h2>
<p>The cron expression, which is the first argument to <code>schedule</code>, is a string that takes the form <code>"* * * * * *"</code>. We use it to describe the time at which the job should be executed. Each <code>*</code> in the expression is a field and you can see the field represented by each <code>*</code> in the illustration below.</p>
<pre><code class="lang-shell">"* * * * * *"
 | | | | | |
 | | | | | |
 | | | | | day of week
 | | | | month
 | | | day of month
 | | hour
 | minute
 second(optional)
</code></pre>
<p>As you can see from the above illustration, the first field is the <code>second</code> field, the second field is the <code>minute</code> field, and the third is the <code>hour</code> field, and so on.</p>
<p>The table below shows the fields and their corresponding allowed values:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Field</td><td>Allowed values</td></tr>
</thead>
<tbody>
<tr>
<td>second</td><td>0 - 59</td></tr>
<tr>
<td>minute</td><td>0 - 59</td></tr>
<tr>
<td>hour</td><td>0 - 23</td></tr>
<tr>
<td>day of month</td><td>1 - 31</td></tr>
<tr>
<td>month</td><td>1 - 12 or names</td></tr>
<tr>
<td>day of week</td><td>0 - 7 or names, 0 and 7 refer to sunday</td></tr>
</tbody>
</table>
</div><blockquote>
<p>The job is executed when the second, minute, hour, and month fields match the current time, <strong>and</strong> when at least one of the two day fields (day of month, or day of week) match the current time. – <a target="_blank" href="https://www.gnu.org/software/mcron/manual/html_node/Crontab-file.html">crontab documentation</a></p>
</blockquote>
<p>There are different ways to populate the fields in a cron expression. Each field in a Node expression can be populated using single integer values, a range of values, multiple values separated by commas, step values, or using names (as explained in the sub-sections below).</p>
<h3 id="heading-how-to-use-single-integer-values-to-populate-a-chron-expression">How to Use Single Integer Values to Populate a Chron Expression</h3>
<p>You can replace each asterisk with a single integer value in the allowed range of values.</p>
<p>For example, passing <code>"30 20 * * * *"</code> will make node-cron run your job at the thirtieth second of the twentieth minute of each hour. Since you didn't specify a value for the hour field, node-cron interprets <code>*</code> to mean every hour. The same applies to the <code>day of the month</code> field, and so on.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> job = nodeCron.schedule(<span class="hljs-string">"30 20 * * * *"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString());
});
</code></pre>
<p>Similarly, passing <code>"30 5 13 * * *"</code> will run your task at 1:05:30pm every day.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> job = nodeCron.schedule(<span class="hljs-string">"30 5 13 * * *"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString());
});
</code></pre>
<h3 id="heading-how-to-use-a-range-of-values-to-populate-chron-expressions">How to Use a Range of Values to Populate Chron Expressions</h3>
<p>You an also use ranges of numbers to populate your chron expressions. A range refers to two numbers separated by the <code>-</code> character. The end values are part of the range.</p>
<p>For example, if the <code>hour</code> field is set to<code>2-4</code>, it specifies execution at hours 2, 3, and 4.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> job = nodeCron.schedule(<span class="hljs-string">"* 2-4 3 * *"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString());
});
</code></pre>
<p>In the above code snippet, I have excluded the optional <code>second</code> field. It will execute your job every minute from 2 am to 4 am on the third day (because the <code>day of the month</code> field has a value of <code>3</code>) of each month.</p>
<h3 id="heading-how-to-use-multiple-values-to-populate-chron-expressions">How to Use Multiple Values to Populate Chron Expressions</h3>
<p>You can also pass multiple values separated by commas or a range of values separated by commas.</p>
<p>For example, passing <code>2,3,4</code> as the value of the <code>minute</code> field will execute your job at minutes 2, 3, and 4.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> job = nodeCron.schedule(<span class="hljs-string">"2,3,4 * * * *"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString());
});
</code></pre>
<p>In the above code snippet, I have again excluded the optional <code>second</code> field. It will execute your job at the first, second, and third minutes of each hour.</p>
<h3 id="heading-how-to-use-step-values-to-populate-chrone-expressions">How to Use Step Values to Populate Chrone Expressions</h3>
<p>You can use step values with ranges. Following a range with <code>/&lt;number&gt;</code> skips the number's value through the range.</p>
<p>For example, using <code>0-8/2</code> in the <code>hour</code> field will execute the code at 0,2,4,6 and 8 hours. You can also use step values with <code>*</code>. For example <code>*/3</code> executes every three hours.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> job = nodeCron.schedule(<span class="hljs-string">"*/2 * * * *"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString());
});
</code></pre>
<p>In the above code snippet, the job will be executed every two minutes. Once again I've omitted the optional <code>second</code> field.</p>
<h3 id="heading-how-to-use-names-to-populate-chron-expressions">How to Use Names to Populate Chron Expressions</h3>
<p>For the month and day of the week fields, you can use names. These can be short or long names. For example <code>January</code> or <code>Jan</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> job = nodeCron.schedule(<span class="hljs-string">"* * * January,September Sunday"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleString());
});
</code></pre>
<p>Once again I have omitted the optional <code>second</code> field. The job will run every minute on Sundays in January and September. You can also use short names like <code>Jan, Sep</code>.</p>
<p>That is all you need to know about the basics of cron syntax. In the next section, you will implement what you have learned to schedule a simple job.</p>
<blockquote>
<p>There is a handy tool called <a target="_blank" href="https://crontab.guru/">crontab guru</a> which can interpret crontab expressions for you. If you enter an expression, it will validate the expression and tell you when the job will be executed. You can use it if you are not sure of the expression.</p>
</blockquote>
<h2 id="heading-how-to-schedule-a-job-using-node-cron">How to Schedule a Job using node-cron</h2>
<p>In this section, you will apply what you have learned in the previous sections. You will build a simple app that scrapes world population data from <a target="_blank" href="https://www.worldometers.info/world-population/">worldometers site</a> and logs it to the console.</p>
<p>When you navigate to the <a target="_blank" href="https://www.worldometers.info/world-population/">worldometers world population page</a>, you will notice the current world population changing rapidly. You will schedule a job that will scrape the data and print it on the terminal.</p>
<p>In a real app, you will normally save it to a database. Follow the steps below to build the app.</p>
<h3 id="heading-step-1-how-to-create-a-directory">Step 1 - How to Create a Directory</h3>
<p>In this step, you will create a directory for your project and navigate to it. Open the terminal and run the command below to create a directory called <code>learn-node-cron</code>. The name of the directory doesn't matter. You can give it a different name if you wish.</p>
<pre><code class="lang-js">mkdir learn-node-cron
</code></pre>
<p>You should see the <code>learn-node-cron</code> folder created after running the above command successfully. You can open the folder in your favorite text editor. In the next step, you will initialize the project.</p>
<h3 id="heading-step-2-how-to-initialize-the-project">Step 2 - How to Initialize the Project</h3>
<p>In this step, you will initialize the project by running the command below on the terminal.</p>
<pre><code class="lang-js">npm init -y
</code></pre>
<p>After successfully running the above command, you should be able to see the <code>package.json</code> file created at the root of the project directory.</p>
<h3 id="heading-step-3-how-to-install-dependencies">Step 3 - How to Install Dependencies</h3>
<p>In this step, you will install the project dependencies by running the command below on the terminal.</p>
<pre><code class="lang-js">npm i node-cron puppeteer ora chalk
</code></pre>
<p>The above installation will take a bit of time, so just be patient. After successfully installing the above dependencies, you should see them in the <code>package.json</code> file under the <code>dependencies</code> field.</p>
<p><code>node-cron</code> is the most important dependency here because it is what this article is all about.</p>
<p>We'll use <code>puppeteer</code> to scrape data from a web page. According to the <a target="_blank" href="https://pptr.dev/">documentation</a> <code>puppeteer</code> is:</p>
<blockquote>
<p>A Node library that provides a high-level API to control Chrome or Chromium over the DevTools Protocol. Puppeteer runs headless by default but can be configured to run full (non-headless) Chrome or Chromium - <a target="_blank" href="https://pptr.dev/">puppeteer documentation</a></p>
</blockquote>
<p>If the above statement doesn't make sense to you, there is a nice article <a target="_blank" href="https://www.toptal.com/puppeteer/headless-browser-puppeteer-tutorial">on toptal</a> that explains puppeteer, headless browsers, and why they are necessary. It is still okay if you are not interested in <code>puppeteer</code>. This article is about <code>node-cron</code> and how to use it to schedule a job.</p>
<p><a target="_blank" href="https://github.com/sindresorhus/ora">ora</a> is a simple npm package that we will use for displaying messages and a spinner on the terminal as we scrape the data. This will provide a better user experience.</p>
<p><a target="_blank" href="https://www.npmjs.com/package/chalk">chalk</a> is another npm package that we'll use for displaying colorful messages on the terminal.</p>
<p>In the next step, you will implement the cron job.</p>
<h3 id="heading-step-4-how-to-implement-the-cron-job">Step 4 - How to Implement the Cron Job</h3>
<p>In this step, you will implement a simple cron job. Create a new JavaScript file by running the command below:</p>
<pre><code class="lang-js">touch app.js
</code></pre>
<p>Successfully running the above command will create an <code>app.js</code> file at the root of the project. Copy and paste the code below in the file you have just created:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> nodeCron = <span class="hljs-built_in">require</span>(<span class="hljs-string">"node-cron"</span>);
<span class="hljs-keyword">const</span> puppeteer = <span class="hljs-built_in">require</span>(<span class="hljs-string">"puppeteer"</span>);
<span class="hljs-keyword">const</span> ora = <span class="hljs-built_in">require</span>(<span class="hljs-string">"ora"</span>);
<span class="hljs-keyword">const</span> chalk = <span class="hljs-built_in">require</span>(<span class="hljs-string">"chalk"</span>);

<span class="hljs-keyword">const</span> url = <span class="hljs-string">"https://www.worldometers.info/world-population/"</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scrapeWorldPopulation</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Log a message on the terminal as the scheduled job starts</span>
  <span class="hljs-comment">// We are using chalk to make the message on the terminal look colorful</span>
  <span class="hljs-built_in">console</span>.log(chalk.green(<span class="hljs-string">"Running scheduled job"</span>));
  <span class="hljs-comment">// Launch a loading spinner with an appropriate message on the terminal</span>
  <span class="hljs-comment">// It provides a good user experience as the scraping process takes a bit of time</span>
  <span class="hljs-keyword">const</span> spinner = ora({
    <span class="hljs-attr">text</span>: <span class="hljs-string">"Launcing puppeteer"</span>,
    <span class="hljs-attr">color</span>: <span class="hljs-string">"blue"</span>,
    <span class="hljs-attr">hideCursor</span>: <span class="hljs-literal">false</span>,
  }).start();

  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// This will help us compute the duration of the job later</span>
    <span class="hljs-keyword">const</span> date = <span class="hljs-built_in">Date</span>.now();
    <span class="hljs-comment">// Launch puppeteeer</span>
    <span class="hljs-keyword">const</span> browser = <span class="hljs-keyword">await</span> puppeteer.launch();
    <span class="hljs-comment">// Change the message on the terminal as we launch</span>
    <span class="hljs-comment">// a new headless browser page</span>
    spinner.text = <span class="hljs-string">"Launching headless browser page"</span>;
    <span class="hljs-comment">// Launch a new headless browser page</span>
    <span class="hljs-keyword">const</span> newPage = <span class="hljs-keyword">await</span> browser.newPage();
    <span class="hljs-comment">// Change the message on the terminal as we navigate</span>
    <span class="hljs-comment">// to the URL of the page we are scraping</span>
    spinner.text = <span class="hljs-string">"Navigating to URL"</span>;
    <span class="hljs-comment">// Navigate to the URL of the page we are scraping. This takes a bit of time</span>
    <span class="hljs-comment">// You can change the timeout to an appropriate value if you wish otherwise</span>
    <span class="hljs-comment">// we wait until the page loads</span>
    <span class="hljs-keyword">await</span> newPage.goto(url, { <span class="hljs-attr">waitUntil</span>: <span class="hljs-string">"load"</span>, <span class="hljs-attr">timeout</span>: <span class="hljs-number">0</span> });

    <span class="hljs-comment">// Change the message on the terminal as we start scraping the page</span>
    spinner.text = <span class="hljs-string">"Scraping page"</span>;
    <span class="hljs-comment">// Start scraping the page</span>
    <span class="hljs-comment">// If world population is 7,876,395,914 then digitGroups will be</span>
    <span class="hljs-comment">// ["7", "876", "395", "914"]</span>
    <span class="hljs-keyword">const</span> digitGroups = <span class="hljs-keyword">await</span> newPage.evaluate(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> digitGroupsArr = [];
      <span class="hljs-comment">// For selecting span elements containing digit groups</span>
      <span class="hljs-keyword">const</span> selector =
        <span class="hljs-string">"#maincounter-wrap .maincounter-number .rts-counter span"</span>;
      <span class="hljs-keyword">const</span> digitSpans = <span class="hljs-built_in">document</span>.querySelectorAll(selector);
      <span class="hljs-comment">// Loop through the digit spans selected above</span>
      digitSpans.forEach(<span class="hljs-function">(<span class="hljs-params">span</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">isNaN</span>(<span class="hljs-built_in">parseInt</span>(span.textContent))) {
          digitGroupsArr.push(span.textContent);
        }
      });
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">JSON</span>.stringify(digitGroupsArr);
    });
    <span class="hljs-comment">// Change the message on the terminal since we are about</span>
    <span class="hljs-comment">// to close the headless browser</span>
    spinner.text = <span class="hljs-string">"Closing headless browser"</span>;
    <span class="hljs-comment">// Close the headless browser</span>
    <span class="hljs-keyword">await</span> browser.close();
    <span class="hljs-comment">// Print success message with duration it took to scrape the data in ms</span>
    spinner.succeed(<span class="hljs-string">`Page scraping successfull after <span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now() - date}</span>ms`</span>);
    <span class="hljs-comment">// Remove the spinner from the terminal</span>
    spinner.clear();
    <span class="hljs-comment">// Print world population on the terminal if scraping is successful</span>
    <span class="hljs-built_in">console</span>.log(
      chalk.yellow.bold(<span class="hljs-string">`World population on <span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString()}</span>:`</span>),
      chalk.blue.bold(<span class="hljs-built_in">JSON</span>.parse(digitGroups).join(<span class="hljs-string">","</span>))
    );
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-comment">// Print failed on the terminal if scraping is unsuccessful</span>
    spinner.fail({ <span class="hljs-attr">text</span>: <span class="hljs-string">"Scraping failed"</span> });
    <span class="hljs-comment">// Remove the spinner from the terminal</span>
    spinner.clear();
    <span class="hljs-comment">// Print the error message on the terminal</span>
    <span class="hljs-built_in">console</span>.log(error);
  }
}
<span class="hljs-comment">// Schedule a job to run every two minutes</span>
<span class="hljs-keyword">const</span> job = nodeCron.schedule(<span class="hljs-string">"*/2 * * * *"</span>, scrapeWorldPopulation);
</code></pre>
<p>In the above code snippet, we <em>required</em> all the dependencies we needed at the top of the file. They include <code>node-cron</code>, <code>puppeteer</code>, <code>chalk</code>, and <code>ora</code>. We are scraping the data from <code>https://www.worldometers.info/world-population/</code>, so I assigned it to the <code>url</code> variable.</p>
<p>Since our job is to scrape data from a site, I have named the function responsible for executing our job <code>scrapeWorldPopulation</code>.</p>
<p>I have tried my best to give self-explanatory variable names and commented on almost every line of code. You should be able to follow what is happening in the <code>scrapeWorldPopulation</code> function.</p>
<p>Since this article is about job scheduling, I won't dive into <code>puppeteer</code>. You can also implement a different job if you wish.</p>
<p>I scheduled the job to run every two minutes by invoking the <code>nodeCron.schedule</code> method at the bottom.</p>
<p>You can run the command <code>node app.js</code> on the terminal to schedule the job. You should see the job run every two minutes. This is what I see on my terminal after running <code>node app.js</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/006-01-schedule-job.png" alt="Terminal" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned crontab syntax and how to implement a cron job in Node using <code>node-cron</code>.</p>
<p>There are several projects you can try out to learn cron syntax, for example:</p>
<ul>
<li><p>scheduling a job to fetch the latest COVID-19 vaccination coverage for your country and logging the output to the console</p>
</li>
<li><p>fetching trending hashtags from Twitter (this might need an API key), or</p>
</li>
<li><p>getting the latest news headlines at intervals of time and so on.</p>
</li>
</ul>
<h3 id="heading-references">References</h3>
<ul>
<li><p><a target="_blank" href="https://github.com/merencia/node-cron">node-cron</a></p>
</li>
<li><p><a target="_blank" href="https://crontab.guru/">crontab guru</a></p>
</li>
<li><p><a target="_blank" href="https://pptr.dev/">Puppeteer</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Securely Access Secret API keys using Netlify Functions in a React App ]]>
                </title>
                <description>
                    <![CDATA[ In this article, you will learn how to securely access secret API keys using Netlify functions in a React app. Netlify provides rich features that help you easily deploy Single Page Applications built using frameworks like React, Vue and Angular amon... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-access-secret-api-keys-using-netlify-functions-in-a-react-app/</link>
                <guid isPermaLink="false">66d45f63246e57ac83a2c773</guid>
                
                    <category>
                        <![CDATA[ Application Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ create-react-app ]]>
                    </category>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Netlify ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joseph Mawa ]]>
                </dc:creator>
                <pubDate>Mon, 28 Jun 2021 21:17:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/pexels-noelle-otto-906018.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, you will learn how to securely access secret API keys using Netlify functions in a React app.</p>
<p>Netlify provides rich features that help you easily deploy Single Page Applications built using frameworks like <a target="_blank" href="https://reactjs.org/">React</a>, <a target="_blank" href="https://v3.vuejs.org/">Vue</a> and <a target="_blank" href="https://angular.io/">Angular</a> among others. This takes away the burden of coding and maintaining server-side code.</p>
<p>In some cases, a front-end app needs to communicate with an external third-party API. Some of the third-party APIs require secret API keys to access.</p>
<p>Let's imagine a situation where you want to include weather alerts on your front-end app. As a result, you sign up for <a target="_blank" href="https://openweathermap.org/api">open weather map</a> API's paid plan which requires a secret API key to access.</p>
<p>In such situations, you'll need to take care to ensure that you don't expose the secret API key on the front end.</p>
<p>Netlify provides functionality on its web user interface which you can use to hide API keys. But the API key can be accessed from the client side if the environment variable in which it is stored is accessed from the front-end code.</p>
<h2 id="heading-what-youll-learn-in-this-article">What You'll Learn in This Article</h2>
<p>In this article, you are going to hide the secret API key on the Netlify UI and securely access it using Netlify functions in a React app created using <a target="_blank" href="https://create-react-app.dev/">create-react-app(CRA)</a>. Using Netlify functions makes sure that the API key is not exposed on the client-side.</p>
<p>The process should be similar for other frameworks, though we are using <a target="_blank" href="https://reactjs.org/">React</a> in this article.</p>
<p>By the end of this article, you will be able to do the following:</p>
<ul>
<li><p>Add a Netlify function to a React app</p>
</li>
<li><p>Use Netlify functions to securely access secret API keys</p>
</li>
<li><p>Use the <a target="_blank" href="https://docs.netlify.com/cli/get-started/">netlify-cli</a> tool to test your Netlify functions</p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Outlined below are some of the prerequisites for this article. It is worth pointing out that you can still follow along even if you don't check off every one.</p>
<p>You can Google if there is something you don't understand or post a question on the <a target="_blank" href="https://forum.freecodecamp.org/">freeCodeCamp forum</a>. We shall be happy to help.</p>
<ul>
<li><p>Have at least a basic understanding of <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">JavaScript</a>, the <a target="_blank" href="https://reactjs.org/">React</a> framework, and a version control system like <a target="_blank" href="https://git-scm.com/">Git</a>.</p>
</li>
<li><p>Have <a target="_blank" href="https://nodejs.org/en/">Node</a> installed on your machine. If you don't have it installed, you can download it for your system from the <a target="_blank" href="https://nodejs.org/en/download/">Node downloads page</a>.</p>
</li>
<li><p>Have <a target="_blank" href="https://git-scm.com/">Git</a> installed on your machine. If you don't have it installed, you can do so from the <a target="_blank" href="https://git-scm.com/downloads">Git downloads page</a>.</p>
</li>
<li><p>Have a text editor like <a target="_blank" href="https://code.visualstudio.com/">VS code</a> or <a target="_blank" href="https://atom.io/">Atom</a> installed.</p>
</li>
<li><p>Have a <a target="_blank" href="https://www.netlify.com/">Netlify</a> account. If you don't have one, you can <a target="_blank" href="https://app.netlify.com/signup">sign up</a> at no cost using your email address.</p>
</li>
<li><p>Have a basic knowledge of Netlify's <a target="_blank" href="https://docs.netlify.com/site-deploys/create-deploys/#deploy-with-git">continuous deployment</a> feature. You will use it to deploy your React app to Netlify from <a target="_blank" href="https://github.com/">GitHub</a>.</p>
</li>
<li><p>Have a <a target="_blank" href="https://github.com/">GitHub</a> account because we'll be using Netlify's <a target="_blank" href="https://docs.netlify.com/site-deploys/create-deploys/#deploy-with-git">continuous deployment</a> feature. If you don't have an account, you can <a target="_blank" href="https://github.com/">sign up</a> using your email address.</p>
</li>
</ul>
<h2 id="heading-how-to-use-environment-variables-in-a-react-app-created-using-create-react-app">How to Use Environment Variables in a React App Created using <code>create-react-app</code></h2>
<p>In this section, you will learn how to use environment variables in a React app created using <a target="_blank" href="https://create-react-app.dev/"><code>CRA</code></a>. If you are already familiar with how to do this, then you can skip to the next section.</p>
<p>React apps created using <a target="_blank" href="https://create-react-app.dev/">CRA</a> come configured so you can create custom environment variables in <code>.env</code> file and then access them in your codebase using <code>process.env</code>.</p>
<p>To use this feature, you can follow the steps below. These steps assume you have already created a React app using <a target="_blank" href="https://create-react-app.dev/">CRA</a>.</p>
<h3 id="heading-step-1-create-a-env-file-at-the-root-of-the-project-directory">Step 1 - Create a <code>.env</code> file at the root of the project directory</h3>
<p>Start by creating a <code>.env</code> file at the root of the project directory. You can then add your environment variables in the <code>.env</code> file so that they look like the below.</p>
<pre><code class="lang-shell">REACT_APP_FIRST_SECRET=12345678
REACT_APP_SECOND_SECRET=123456789
</code></pre>
<p>In the above <code>.env</code> file, the environment variables are <code>REACT_APP_FIRST_SECRET</code> and <code>REACT_APP_SECOND_SECRET</code>. Their corresponding values are on the right-hand side. You need to take note of a few things when using environment variables with <a target="_blank" href="https://create-react-app.dev/">CRA</a>:</p>
<ul>
<li><p>The environment variable should always start with <code>REACT_APP</code> and then be followed by the variable name for it to work. For example, you can name the variable containing your API key <code>REACT_APP_API_KEY</code>.</p>
</li>
<li><p>There should be no spacing before and after the <code>=</code>.</p>
</li>
</ul>
<h3 id="heading-step-2-access-the-environment-variable-in-your-app-using-processenv">Step 2 - Access the environment variable in your app using <code>process.env</code></h3>
<p>You can then access those environment variables in your React app using <code>process.env.REACT_APP_FIRST_SECRET</code> and <code>proces.env.REACT_APP_SECOND_SECRET</code>. These variables are added to your codebase at build time, so you should restart your development server if you are running the app on <code>localhost</code> for the changes to take effect.</p>
<p>Accessing the environment variable like that prevents you from pushing your secret API key to a remote Git hosting service like <a target="_blank" href="https://github.com/">GitHub</a>.</p>
<p><a target="_blank" href="https://create-react-app.dev/">CRA</a> adds the <code>.gitignore</code> file by default. You just need to add <code>.env</code> file to it so that Git will ignore your <code>.env</code> file when you commit your changes.</p>
<p>What you have just learned about environment variables will keep your secrets safe in development.</p>
<p>But what will happen if you do the same thing in production since the environment variables are added to your codebase at build time? The next section will answer that question.</p>
<h2 id="heading-accessing-environment-variables-from-a-react-app-created-using-creat-react-app-exposes-your-api-keys">Accessing environment variables from a React app created using <code>creat-react-app</code> exposes your API keys</h2>
<p>Yes, indeed it does. Unfortunately, some absolute beginners think otherwise. That included me when I was just starting. But even the <a target="_blank" href="https://create-react-app.dev/">create-react-app documentation</a> states that:</p>
<blockquote>
<p>Environment variables are embedded into the build, meaning anyone can view them by inspecting your app's files - <a target="_blank" href="https://create-react-app.dev/">create-react-app documentation</a></p>
</blockquote>
<p>To illustrate this, I have built a <a target="_blank" href="https://netlify-secrets-demo.netlify.app/">simple demo app</a> and deployed it to Netlify. This is a simple React app created using <a target="_blank" href="https://create-react-app.dev/">CRA</a>. If you are interested, you can fork the <a target="_blank" href="https://github.com/nibble0101/netlify-secrets-demo-app">project repository</a> and deploy the app to Netlify under your account.</p>
<p>In this app, I am fetching a placeholder todo item from the <a target="_blank" href="https://jsonplaceholder.typicode.com/todos">JSON placeholder API</a> and then displaying it to the user.</p>
<p>The <a target="_blank" href="https://jsonplaceholder.typicode.com/todos">JSON placeholder API</a> does not need an API key to access. But for this illustration, I am using the base URL as the "secret" which I don't want to expose.</p>
<p>Most web-based APIs require passing the API key as a query parameter when authorizing users. While deploying the app, I have set the value of <code>REACT_APP_TODO_BASE_URL</code> to <code>https://jsonplaceholder.typicode.com/todos</code> on Netlify's web interface.</p>
<p>There are two ways you can access the value which I have hidden in the environment variable from the front-end:</p>
<ol>
<li><p>By inspecting the app's codebase</p>
</li>
<li><p>By inspecting the Network tab in the <a target="_blank" href="https://developer.chrome.com/docs/devtools/">Chrome DevTools</a></p>
</li>
</ol>
<h3 id="heading-how-to-inspect-the-apps-codebase">How to inspect the app's codebase</h3>
<p>To inspect the app's codebase, follow the steps below:</p>
<ol>
<li><p>Navigate to the deployed <a target="_blank" href="https://netlify-secrets-demo-app.netlify.app/">demo app</a>.</p>
</li>
<li><p>Open the browser developer tools. You can open them by pressing the key combination <code>CTRL + SHIFT + I</code> on Chrome or right-clicking and then selecting the Inspect option in Chrome. Click the <code>Sources</code> tab. This is what it looks like for me in Chrome if the <code>Sources</code> tab is active. It might look different in other browsers though.</p>
<p> <img src="https://www.freecodecamp.org/news/content/images/2021/06/005-01-sources-tab.png" alt="005-01-sources-tab" width="600" height="400" loading="lazy"></p>
</li>
<li><p>In the <code>Sources</code> tab, you should see <code>top</code> folder under the <code>Page</code> tab. Then navigate from the <code>top</code> folder to <code>main.e54a1b49.chunk.js</code> by following the path <code>top/netlify-secrets-demo-app.netlify.app/static/js/main.e54a1b49.chunk.js</code>. <code>main.e54a1b49.chunk.js</code> is a one-line minifed file that is not readable.</p>
<p> <img src="https://www.freecodecamp.org/news/content/images/2021/06/005-02-sources-folder.png" alt="005-02-sources-folder" width="600" height="400" loading="lazy"></p>
</li>
<li><p>Click the<code>{}</code> symbol at the bottom left of the panel to pretty-print the code in a readable format.</p>
</li>
<li><p>The secret that we hid in the environment variable is right there in the codebase on line 37 as shown in the image below.</p>
<p> <img src="https://www.freecodecamp.org/news/content/images/2021/06/005-03-pretty-code.png" alt="005-03-pretty-code" width="600" height="400" loading="lazy"></p>
</li>
</ol>
<h3 id="heading-how-to-inspect-the-newtwork-tab-in-the-devtoolshttpsdeveloperchromecomdocsdevtools">How to inspect the Newtwork tab in the <a target="_blank" href="https://developer.chrome.com/docs/devtools/">Devtools</a></h3>
<ol>
<li><p>Navigate to the deployed <a target="_blank" href="https://netlify-secrets-demo-app.netlify.app/">demo app</a></p>
</li>
<li><p>Open the browser developer tool and then open the Network Tab. The network Tab should look like in the image below in chrome. It might look different in other browsers.</p>
<p> <img src="https://www.freecodecamp.org/news/content/images/2021/06/005-04-network-tab.png" alt="005-04-network-tab" width="600" height="400" loading="lazy"></p>
</li>
<li><p>Click the <code>Get another todo</code> button in the browser. You should be able to see another row in the open panel indicating that another request has been made. Mine looks like in the image below.</p>
<p> <img src="https://www.freecodecamp.org/news/content/images/2021/06/005-05-network-request-made.png" alt="005-05-network-request-made" width="600" height="400" loading="lazy"></p>
</li>
<li><p>Click the last row. Another panel will open showing the request and response headers. Again our "secret" has been exposed.</p>
<p> <img src="https://www.freecodecamp.org/news/content/images/2021/06/005-06-response-header-open.png" alt="005-06-response-header-open" width="600" height="400" loading="lazy"></p>
</li>
</ol>
<p>As you can see from the above, your API key may not be visible in the codebase that has been committed to <a target="_blank" href="https://github.com/">GitHub</a> but it is still accessible on the client-side. Now you know what would happen if your key is for a paid plan.</p>
<p>To keep your secret key secret, you need to access your environment variable using <a target="_blank" href="https://www.netlify.com/products/functions/">Netlify functions</a>.</p>
<p>In the next section, you will learn how to securely access environment variables using Netlify functions. You will do that by adding Netlify functions to a React app and then deploying it to Netlify.</p>
<h2 id="heading-how-to-securely-access-environment-variables-with-netlify-functions">How to Securely Access Environment Variables with Netlify Functions</h2>
<p>In this section, you will fork a simple React app which was created using <a target="_blank" href="https://create-react-app.dev/">CRA</a> and then add a Netlify function to it. You will then use your function to access the environment variable instead of accessing it from your front-end code.</p>
<p>This will ensure that you don't expose your secret API key as illustrated in the section above. You will then deploy the app to Netlify using Netlify's <a target="_blank" href="https://docs.netlify.com/site-deploys/create-deploys/#deploy-with-git">continuous deployment</a> feature.</p>
<h3 id="heading-what-is-a-netlify-function">What is a Netlify function?</h3>
<p>This is a function that you can use for executing server-side code without having to deploy your own server.</p>
<p>According to the <a target="_blank" href="https://docs.netlify.com/functions/overview/">documentation</a>, if you use Netlify functions, you are indirectly using AWS’s serverless Lambda functions which are used for running on-demand, server-side code without having to run a dedicated server.</p>
<p>Below are some of the reasons why you might need to use Netlify functions.</p>
<ul>
<li><p>Fetch live data from an API</p>
</li>
<li><p>Return dynamic images</p>
</li>
<li><p>Send automated emails</p>
</li>
</ul>
<p>To start using Netlify functions, create a folder at the root of the project directory and name it <code>netlify</code>.</p>
<p>Inside the Netlify folder, you have to create another folder called <code>functions</code>. In the <code>functions</code> folder, you can create a file that contains a function that executes your code. As a result, the path to the files containing your functions should be <code>netlify/functions</code>.</p>
<p>This is the default location where Netlify will look for your functions. If you want to change the directory where your functions are located inside <code>netlify</code> folder, then you need to add that information to a <code>netlify.toml</code> configuration file at the root of the project directory so that Netlify knows where to look for them.</p>
<p>Using <code>netlify.toml</code> is outside the scope of this article. We shall be using the default configuration.</p>
<p>Below is what a Netlify function looks like. Let's assume that I have created a <code>todo.js</code> file in <code>netlify/functions</code> and added the code below to it.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);

<span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event, context</span>) </span>{
  <span class="hljs-comment">//Securely access environment variables here</span>
};
</code></pre>
<p>You will notice that the function has two parameters, <code>event</code> and <code>context</code>. If the function needs a dependency, make sure you add it to your project's <code>package.json</code> file.</p>
<p>In this case, I have added <code>axios</code> as a dependency. This function is executed whenever we hit the <code>netlify/functions/todo</code> endpoint.</p>
<p>There are other ways of triggering Netlify functions, but for this article let's focus on the simplest use case.</p>
<p>Data that have been passed from the front-end can be accessed in the <code>event</code> parameter. In the body of the function, you can do whatever you want including securely accessing your API key and sending data back to the front-end.</p>
<p>That is what you need to know to start using Netlify functions. If you want to dive deeper and explore what else you can do with them, take a look at the <a target="_blank" href="https://docs.netlify.com/functions/overview/">documentation</a>.</p>
<p>Now that you understand the basics of <a target="_blank" href="https://docs.netlify.com/functions/overview/">Netlify functions</a>, follow the steps below to learn how to implement them in a codebase.</p>
<p>You will fork <a target="_blank" href="https://github.com/nibble0101/netlify-secrets-demo-app">this demo app</a> and then add Netlify functions to it. It is a simple React project created using <a target="_blank" href="https://create-react-app.dev/">CRA</a>.</p>
<h3 id="heading-step-1-how-to-fork-the-project-under-your-own-github-account">Step 1 - How to fork the project under your own GitHub account</h3>
<p>In this step, you are going to fork the <a target="_blank" href="https://github.com/nibble0101/netlify-secrets-demo-app">demo app</a> under your own GitHub account. It is necessary to fork the project under your account so that you will be able to deploy it to Netlify.</p>
<p>If you are not interested in forking the project but would like to implement Netlify functions to your project, then skip to step 6.</p>
<p>If you don't know how to fork a GitHub repository, you can follow the steps described in the <a target="_blank" href="https://docs.github.com/en/get-started/quickstart/fork-a-repo">how to fork a repo</a> section of the GitHub documentation.</p>
<h3 id="heading-step-2-how-to-clone-the-project-to-your-local-machine">Step 2 - How to clone the project to your local machine</h3>
<p>In this step, you are going to clone the project to your local machine by running the command below (assuming you forked the project under your accoun). Do not forget to replace <code>GITHUB_USER_NAME</code> with your GitHub username.</p>
<pre><code class="lang-shell">git clone git@github.com:GITHUB_USER_NAME/netlify-secrets-demo-app.git
</code></pre>
<p>or</p>
<pre><code class="lang-shell">git clone https://github.com/GITHUB_USER_NANE/netlify-secrets-demo-app.git
</code></pre>
<p>After successfully cloning the project to your machine, you should be able to see the <code>netlify-secrets-demo-app</code> folder containing your project in the directory where the project was cloned.</p>
<p>You can navigate to the project directory and open it in your favorite text editor.</p>
<p>In the next step, you will install dependencies.</p>
<h3 id="heading-step-3-how-to-install-dependencies">Step 3 - How to install dependencies</h3>
<p>In this step, you will install dependencies by running the command below on the terminal.</p>
<pre><code class="lang-shell">npm install
</code></pre>
<p>The above command will install the dependencies you need. The installation process might take a couple of minutes so you need to be patient.</p>
<p>In the next step, you will create a <code>.env</code> file and add environment variables to it.</p>
<h3 id="heading-step-4-how-to-create-a-env-file">Step 4 - How to create a <code>.env</code> file</h3>
<p>In this step, you are going to create a <code>.env</code> file at the root of the project directory by running the command below on the terminal:</p>
<pre><code class="lang-shell">touch .env
</code></pre>
<p>You should be able to see the <code>.env</code> file created at the root of the project directory. Copy and paste the contents of the <code>example.env</code> file in it.</p>
<p>Since we'll be using Netlify functions to access environment variables, you don't need to prefix the variable name with <code>REACT_APP</code> as described at the beginning of the article. Change <code>REACT_APP_TODO_BASE_URL</code> environment variable to <code>TODO_BASE_URL</code> and set its value to <code>https://jsonplaceholder.typicode.com/todos</code>.</p>
<p>In the next step, you will add Netlify functions to your app.</p>
<h3 id="heading-step-5-how-to-add-netlify-functions-to-your-app">Step 5 - How to add Netlify functions to your app</h3>
<p>In this step, you will add a Netlify function to the app and use it to securely access your environment variables.</p>
<p>As I mentioned above, by default, Netlify will look for your functions inside the <code>functions</code> directory which must be located inside the <code>netlify</code> folder.</p>
<p>If you are keeping the functions in a different directory inside the <code>netlify</code> folder, then you need to provide additional information inside <code>netlify.toml</code> configuration file at the root of the project directory. This will make sure that Netlify knows where to locate your functions. But in this article, we'll be using the Netlify default configuration.</p>
<p>Create a folder at the root of the project directory and name it <code>netlify</code>. In the <code>netlify</code> folder create another folder and call it <code>functions</code>. In the <code>functions</code> folder, create <code>todo.js</code> file.</p>
<p>Copy and paste the code below in the <code>todo.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);

<span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event, context</span>) </span>{
  <span class="hljs-built_in">console</span>.log(event);
  <span class="hljs-built_in">console</span>.log(context);
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { id } = event.queryStringParameters;
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">`<span class="hljs-subst">${process.env.TODO_BASE_URL}</span>/<span class="hljs-subst">${id}</span>`</span>);
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">title</span>: response.data.title }),
    };
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">statusCode</span>: <span class="hljs-number">404</span>,
      <span class="hljs-attr">body</span>: err.toString(),
    };
  }
};
</code></pre>
<p>We'll send data from the front-end as the value of the <code>id</code> parameter in the query string. It is accessible in the <code>queryStringParameters</code> property of the <code>event</code> object.</p>
<p>You can also <code>console.log</code> the <code>event</code> and <code>context</code> parameters to see what their properties are.</p>
<p>We securely access the environment variable and use <code>axios</code> to fetch our todo. If it is successful, we send back a response object with a <code>statusCode</code> of 200 with the data in the body of the response object. If there is an error we return a <code>statusCode</code> of 404 and the error is sent back in the body of the response object.</p>
<p>The function you have added above will be exposed to your front-end code via <code>/.netlify/functions/todo</code> endpoint. It will be executed whenever you hit the <code>/.netlify/functions/todo</code> endpoint. Now let's execute the function from the front-end.</p>
<p>Navigate to the <code>App.js</code> component in the <code>src</code> folder. In the <code>useEffect</code> hook on line 15, instead of accessing <code>process.env.</code> on the front-end, we instead make a <code>GET</code> request to our endpoint exposed by the Netlify function we declared in the previous step.</p>
<p>So change line 15 from:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> url = <span class="hljs-string">`<span class="hljs-subst">${process.env.REACT_APP_TODO_BASE_URL}</span>/<span class="hljs-subst">${todoId}</span>`</span>;
</code></pre>
<p>to:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> url = <span class="hljs-string">`/.netlify/functions/todo?id=<span class="hljs-subst">${todoId}</span>`</span>;
</code></pre>
<p>Your <code>App.js</code> component should now look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</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> [todoId, setTodoId] = useState(<span class="hljs-number">1</span>);
  <span class="hljs-keyword">const</span> [todo, setTodo] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getNewTodo</span>(<span class="hljs-params"></span>) </span>{
    setTodoId(<span class="hljs-function">(<span class="hljs-params">todoId</span>) =&gt;</span> (todoId === <span class="hljs-number">20</span> ? <span class="hljs-number">1</span> : todoId + <span class="hljs-number">1</span>));
  }

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchTodo</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> url = <span class="hljs-string">`/.netlify/functions/todo?id=<span class="hljs-subst">${todoId}</span>`</span>;
      <span class="hljs-keyword">try</span> {
        setLoading(<span class="hljs-literal">true</span>);
        <span class="hljs-keyword">const</span> todo = <span class="hljs-keyword">await</span> fetch(url).then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json());
        setTodo(todo.title);
      } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(err);
      } <span class="hljs-keyword">finally</span> {
        setLoading(<span class="hljs-literal">false</span>);
      }
    }
    fetchTodo();
  }, [todoId]);

  <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">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{getNewTodo}</span>&gt;</span> Get another todo <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{loading ? "Loading..." : todo}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>In the code above we are storing <code>todo</code> and <code>todoId</code> in state. Notice that the <code>GET</code> request we are making to the <code>/.netlify/functions/todo</code> endpoint in the <code>useEffect</code> hook. We are passing the <code>todoId</code> as the value of the query parameter <code>id</code>.</p>
<p>After making the fetch request, our <code>todo.js</code> function will be invoked. Inside <code>todo.js</code> as explained above, we'll access the environment variable and fetch the todo which is returned by the function for the front-end code to use. This keeps our environment variable safe since it is not accessible from the front-end. The front-end only consumes what the function returns.</p>
<p>In the next step, you will test whether the function you have just defined works as intended.</p>
<h3 id="heading-step-6-how-to-test-your-netlify-function">Step 6 - How to test your Netlify function</h3>
<p>In this step, you will use <a target="_blank" href="https://docs.netlify.com/cli/get-started/">netlify-cli</a> to test whether the function you defined works as intended.</p>
<p>Run the command below to install <code>netlify-cli</code> globally. The installation will take a bit of time, so be patient:</p>
<pre><code class="lang-js">npm install netlify-cli -g
</code></pre>
<p>After <code>netlify-cli</code> is installed globally, run this command to test your function:</p>
<pre><code class="lang-js">netlify dev
</code></pre>
<p>Running the above command successfully will start a local development server on port 8888. You will also see the <code>event</code> and <code>context</code> parameters printed on the console when your function is invoked.</p>
<p>You can also test the function by running the command below on another terminal. Make sure the server is running before running the command below otherwise you will get an error.</p>
<pre><code class="lang-js">netlify functions:invoke --querystring <span class="hljs-string">"id=1"</span>
</code></pre>
<p>This command will invoke the function with the specified query string. You will be prompted to make some selections on the terminal. Just press enter.</p>
<p>Successfully running the above command will fetch our todo which will then be printed on the terminal.</p>
<pre><code class="lang-js">{<span class="hljs-string">"title"</span>:<span class="hljs-string">"delectus aut autem"</span>}
</code></pre>
<p>In the next step, you will deploy the project on your local machine to GitHub.</p>
<h3 id="heading-step-7-how-to-commit-your-changes-and-push-to-github">Step 7 - How to commit your changes and push to GitHub</h3>
<p>In this step, you will commit the changes on your local machine and push them to GitHub using the commands below.</p>
<pre><code class="lang-shell">git commit -m "Add netlify functions"
git push origin master
</code></pre>
<p>In the next step, you will use netlify's <a target="_blank" href="https://docs.netlify.com/site-deploys/create-deploys/#deploy-with-git">continuous ceployment</a> feature to deploy the app from GitHub.</p>
<h3 id="heading-step-8-how-to-deploy-the-app-to-netlify-from-github">Step 8 - How to deploy the app to Netlify from GitHub</h3>
<p>In this step, you will use Netlify's <a target="_blank" href="https://docs.netlify.com/site-deploys/create-deploys/#deploy-with-git">continuous deployment</a> feature to deploy from GitHub.</p>
<p>This step requires you to have a Netlify account. If you haven't signed up, you can do so from the <a target="_blank" href="https://app.netlify.com/signup">signup page</a> at no cost.</p>
<p>Log in to your Netlify account and follow the process for linking a GitHub repository to Netlify for continuous deployment <a target="_blank" href="https://docs.netlify.com/configure-builds/get-started/#basic-build-settings">as described in the documentation</a>. Do not forget to add the environment variable <code>TODO_BASE_URL</code> and set its value to <code>https://jsonplaceholder.typicode.com/todos</code> under the advanced settings as you deploy the app to Netlify.</p>
<p>And there you have it! That is how you hide secret API keys using Netlify functions. I hope you enjoyed reading the article.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article we learned how to:</p>
<ul>
<li><p>Add a Netlify function to a React app</p>
</li>
<li><p>Use Netlify functions to securely access secret API keys</p>
</li>
<li><p>Use the <a target="_blank" href="https://docs.netlify.com/cli/get-started/">netlify-cli</a> tool to test your Netlify functions</p>
</li>
</ul>
<p>With <a target="_blank" href="https://www.netlify.com/products/functions/">netlify's serverless functions</a>, you can send emails, fetch data from an API like we just did, and much more. It has equipped front-end developers with the tools to write back-end code without worrying about server maintenance.</p>
<p>You can explore more about what else you can do with Netlify functions in the <a target="_blank" href="https://docs.netlify.com/functions/overview/">functions section of the documentation</a>.</p>
<p>Finally, if you have any questions about what we've covered in this article, feel free to ask on the <a target="_blank" href="https://forum.freecodecamp.org/">freeCodeCamp forum</a> or DM me on <a target="_blank" href="https://twitter.com/MJMAWA">Twitter</a>. You can also ask your question in the <a target="_blank" href="https://answers.netlify.com/">Netlify forum</a>.</p>
<p>Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Generate a Code Coverage Report with CodeCov and GitHub Actions ]]>
                </title>
                <description>
                    <![CDATA[ Software testing is an important part of the software development process. You run tests at different stages of the software development life cycle, and you'll want to make sure that you have good test coverage. Here are some key reasons for writing ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-generate-code-coverage-report-with-codecov-and-github-actions/</link>
                <guid isPermaLink="false">66d45f6bd14641365a0508ff</guid>
                
                    <category>
                        <![CDATA[ GitHub Actions ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joseph Mawa ]]>
                </dc:creator>
                <pubDate>Mon, 24 May 2021 19:40:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/05/automation.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Software testing is an important part of the software development process. You run tests at different stages of the software development life cycle, and you'll want to make sure that you have good test coverage.</p>
<p>Here are some key reasons for writing software tests:</p>
<ul>
<li><p>Testing prevents you from introducing breaking changes to your codebase in the future. In other words, the tests you write now might save you from your own self in the future.</p>
</li>
<li><p>Testing makes sure that the product you build meets the required specification.</p>
</li>
<li><p>Well tested code gives you more confidence about the quality of your code.</p>
</li>
<li><p>Testing reduces the likelihood that you have code in your codebase with unknown behavior which might become a source of errors.</p>
</li>
<li><p>Testing makes it easier to maintain your code. You cannot tell how changing a small section of your codebase might affect the entire codebase if you don't have a high code coverage.</p>
</li>
</ul>
<p>In this article, you will learn how to generate a code coverage report using <a target="_blank" href="https://about.codecov.io/">codecov</a> and <a target="_blank" href="https://github.com/features/actions">gitHub actions</a>.</p>
<h2 id="heading-what-is-code-coverage">What is code coverage?</h2>
<p>Code coverage is a metric which helps you know how much of your source code has been tested. There are a number of tools which you can use to generate code coverage reports. These tools include:</p>
<ul>
<li><p><a target="_blank" href="https://about.codecov.io/">codecov</a></p>
</li>
<li><p><a target="_blank" href="https://coveralls.io/">coveralls</a></p>
</li>
<li><p><a target="_blank" href="https://istanbul.js.org/">istanbul</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/uber/uberalls">uberalls</a></p>
</li>
</ul>
<p>Most code coverage anysis tools use a set of metrics for reporting code coverage anysis. These metrics include:</p>
<ul>
<li><p><strong>Function coverage</strong> The number of declared functions that have been invoked after running your test suites.</p>
</li>
<li><p><strong>Statement coverage</strong> The number of statements that have been executed after running the test suites.</p>
</li>
<li><p><strong>Branch coverage</strong> How much of the branch code, such as <code>if</code> code blocks, have been executed.</p>
</li>
<li><p><strong>Condition coverage</strong> The number of boolean sub-expressions that have been tested for <code>true</code> and <code>false</code> values.</p>
</li>
<li><p><strong>Line coverage</strong> Lines of code that have been tested.</p>
</li>
</ul>
<p>In this article, we'll focus primarily on how to use <a target="_blank" href="https://about.codecov.io/">codecov</a> and <a target="_blank" href="https://github.com/features/actions">gitHub actions</a> to generate a code coverage report for a Node project.</p>
<h2 id="heading-why-is-code-coverage-important">Why is code coverage important?</h2>
<p>Good code coverage gives you confidence about the code you are shipping, especially if your tests are robust and well-thought out.</p>
<p>When you write tests to increase your code coverage, it is more likely you will detect bugs and fix them before shipping to production.</p>
<h2 id="heading-what-is-codecov">What is Codecov?</h2>
<p><a target="_blank" href="https://about.codecov.io/">Codecov</a> is a tool you can use to generate coverage reports for your projects. You can upload code coverage data generated in your local file system to codecov and easily visualize the coverage report on different charts.</p>
<p>In this article, though, you are going to use GitHub actions so that the processes of generating coverage reports and uploading them to <a target="_blank" href="https://about.codecov.io/">codecov</a> is automated.</p>
<p>You can integrate codecov as part of your continuous integration workflow. Codecov is capable of making pull request comments and much more. These comments will help other developers know how merging their pull request will affect the code coverage without leaving their GitHub UI.</p>
<p>You can also display a badge showing the coverage report on your GitHub repository for all the collaborators of your project to see. You just have to integrate codecov into your continuous integration workflow.</p>
<p>You can read more about all the other features codecov offers in the <a target="_blank" href="https://docs.codecov.io/docs">documentation</a>.</p>
<h2 id="heading-hpw-tp-create-a-project-and-generate-a-coverage-report">Hpw tp create a project and generate a coverage report</h2>
<p>In the steps below, you are going to create a simple Node project and generate a codecov coverage report for it.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>You need to have the following installed on your machine to be able to run the commands in the next subsections.</p>
<ul>
<li><p><a target="_blank" href="https://nodejs.org/en/">Node</a></p>
</li>
<li><p>Text editor like <a target="_blank" href="https://code.visualstudio.com/">VS code</a> or <a target="_blank" href="https://atom.io/">atom</a></p>
</li>
<li><p><a target="_blank" href="https://git-scm.com/">Git</a></p>
</li>
</ul>
<h3 id="heading-step-1-create-a-directory-and-navigate-to-it">Step 1: Create a directory and navigate to it</h3>
<p>In this step you are going to create a directory called <code>learn-test-coverage</code> and then navigate to it. You can give the directory a different name if you wish, provided it is a meaningful name.</p>
<p>Run the following commands in the terminal:</p>
<pre><code class="lang-js">mkdir learn-test-coverage
cd learn-test-coverage
</code></pre>
<p>In the next step, you are going to initalize the project.</p>
<h3 id="heading-step-2-initialize-the-project">Step 2: Initialize the project</h3>
<p>In this step you are going to initialize the project by running the command below in the terminal:</p>
<pre><code class="lang-js">npm init --yes
</code></pre>
<p>Successfully running the above command will create a <code>package.json</code> file at the root of your project directory.</p>
<p>In the next step, you are going to install <a target="_blank" href="https://jestjs.io/">jest</a> as a development dependency.</p>
<h3 id="heading-step-3-install-jest-as-a-dependency">Step 3: Install Jest as a dependency</h3>
<p>In this step, you are going to install <a target="_blank" href="https://jestjs.io/">jest</a> as a development dependency. Jest is a simple JavaScript testing framework which usually works out of the box in Node with minimal setup.</p>
<p>Run the command below in the terminal:</p>
<pre><code class="lang-js">npm install --save-dev jest
</code></pre>
<p>After successfully running the above command, you should be able to see the <code>node_modules</code> directory and <code>package-lock.json</code> file created at the root of your project directory. You should also be able to see Jest installed as a development dependency in the <code>package.json</code> file.</p>
<p>In the next step you will initialize a git repository in your project.</p>
<h3 id="heading-step-4-initialize-a-git-repository">Step 4: Initialize a Git repository</h3>
<p>In this step you are going to intialize a git repository in your project by running the command below:</p>
<pre><code class="lang-shell">git init
</code></pre>
<p>Create a <code>.gitignore</code> file at the root of the project directory and add the following code to it. This will ignore <code>node_modules</code> file so that it is not committed to the remote repository later.</p>
<pre><code class="lang-shell">/node_modules
</code></pre>
<p>In the next step we will declare a simple function and write a test for it.</p>
<h3 id="heading-step-5-declare-a-function-and-write-a-test-for-it">Step 5: Declare a function and write a test for it</h3>
<p>In this step, you will declare a simple function called <code>sum</code> in the <code>sum.js</code> file. This function takes two parameters and returns their sum. You will also write tests for your code in the <code>sum.test.js</code> file.</p>
<p>Run the command below in the terminal:</p>
<pre><code class="lang-js">touch sum.js sum.test.js
</code></pre>
<p>You should be able to see the two files created in your project. Copy and paste the code below in <code>sum.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sum</span>(<span class="hljs-params">num1, num2</span>) </span>{
  <span class="hljs-keyword">return</span> num1 + num2;
}

<span class="hljs-built_in">module</span>.exports = sum;
</code></pre>
<p>Similarly, copy and paste the code below in <code>sum.test.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> sum = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./sum"</span>);

test(<span class="hljs-string">"adds 1 + 2 to equal 3"</span>, <span class="hljs-function">() =&gt;</span> {
  expect(sum(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)).toBe(<span class="hljs-number">3</span>);
});
</code></pre>
<p>Change the value of the <code>"test"</code> property in your <code>package.json</code> to <code>"jest --coverage"</code> so that the value of the <code>"scripts"</code> property looks like this:</p>
<pre><code class="lang-js">{
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"jest --coverage"</span>
}
</code></pre>
<p>In the terminal run <code>npm test</code> to run your test. After the test completes, you should be able to see the code coverage summary in the terminal and a <code>coverage</code> directory generated.</p>
<p>Here's what I see in my terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/coverage-terminal-output.png" alt="coverage-terminal-output" width="600" height="400" loading="lazy"></p>
<p>You can also view the summary in the browser by opening the <code>index.html</code> file inside the <code>coverage/lcov-report</code> folder. You should be able to see the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/codecov-coverage-report-browser.png" alt="codecov-coverage-report-browser" width="600" height="400" loading="lazy"></p>
<p>You are able to generate the coverage report because Jest comes bundled with <a target="_blank" href="https://istanbul.js.org/">istanbul</a>. Make sure you delete the <code>coverage</code> file, as you don't need it since we'll automate the process using GitHub actions.</p>
<p>You should be able to identify which metrics <a target="_blank" href="https://istanbul.js.org/">istanbul</a> uses to generate coverage report (the metrics I mentioned at the beginning of the articl).</p>
<p>In the next step we'll add GitHub actions' Continuous Integration to our project.</p>
<h3 id="heading-step-6-add-github-actions-continuous-integration-workflow">Step 6: Add GitHub actions' continuous integration workflow</h3>
<p>In this step you will add GitHub actions' continuous integration workflow to your project so that codecov will automatically generate a report on creating a pull request.</p>
<p>Create a <code>.github</code> file at the root of your project folder. Inside the <code>.github</code> folder, create a <code>workflows</code> folder. Then inside <code>workflows</code> create a <code>codecov.yml</code> file. The file doesn't need to be named <code>codecov</code>. You can give it any name you like.</p>
<p>Copy and paste the code below inside your <code>codecov.yml</code> file.</p>
<p>This is the workflow configuration file. It will run your test when the two events <code>push</code> and <code>pull_request</code> occur. You can read more about <a target="_blank" href="https://yaml.org/spec/1.2/spec.html">YAML syntax</a> and <a target="_blank" href="https://github.com/features/actions">gitHub actions</a> to understand the contents of the file below.</p>
<pre><code class="lang-yml"><span class="hljs-attr">name:</span> <span class="hljs-string">Running</span> <span class="hljs-string">Code</span> <span class="hljs-string">Coverage</span>

<span class="hljs-attr">on:</span> [<span class="hljs-string">push</span>, <span class="hljs-string">pull_request</span>]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>

    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">strategy:</span>
      <span class="hljs-attr">matrix:</span>
        <span class="hljs-attr">node-version:</span> [<span class="hljs-number">12.</span><span class="hljs-string">x</span>, <span class="hljs-number">13.</span><span class="hljs-string">x</span>, <span class="hljs-number">14.</span><span class="hljs-string">x</span>, <span class="hljs-number">15.</span><span class="hljs-string">x</span>]

    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">repository</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">fetch-depth:</span> <span class="hljs-number">2</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Set</span> <span class="hljs-string">up</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">node-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">tests</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">test</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Upload</span> <span class="hljs-string">coverage</span> <span class="hljs-string">to</span> <span class="hljs-string">Codecov</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">codecov/codecov-action@v1</span>
</code></pre>
<p>The last step is responsible for uploading the coverage report to codecov in the above configuration file.</p>
<p>In the next step, you are going to create a repository on GitHub and push your project to it</p>
<h3 id="heading-step-7-create-a-repository-on-github-and-push-your-changes-to-it">Step 7: Create a repository on GitHub and push your changes to it</h3>
<p>In this step, you are going to create a repository on gitHub and push your changes to it.</p>
<p>Navigate to GitHub. Create an empty repository and name it <code>learn-test-coverage</code>.</p>
<p>At the root of your project directory on your machine, run the following commands to initialize your project repository and commit your changes.</p>
<pre><code class="lang-shell">git add .
git commit -m "Initial commit"
</code></pre>
<p>You can then add the remote repository you created above to your local repository using the command below:</p>
<pre><code class="lang-shell">git remote add origin &lt;Remote repository&gt;
</code></pre>
<p>Finally, you can push your changes to your remote repository using the command below:</p>
<pre><code class="lang-shell">git push origin master
</code></pre>
<p>In the next step, we are going to link our GitHub repository to codecov. This makes sure that our coverage data is automatically uploaded whenever we create a pull request so that a report is generated.</p>
<h3 id="heading-step-8-link-your-remote-repository-to-codecov">Step 8: Link your remote repository to codecov</h3>
<p>In this step you are going to link your repository to codecov. But you need to sign up first.</p>
<p>Codecov allows you to sign up with your GitHub account in just a couple of minutes. You can then select the GitHub repository you want to link on the codecov dashboard.</p>
<p>After selecting the repository, you will be redirected to a page with a token. You don't need this token for public repositories.</p>
<p>For private repositories, you will need to add it to your GitHub secrets and then add the following at the bottom of your workflow configuration file so that it looks like this:</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Upload</span> <span class="hljs-string">coverage</span> <span class="hljs-string">to</span> <span class="hljs-string">Codecov</span>
    <span class="hljs-attr">uses:</span> <span class="hljs-string">codecov/codecov-action@v1</span>
    <span class="hljs-attr">with:</span>
        <span class="hljs-attr">token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.YOUR_SECRET_TOKEN</span> <span class="hljs-string">}}</span>
</code></pre>
<h3 id="heading-step-9-test-your-continuous-integration-workflow">Step 9: Test your continuous integration workflow</h3>
<p>In this step, you are going to test your continuous integration workflow.</p>
<p>Create a <code>README.md</code> file at the root of your project. Copy and paste the codecov badge on your codecov dashboard under the settings tab in your <code>README.md</code> file. This is what the badges look like.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/codecov-badge.png" alt="codecov-badge" width="600" height="400" loading="lazy"></p>
<p>Commit and push the changes to GitHub. You should be able to see the code coverage indicated on your badge after the CI workflow run completes.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/codecov-readme.png" alt="codecov-readme" width="600" height="400" loading="lazy"></p>
<p>You can also view the coverage report on your codecov dashboard. Try creating a pull request to see what happens.</p>
<p>For more insights on what else you can do, check out the <a target="_blank" href="https://docs.codecov.io/docs">Codecov documentation</a>.</p>
<p>If you get stuck, you can also check out <a target="_blank" href="https://github.com/nibble0101/learn-test-coverage">my project</a> on GitHub.</p>
<h2 id="heading-how-does-codecov-generate-its-coverage-report">How does codecov generate its coverage report?</h2>
<p>Codecov uses the terms <strong>hit</strong>, <strong>partial</strong> and <strong>miss</strong> to describe the code coverage in your project. Coverage is the ratio of <code>hits</code> to the sum of <code>hits</code>, <code>partials</code> and <code>misses</code>.</p>
<p>If the code is described as a <strong>hit</strong>, it means that the source code was executed by the test suite.</p>
<p>If it is described as <strong>partial</strong>, it indicates that the source code was not fully executed by the test suite. There are remaining branches that were not executed.</p>
<p>A <strong>miss</strong> indicates that the source code was not executed by the test suite.</p>
<blockquote>
<p>A code base that has 5 lines executed by tests out of 12 total lines will receive a coverage ratio of 41% (rounding down) - <a target="_blank" href="https://docs.codecov.io/docs">Codecov documentation</a></p>
</blockquote>
<p>That is how you integrate codecov as part of your contnuous integration workflow. If you want to explore more features, you can check out the <a target="_blank" href="https://docs.codecov.io/docs">Codecov documentation</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article we looked at how you can integrate <a target="_blank" href="https://docs.codecov.io">codecov</a> as part of your continuous integration workflow.</p>
<p>Increasing code coverage will help you in so many ways. But having higher code coverage just for the sake of it can get you into trouble if your tests are not robust and well thought out.</p>
<p>Code coverage analysis tools are just tools meant to make your work easier. But you shouldn't substitute them for code reviews. A tool is only as good as its user.</p>
<h3 id="heading-references">References</h3>
<ul>
<li><p><a target="_blank" href="https://docs.codecov.io/docs">Codecov documentation</a></p>
</li>
<li><p><a target="_blank" href="https://jestjs.io/docs/getting-started">Jest documentation</a></p>
</li>
<li><p><a target="_blank" href="https://istanbul.js.org/">Instanbul documentation</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add a Netlify Form to a React App Built with create-react-app ]]>
                </title>
                <description>
                    <![CDATA[ If you are a web developer, at some point you will need to capture information from people who use your website or app. One way of doing so is by using HTML forms. But there are also tons of frameworks out there that you can use to build web apps ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-a-netlify-form-to-a-react-app/</link>
                <guid isPermaLink="false">66d45f6536c45a88f96b7ce3</guid>
                
                    <category>
                        <![CDATA[ create-react-app ]]>
                    </category>
                
                    <category>
                        <![CDATA[ forms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Netlify ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joseph Mawa ]]>
                </dc:creator>
                <pubDate>Mon, 19 Apr 2021 21:20:05 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/04/questions-4304981_1280.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you are a web developer, at some point you will need to capture information from people who use your website or app.</p>
<p>One way of doing so is by using HTML forms. But there are also tons of frameworks out there that you can use to build web apps very quickly.</p>
<p>One such framework is React. You can bootstrap a single page application (SPA) very easily using <code>create-react-app</code> (CRA). Then you can deploy it to platforms such as Netlify, Vercel, Firebase and Digital Ocean in just a couple of steps.</p>
<p>The main focus of this article will be on how to add Netlify form functionality to a React app bootstrapped using <code>create-react-app</code>. At the end of this tutorial you will be able to:</p>
<ul>
<li><p>Quickly set up a single page app using <code>create-react-app</code></p>
</li>
<li><p>Add functionality to utilize Netlify's builtin form handling feature</p>
</li>
<li><p>Deploy the app to Netlify</p>
</li>
<li><p>Configure the builtin form handling feature on Netlify to send email notifications whenever a form has been submitted by a client</p>
</li>
</ul>
<p>Whether you are beginner trying to deploy your first React app or you are an experienced React developer, this article will help you learn to use Netlify's builtin form functionality without writing any server side code.</p>
<p>If you are an experienced React developer, you can skip the introduction and go to <code>step 6</code>. If you are a beginner in React, you can follow along right from the beginning.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this article, you should:</p>
<ul>
<li><p>Have an intermediate knowledge of JavaScript. If you are a beginner, you can still follow along and ask questions on the <a target="_blank" href="https://forum.freecodecamp.org">freeCodeCamp forum</a> if there is something you don't understand. You can also copy the code samples in each section and play with them in your text editor to make sense of what is going on.</p>
</li>
<li><p>Have at least basic knowledge of the React library</p>
</li>
<li><p>Have Node installed on your machine</p>
</li>
<li><p>Have a Netlify account. If you don't have one, you can signup for an account at no cost using your email address.</p>
</li>
<li><p>Have a text editor like <a target="_blank" href="https://code.visualstudio.com/">VS code</a> or <a target="_blank" href="https://atom.io/">Atom</a> installed on your machine. You can try out the code samples as you follow along. It will make it easier for you to understand.</p>
</li>
</ul>
<h2 id="heading-step-1-check-whether-you-have-node-and-npm-installed-on-your-machine">Step 1: Check whether you have <code>node</code> and <code>npm</code> installed on your machine</h2>
<p>Before we get started, you should check whether you have <a target="_blank" href="https://nodejs.org/en/">node</a> installed on your machine.</p>
<p>Node is a JavaScript runtime environment, and it's important to have it installed to be able to run the project. Open a terminal and type the following command in the command prompt.</p>
<pre><code class="lang-js">node - v
</code></pre>
<p>Instead of the above command, you can also type the command below. Both of them do the same thing.</p>
<pre><code class="lang-js">node --version
</code></pre>
<p>If Node is installed, you should be able to see the version printed on the terminal. Your version might be different from mine but you should see something like:</p>
<pre><code class="lang-js">v15<span class="hljs-number">.13</span><span class="hljs-number">.0</span>
</code></pre>
<p>If Node is installed, that means <code>npm</code> is also installed because recent versions of Node come with <code>npm</code>. If you are curious, type the command <code>npm --version</code> or <code>npm -v</code>. You should be able to see the version of <code>npm</code> which has been installed.</p>
<p>On the other hand, if you don't have Node installed on your machine, you can download and install for your platform from <a target="_blank" href="https://nodejs.org/en/download/">here</a>.</p>
<h2 id="heading-step-2-navigate-to-the-directory-where-you-want-to-create-your-project">Step 2: Navigate to the directory where you want to create your project</h2>
<p>Next, you need to navigate to a directory where you want to create your project. You can work from the Desktop or from any directory of your choice.</p>
<p>I like keeping my personal projects in a directory called <code>projects</code> on the desktop for easy access. This is just personal choice.</p>
<p>Open the terminal and navigate to the directory where you want to create your project. I am using <code>cd</code> (change directory) in the commands below.</p>
<p><strong>Take note</strong>: I already have a directory named <code>projects</code> on the Desktop. If you don't, you will have to first run the command <code>mkdir projects</code> before you <code>cd</code> into it. Like I said above, you can decide to work from another directory and then you won't have to run the commands below.</p>
<ol>
<li><p><code>cd Desktop</code></p>
</li>
<li><p><code>cd projects</code></p>
</li>
</ol>
<h2 id="heading-step-3-how-to-bootstrap-a-single-page-app-using-create-react-app">Step 3: How to bootstrap a single page app using <code>create-react-app</code></h2>
<p>How we are going to bootstrap a React project using <code>create-react-app</code>. In the directory where you want to create your project, run the command below.</p>
<pre><code class="lang-js">npx create-react-app netlify-form
</code></pre>
<p>I have named the project <code>netlify-form</code>. You can give it a different name if you wish.</p>
<p>If you don't have <code>create-react-app</code> installed, you will see a prompt on the terminal asking whether it should be installed. Type <code>Y</code> on the command prompt (for "Yes"). It will install <code>create-react-app</code> and then create a React project in the <code>netlify-form</code> directory.</p>
<p>If you already have <code>create-react-app</code> in your system, it will go straight to creating a React project in the <code>netlify-form</code> directory. This will take a couple of minutes, so just be patient.</p>
<p>In the next step, you will start the development server.</p>
<h2 id="heading-step-4-start-the-development-server">Step 4: Start the development server</h2>
<p>In this step, we are going to start the development server. This ensures hot reloading when we make changes to the project during development so that we are able to see how our project is taking shape.</p>
<p>You can open the <code>netlify-form</code> directory in your text editor of choice. When you are in <code>netlify-form</code>, open the terminal and run the command below.</p>
<pre><code class="lang-js">npm run start
</code></pre>
<p>The above command starts the development server on port 3000. If there is another project or service running on port 3000, you will be prompted to start the server on another port.</p>
<p>A new browser tab will be opened in your default browser where you can see the project. Any changes you make will automatically be reflected in the browser.</p>
<p>In the next step, you are going to create a component which will contain your form.</p>
<h2 id="heading-step-5-create-a-new-component-inside-the-src-directory">Step 5: Create a new component inside the <code>src</code> directory</h2>
<p>Now you are going to create a component named <code>Form</code> inside the <code>src</code> directory. In this component, you will have the form which will be rendered in your app.</p>
<p>Create a <code>Form.js</code> file in the <code>src</code> directory then copy and paste the code below in it:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Form</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"contact"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"name"</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</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">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">required</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">required</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"message"</span>&gt;</span>Message<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"message"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"message"</span> <span class="hljs-attr">required</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Submit message"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
</code></pre>
<p>The above component returns an ordinary form. I have enclosed each label-input pair and label-textarea pair in its own <code>p</code> tag.</p>
<p>There is nothing special about the <code>p</code> tag. You can use <code>div</code> if you wish. I just used it because I want to apply spacing between successive label-input pairs without using CSS.</p>
<p>You can import the <code>Form</code> component and render it inside <code>App</code>. To clean up <code>App.js</code>, you can also delete some items which come with <code>create-react-app</code>, so that it looks like:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> Form <span class="hljs-keyword">from</span> <span class="hljs-string">"./Form"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Get in touch <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>You can also clean up <code>App.css</code> so that it has only the following CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.App</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
}
</code></pre>
<p>When you check your form in the browser it should look like the image below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-from-2021-04-17-14-30-11.png" alt="Screenshot-from-2021-04-17-14-30-11" width="600" height="400" loading="lazy"></p>
<p>Right now deploying that app to Netlify won't enable us to capture a client's form submissions. To do that, we need to add necessary information to our app so that Netlify's bots will be able to detect our form.</p>
<p>In the next step, we are going to add all the necessary information to make the JSX <code>form</code> in React detectable by Netlify.</p>
<h2 id="heading-step-6-add-necessary-information-to-make-the-form-detectable-by-netlifys-bots">Step 6: Add necessary information to make the <code>form</code> detectable by Netlify's bots</h2>
<p>In this step, you are going to add some information to your app so that Netlify will be able to detect your app's form setup. If your form is deployed in plain HTML, the process of making it detectable is quite simple. You can read about it in the <a target="_blank" href="https://docs.netlify.com/forms/setup/?_ga=2.214149207.1369394306.1618461268-796209470.1617367540">documentation</a>.</p>
<p>But if you are dealing with a JSX form in React like in this simple app we are building, then you will have to do a bit more work. You can follow the steps outlined below.</p>
<h3 id="heading-add-the-html-version-of-the-form-to-the-indexhtml-file">Add the HTML version of the form to the <code>index.html</code> file</h3>
<p>Copy and paste your JSX form into the <code>index.html</code> file just after the opening <code>body</code> tag. This will ensure that Netlify detects our form because build bots parse the HTML files directly at deploy time. The JSX form cannot be parsed by the bots.</p>
<p>You can remove the <code>label</code> elements and the <code>submit</code> input element because we will add a <code>hidden</code> attribute to the <code>form</code> so that it is not visible to users and screen readers.</p>
<p>You can only leave the <code>type</code> and <code>name</code> attributes on the <code>input</code> elements and <code>name</code> attribute on <code>textarea</code> so that we keep the form minimal.</p>
<p>This is illustrated in the code below:</p>
<pre><code class="lang-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"contact"</span> <span class="hljs-attr">netlify</span> <span class="hljs-attr">netlify-honeypot</span>=<span class="hljs-string">"bot-field"</span> <span class="hljs-attr">hidden</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>  <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"message"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>As you can see in the above code snippet, there are additional attributes <code>netlify</code> and <code>netlify-honeypot</code> on the <code>form</code>. Netlify bots will use them while parsing your HTML so make sure to add them.</p>
<p>Do not forget to add the <code>hidden</code> attribute, because this form needs to be hidden from the users of your website. It is also worth pointing out that the name attributes in the HTML form must be exactly the same as those in the corresponding JSX form.</p>
<h3 id="heading-add-a-hidden-input-element-in-your-jsx-form">Add a hidden <code>input</code> element in your JSX form</h3>
<p>You also need to add a hidden <code>input</code> element in your JSX form with the attributes <code>name</code> and <code>value</code> as illustrated in the code below:</p>
<pre><code class="lang-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"form-name"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"contact"</span> /&gt;</span>
</code></pre>
<p>The value of the <code>name</code> attribute should always be <code>"form-name"</code> and the value of the <code>value</code> attribute should be the name of the HTML form, which in our case is <code>contact</code>.</p>
<p>Your <code>Form.js</code> file should now look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Form</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"contact"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"form-name"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"contact"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"name"</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</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">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">required</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">required</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"message"</span>&gt;</span>Message<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"message"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"message"</span> <span class="hljs-attr">required</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Submit message"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
</code></pre>
<p>If you check the app in the browser, you should be able to see the form – but you won't be able to submit it from your local setup. You can only submit forms after deploying your app to Netlify.</p>
<p>So let's do that now.</p>
<h2 id="heading-step-7-deploy-the-app-to-netlify">Step 7: Deploy the app to Netlify</h2>
<p>In this step, you are going to deploy our app to Netlify so that you are able to test whether clients can make form submissions.</p>
<p>There are a couple of ways you can deploy your app to Netlify. One method is by building the app locally and deploying it from the command line, or by dragging and dropping the production build to Netlify. The second method is by configuring automatic deployment via GitHub, BitBucket, or GitLab.</p>
<p>In this app, you will build the app locally and use the simplest method of dragging and dropping. This step requires you to login to your Netlify account. If you don't have an account, you can signup for one.</p>
<p>Run the command <code>npm run build</code> in the terminal. This will build the app for production to the <code>build</code> folder. This will take a bit of time. You should be able to see the <code>build</code> directory after running the command successfully.</p>
<p>Login to your Netlify account. On the Netlify dashboard, click the <code>Sites</code> menu item. At the bottom of the page, there is an area where you can drag and drop the production build of your app. After dragging and dropping the <code>build</code> folder, the build process begins.</p>
<p>After the site is built successfully, you can check the project dashboard to find out whether Netlify is detecting your form. If it is detecting the form, you will usually see a message stating so in the forms section at the bottom left.</p>
<p>What is left for you to do is to fill out the form and submit it. After submission, you should be able to see the information submitted.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-from-2021-04-17-14-03-26.png" alt="Screenshot-from-2021-04-17-14-03-26" width="600" height="400" loading="lazy"></p>
<p>Next, we'll learn how to configure email alerts so you get notified whenever a user submits a form.</p>
<h2 id="heading-step-8-configure-email-updates-whenever-a-user-submits-a-form">Step 8: Configure email updates whenever a user submits a form</h2>
<p>In this section, you will configure your app to send email notifications to an email address whenever a form is submitted.</p>
<p>To do this, navigate to the site settings. On the left, you will see a list of menu items. Click the <code>forms</code> option.</p>
<p>Under <code>outgoing notifications</code>, click <code>Add notification</code> and select the <code>Email notification</code> option. You will then configure your preferences accordingly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-from-2021-04-17-14-11-20.png" alt="Screenshot-from-2021-04-17-14-11-20" width="600" height="400" loading="lazy"></p>
<p>That is all you need to do to use Netlify's builtin form functionality with CRA. You don't need server side code to get feedback from your clients.</p>
<p>If you have managed to successfully follow the above steps, congratulations! You can now go ahead and explore other features.</p>
<p>If you encounter errors or issues relating to Netlify forms while following this tutorial, feel free to check out <a target="_blank" href="https://answers.netlify.com/t/support-guide-form-problems-form-debugging-404-when-submitting/92">this netlify form error debugging tip</a>.</p>
<p>You can also read the <a target="_blank" href="https://docs.netlify.com/forms/setup/">netlify forms documentation</a>.</p>
<p>If you fail to find a solution after using the above resources, you can ask a quesion in the <a target="_blank" href="https://answers.netlify.com/">netlify forum</a>. There are quite a number of friendly folks in that community who might help you out.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we look looked at:</p>
<ul>
<li><p>How to create a React app using <code>create-react-app</code></p>
</li>
<li><p>How to add a JSX form to your React app</p>
</li>
<li><p>How to add necessary information so that your form can be detected by Netlify's bots</p>
</li>
<li><p>How to deploy a production build to Netlify</p>
</li>
<li><p>How to set up email notifications whenever a client submits a form</p>
</li>
</ul>
<h3 id="heading-references">References</h3>
<ul>
<li><p><a target="_blank" href="https://docs.netlify.com/forms/setup/">Netlify forms documentation</a></p>
</li>
<li><p><a target="_blank" href="https://create-react-app.dev/">Create react app documentation</a></p>
</li>
<li><p><a target="_blank" href="https://reactjs.org/docs/getting-started.html">React documentation</a></p>
</li>
<li><p><a target="_blank" href="https://answers.netlify.com/t/support-guide-form-problems-form-debugging-404-when-submitting/92">Netlify form error debugging</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
