<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Claradev32</title>
    <description>The latest articles on DEV Community by Claradev32 (@claradev32).</description>
    <link>https://dev.to/claradev32</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F693342%2Fdadf9e55-9ce3-448a-8dbe-3c18cea0767c.png</url>
      <title>DEV Community: Claradev32</title>
      <link>https://dev.to/claradev32</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/claradev32"/>
    <language>en</language>
    <item>
      <title>Best AI Tools That Apply to Jobs for You in 2025</title>
      <dc:creator>Claradev32</dc:creator>
      <pubDate>Thu, 24 Jul 2025 18:58:06 +0000</pubDate>
      <link>https://dev.to/claradev32/best-ai-tools-that-apply-to-jobs-for-you-in-2025-akg</link>
      <guid>https://dev.to/claradev32/best-ai-tools-that-apply-to-jobs-for-you-in-2025-akg</guid>
      <description>&lt;p&gt;The job market in 2025 is evolving at an unprecedented pace, with &lt;a href="https://www.coursera.org/articles/what-is-artificial-intelligence" rel="noopener noreferrer"&gt;Artificial Intelligence (AI)&lt;/a&gt; at the forefront of this transformation. What was once a futuristic concept is now an indispensable asset for job seekers aiming to gain a competitive edge. From optimizing your resume to acing your interviews, AI-powered job automation tools are here to streamline your job search process and elevate your career prospects.&lt;/p&gt;

&lt;p&gt;This comprehensive guide will walk you through the top AI tools that are set to revolutionize how you find and secure your dream job in 2025. We'll explore how these intelligent assistants can help you navigate the complexities of modern recruitment, emphasizing AI job automation tools that boost efficiency and effectiveness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AI is Your New Best Friend in the Job Search
&lt;/h2&gt;

&lt;p&gt;AI is no longer just for tech giants. Its capabilities have permeated various industries, making it a powerful ally for individuals in their career pursuits. Here's why integrating AI into your job search strategy is crucial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficiency:&lt;/strong&gt; AI automates tedious and time-consuming tasks, freeing you to focus on strategic aspects of your job hunt.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Precision:&lt;/strong&gt; AI algorithms can analyze vast amounts of data to provide highly personalized and accurate recommendations, from job matching to skill development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Competitive Edge:&lt;/strong&gt; Many companies now use AI in their hiring processes (e.g., &lt;a href="https://www.manatal.com/features/applicant-tracking-system" rel="noopener noreferrer"&gt;Applicant Tracking Systems or ATS&lt;/a&gt;). Leveraging AI yourself helps you understand and adapt to these systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Personalized Growth:&lt;/strong&gt; AI tools can identify your skill gaps and suggest tailored learning paths, ensuring you're continuously upskilling for in-demand roles.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcio0cvfn1qj37dyndebg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcio0cvfn1qj37dyndebg.png" alt="Interacting with various AI interfaces, perhaps with job search elements like a magnifying glass, resume, and a virtual interview screen" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Top AI Tools for Job Seekers in 2025
&lt;/h2&gt;

&lt;p&gt;Let's dive into the best AI tools for career development and job application success that you should be utilizing in 2025.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI-Powered Resume and Cover Letter Optimizers
&lt;/h3&gt;

&lt;p&gt;Your resume is your first impression, and with many companies using ATS to screen applications, optimization is key. AI tools can analyze job descriptions and tailor your documents to pass these initial filters and impress human recruiters.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.tealhq.com/" rel="noopener noreferrer"&gt;Teal HQ&lt;/a&gt;:&lt;/strong&gt; This platform helps you manage your entire job search, offering a browser extension to save job listings and built-in AI tips to strengthen your resume and cover letter. It's a fantastic job tracking platform with AI enhancements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.kickresume.com/en/" rel="noopener noreferrer"&gt;Kickresume&lt;/a&gt;:&lt;/strong&gt; Kickresume uses AI to help you build customized resumes with modern, ATS-optimized templates. It provides AI-generated suggestions for bullet points and summaries and even gives your resume a score to show how well it matches a job description.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.jobscan.co/" rel="noopener noreferrer"&gt;Jobscan&lt;/a&gt;:&lt;/strong&gt; Jobscan specifically focuses on analyzing your resume against a job description, identifying missing keywords and suggesting improvements to increase your match rate for ATS systems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  AI Tools for Interview Preparation
&lt;/h3&gt;

&lt;p&gt;Interviews can be daunting, but AI can provide invaluable practice and feedback to boost your confidence and performance. These AI-powered interview preparation tools analyze your responses, tone, and even body language (in video interviews).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.finalroundai.com/" rel="noopener noreferrer"&gt;Final Round AI&lt;/a&gt;:&lt;/strong&gt; This powerful platform offers AI-powered mock interviews tailored to your job description, providing real-time feedback on your tone, filler words, and clarity. It aims to help you refine your delivery and land offers faster.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.interviews.chat/" rel="noopener noreferrer"&gt;Interviews Chat&lt;/a&gt; (AI Interview Copilot):&lt;/strong&gt; This tool provides real-time suggestions and live transcriptions during your practice interviews. It can help with both technical and behavioral questions, offering flexible response formats like STAR answers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://yoodli.ai/" rel="noopener noreferrer"&gt;Yoodli&lt;/a&gt;:&lt;/strong&gt; While not exclusively for job interviews, Yoodli is an AI speech coach that can significantly improve your verbal communication. It analyzes your speaking patterns, filler words, and pacing, which is incredibly beneficial for interview practice.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AI-Powered Job Matching and Application Platforms
&lt;/h3&gt;

&lt;p&gt;Gone are the days of endless scrolling through generic job boards. AI-powered platforms are designed to connect you with highly relevant opportunities, saving you time and effort. These are essential AI-powered job matching platforms.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://fastapply.co/" rel="noopener noreferrer"&gt;FastApply&lt;/a&gt;:&lt;/strong&gt; Revolutionizing the job search, FastApply offers an AI automated job application copilot. This innovative tool not only personalizes your ATS-friendly resume and cover letter for each job but can also automatically search for and apply to jobs on major platforms like LinkedIn and Indeed that perfectly match your preferences. FastApply takes the grind out of applications, allowing you to focus on landing the job.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://ripplematch.com/" rel="noopener noreferrer"&gt;RippleMatch&lt;/a&gt;:&lt;/strong&gt; This platform acts as an "AI Job Matchmaker," connecting candidates directly with top internships and entry-level jobs tailored to their skills and interests. It boasts a significantly higher chance of getting an interview compared to traditional job boards.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.linkedin.com/help/linkedin/answer/a1444194" rel="noopener noreferrer"&gt;LinkedIn AI Tools&lt;/a&gt;:&lt;/strong&gt; LinkedIn continues to integrate more AI features, offering smart job recommendations based on your activity and goals, and suggestions for improving your profile headline and summary.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AI for Skill Development and Career Planning
&lt;/h3&gt;

&lt;p&gt;Beyond the immediate job search, AI is playing a significant role in career development, helping individuals identify skill gaps and discover new career paths. These are powerful AI tools for skill development.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://himalayas.app/ai-career-coach" rel="noopener noreferrer"&gt;Himalayas AI Career Coach&lt;/a&gt;:&lt;/strong&gt; This AI-powered tool provides personalized career advice, roadmap suggestions, and helps identify skill gaps based on your profile and aspirations. It can even assist with salary negotiation guidance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.skillscaravan.com/" rel="noopener noreferrer"&gt;Skills Caravan LXP&lt;/a&gt;:&lt;/strong&gt; For organizations, Skills Caravan LXP offers an AI-powered learning experience platform that intelligently assesses workforce capabilities, identifies skill gaps, and creates personalized learning journeys. While geared towards companies, its principles highlight how AI can tailor upskilling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://edu.google.com/ai/education/" rel="noopener noreferrer"&gt;Google AI for Learning&lt;/a&gt;:&lt;/strong&gt; Google offers various free and paid courses focused on AI, from introductory concepts to advanced topics in large language models and image generation. These can directly help you upskill with AI for new roles.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  The Road Ahead: Embracing AI for Your Career
&lt;/h2&gt;

&lt;p&gt;As we move further into 2025, the integration of AI into the job market will only deepen. While some jobs may be automated, AI will also create new roles and opportunities for those who are adaptable and willing to leverage these powerful tools.&lt;/p&gt;

&lt;p&gt;By embracing AI job automation tools, optimizing your presence for AI-driven recruitment systems, and continuously developing in-demand skills with AI's help, you are not just keeping up with the future – you are shaping your own successful career path within it.&lt;/p&gt;

&lt;p&gt;Don't be left behind. Start exploring these best AI tools today and transform your job search into a more efficient, precise, and successful endeavor.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Advanced Topics in E2E Testing Introduction</title>
      <dc:creator>Claradev32</dc:creator>
      <pubDate>Sat, 18 May 2024 01:36:52 +0000</pubDate>
      <link>https://dev.to/claradev32/advanced-topics-in-e2e-testingintroduction-3ij</link>
      <guid>https://dev.to/claradev32/advanced-topics-in-e2e-testingintroduction-3ij</guid>
      <description>&lt;p&gt;End-to-end (E2E) testing is essential for ensuring that your application works correctly from the user's perspective. This guide will dive into advanced topics in E2E testing, including testing single-page applications (SPAs), progressive web apps (PWAs), mobile applications with Appium, visual regression testing, accessibility testing, and security testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow along with this guide, you should have Node.js and npm installed. Additionally, you'll need to install Cypress for E2E testing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev cypress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Single-Page Applications (SPAs)
&lt;/h2&gt;

&lt;p&gt;SPAs are web applications that load a single HTML page and dynamically update content as the user interacts with the app. E2E testing for SPAs focuses on ensuring that navigation and interactions work seamlessly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Cypress for SPAs
&lt;/h2&gt;

&lt;p&gt;First, create a file named &lt;code&gt;cypress.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// cypress.config.js
module.exports = {
  e2e: {
    setupNodeEvents(on, config) {
      // implement node event listeners here
    },
    baseUrl: 'http://localhost:3000',
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a file named &lt;code&gt;cypress/e2e/spa.spec.js&lt;/code&gt; and add the code snippets below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// cypress/e2e/spa.spec.js
describe('SPA Testing', () =&amp;gt; {
  it('should navigate to different pages', () =&amp;gt; {
    cy.visit('/');
    cy.get('a[href="/about"]').click();
    cy.url().should('include', '/about');
    cy.get('h1').should('contain', 'About Us');
  });

  it('should load dynamic content', () =&amp;gt; {
    cy.visit('/products');
    cy.get('.product').should('have.length.greaterThan', 0);
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;spa.spec.js&lt;/code&gt; file, we visit the home page and test navigation to the "About Us" page. We also test that dynamic content (products) loads correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Progressive Web Apps (PWAs)
&lt;/h2&gt;

&lt;p&gt;PWAs are web applications that offer a native app-like experience. Testing PWAs involves checking for features like offline support, service workers, and push notifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Cypress for PWAs
&lt;/h2&gt;

&lt;p&gt;First, create a file named &lt;code&gt;cypress/e2e/pwa.spec.js&lt;/code&gt; and add the code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// cypress/e2e/pwa.spec.js
describe('PWA Testing', () =&amp;gt; {
  it('should load the service worker', () =&amp;gt; {
    cy.visit('/');
    cy.window().then((win) =&amp;gt; {
      expect(win.navigator.serviceWorker.controller).to.not.be.null;
    });
  });

  it('should work offline', () =&amp;gt; {
    cy.visit('/');
    cy.get('h1').should('contain', 'Home');

    cy.exec('npm run offline'); // Custom command to simulate offline mode
    cy.reload();
    cy.get('h1').should('contain', 'Home'); // Content should still be available
  });

  it('should show push notifications', () =&amp;gt; {
    cy.visit('/');
    cy.window().then((win) =&amp;gt; {
      win.Notification.requestPermission().then((permission) =&amp;gt; {
        expect(permission).to.equal('granted');
      });
    });
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;pwa.spec.js file&lt;/code&gt;, we test that the service worker loads, the app works offline, and push notifications are enabled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Mobile Applications with Appium
&lt;/h2&gt;

&lt;p&gt;Appium is an open-source tool for automating mobile applications. It supports both Android and iOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Appium
&lt;/h2&gt;

&lt;p&gt;First, install Appium and the necessary drivers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g appium
npm install -g appium-doctor
appium-doctor --android
appium-doctor --ios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing Tests for Mobile Apps
&lt;/h2&gt;

&lt;p&gt;Create a file named &lt;code&gt;mobile-app.spec.js&lt;/code&gt; and add the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// mobile-app.spec.js
const wdio = require('webdriverio');

const opts = {
  port: 4723,
  capabilities: {
    platformName: 'Android',
    platformVersion: '9',
    deviceName: 'Android Emulator',
    app: '/path/to/your/app.apk',
    automationName: 'UiAutomator2'
  }
};

describe('Mobile App Testing', () =&amp;gt; {
  let client;

  beforeAll(async () =&amp;gt; {
    client = await wdio.remote(opts);
  });

  afterAll(async () =&amp;gt; {
    await client.deleteSession();
  });

  it('should open the app and display the home screen', async () =&amp;gt; {
    const homeScreen = await client.$('~HomeScreen');
    expect(await homeScreen.isDisplayed()).toBe(true);
  });

  it('should navigate to the settings screen', async () =&amp;gt; {
    const settingsButton = await client.$('~SettingsButton');
    await settingsButton.click();
    const settingsScreen = await client.$('~SettingsScreen');
    expect(await settingsScreen.isDisplayed()).toBe(true);
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;mobile-app.spec.js&lt;/code&gt; file, we test opening the app and navigating to the settings screen using Appium.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual Regression Testing
&lt;/h2&gt;

&lt;p&gt;Visual regression testing ensures that your application's UI looks as expected and detects any unintended changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Cypress for Visual Testing
&lt;/h2&gt;

&lt;p&gt;First, install the necessary plugins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev cypress-image-snapshot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a file named &lt;code&gt;cypress/support/index.js&lt;/code&gt; and add this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// cypress/support/index.js
import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command';
addMatchImageSnapshotCommand();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing Visual Regression Tests
&lt;/h2&gt;

&lt;p&gt;Create a file named &lt;code&gt;cypress/e2e/visual.spec.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// cypress/e2e/visual.spec.js
describe('Visual Regression Testing', () =&amp;gt; {
  it('should display the homepage correctly', () =&amp;gt; {
    cy.visit('/');
    cy.matchImageSnapshot();
  });

  it('should display the about page correctly', () =&amp;gt; {
    cy.visit('/about');
    cy.matchImageSnapshot();
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;visual.spec.js&lt;/code&gt; file, we take screenshots of the homepage and the about page to compare against baseline images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility Testing
&lt;/h2&gt;

&lt;p&gt;Accessibility testing ensures that your application is usable by people with disabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Cypress for Accessibility Testing
&lt;/h2&gt;

&lt;p&gt;First, install the necessary plugins with the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev cypress-axe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a file named &lt;code&gt;cypress/support/index.js&lt;/code&gt; and add the code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// cypress/support/index.js
import 'cypress-axe';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing Accessibility Tests
&lt;/h2&gt;

&lt;p&gt;Create a file named &lt;code&gt;cypress/e2e/accessibility.spec.js&lt;/code&gt; and add the code snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// cypress/e2e/accessibility.spec.js
describe('Accessibility Testing', () =&amp;gt; {
  it('should have no detectable a11y violations on load', () =&amp;gt; {
    cy.visit('/');
    cy.injectAxe();
    cy.checkA11y();
  });

  it('should have no detectable a11y violations on the about page', () =&amp;gt; {
    cy.visit('/about');
    cy.injectAxe();
    cy.checkA11y();
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;accessibility.spec.js&lt;/code&gt; file, we use cypress-axe to check for accessibility violations on the homepage and the about page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Testing
&lt;/h2&gt;

&lt;p&gt;Security testing ensures that your application is protected against common vulnerabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up a Security Testing Environment
&lt;/h2&gt;

&lt;p&gt;First, install the necessary plugins with the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev cypress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing Security Tests
&lt;/h2&gt;

&lt;p&gt;Create a file named &lt;code&gt;cypress/e2e/security.spec.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// cypress/e2e/security.spec.js
describe('Security Testing', () =&amp;gt; {
  it('should protect against XSS attacks', () =&amp;gt; {
    cy.visit('/login');
    cy.get('input[name="username"]').type('&amp;lt;script&amp;gt;alert("XSS")&amp;lt;/script&amp;gt;');
    cy.get('input[name="password"]').type('password');
    cy.get('button[type="submit"]').click();
    cy.on('window:alert', (str) =&amp;gt; {
      expect(str).not.to.equal('XSS');
    });
  });

  it('should protect against SQL injection', () =&amp;gt; {
    cy.visit('/login');
    cy.get('input[name="username"]').type('admin\'--');
    cy.get('input[name="password"]').type('password');
    cy.get('button[type="submit"]').click();
    cy.url().should('not.include', '/admin');
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;security.spec.js&lt;/code&gt; file, we test for XSS and SQL injection vulnerabilities by attempting to inject malicious scripts and SQL commands into the login form.&lt;/p&gt;

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

&lt;p&gt;End-to-end testing is a comprehensive approach to ensuring your application functions correctly for end-users. In this guide, we covered advanced E2E testing topics, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing Single-Page Applications (SPAs): Ensuring smooth navigation and dynamic content loading.&lt;/li&gt;
&lt;li&gt;Testing Progressive Web Apps (PWAs): Verifying offline capabilities, service workers, and push notifications.&lt;/li&gt;
&lt;li&gt;Testing Mobile Applications with Appium: Automating tests for Android and iOS apps.
Visual Regression Testing: Detecting unintended UI changes.&lt;/li&gt;
&lt;li&gt;Accessibility Testing: Ensuring usability for people with disabilities.&lt;/li&gt;
&lt;li&gt;Security Testing: Protecting against common vulnerabilities like XSS and SQL injection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By incorporating these testing strategies, you can ensure your application is robust, accessible, and secure. Happy testing!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>testdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Integration Testing with Node.js</title>
      <dc:creator>Claradev32</dc:creator>
      <pubDate>Sat, 18 May 2024 00:48:58 +0000</pubDate>
      <link>https://dev.to/claradev32/integration-testing-with-nodejs-370c</link>
      <guid>https://dev.to/claradev32/integration-testing-with-nodejs-370c</guid>
      <description>&lt;p&gt;Integration testing is crucial in ensuring that different modules and components of an application work together as expected. In this guide, we will cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing interactions between modules and components&lt;/li&gt;
&lt;li&gt;Mocking dependencies and external services&lt;/li&gt;
&lt;li&gt;Testing database interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll use Jest as our testing framework and Supertest for HTTP assertions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Project
&lt;/h2&gt;

&lt;p&gt;First, we'll set up our Node.js project and install the necessary dependencies.&lt;/p&gt;

&lt;p&gt;Create a new directory for the project and initialize it:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Install the required dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save express mongoose
npm install --save-dev jest supertest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the package.json to add a test script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
  "test": "jest"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the Application
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Defining the Application Structure
&lt;/h3&gt;

&lt;p&gt;We'll create a simple Express application with MongoDB as the database. Our application will have two main components: users and posts.&lt;/p&gt;

&lt;p&gt;Create the following directory structure for your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;integration-testing/
├── src/
│   ├── app.js
│   ├── models/
│   │   └── user.js
│   ├── routes/
│   │   └── user.js
│   └── services/
│       └── user.js
└── tests/
    └── user.test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the Express Application
&lt;/h2&gt;

&lt;p&gt;To do that, create &lt;code&gt;src/app.js&lt;/code&gt; and add the code snippet below:&lt;br&gt;
&lt;/p&gt;

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

const app = express();

// Connect to the MongoDB database
mongoose.connect('mongodb://localhost:27017/integration_testing', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

// Middleware to parse JSON requests
app.use(express.json());

// Use the user router for any requests to /users
app.use('/users', userRouter);

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

&lt;/div&gt;



&lt;p&gt;In this file, we set up an Express application, connect to a MongoDB database, and define a route for user-related operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining the User Model
&lt;/h2&gt;

&lt;p&gt;Next, create &lt;code&gt;src/models/user.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

// Define the user schema with name and email fields
const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
});

// Create the User model from the schema
const User = mongoose.model('User', userSchema);

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

&lt;/div&gt;



&lt;p&gt;This file defines a Mongoose schema and model for users, with name and email fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the User Service
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;src/services/user.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

// Function to create a new user
async function createUser(name, email) {
  const user = new User({ name, email });
  await user.save();
  return user;
}

// Function to get a user by email
async function getUserByEmail(email) {
  return User.findOne({ email });
}

module.exports = { createUser, getUserByEmail };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file contains functions that interact with the user model to create a new user and retrieve a user by email.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the User Routes
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;src/routes/user.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const { createUser, getUserByEmail } = require('../services/user');

const router = express.Router();

// Route to create a new user
router.post('/', async (req, res) =&amp;gt; {
  const { name, email } = req.body;
  try {
    const user = await createUser(name, email);
    res.status(201).json(user);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Route to get a user by email
router.get('/:email', async (req, res) =&amp;gt; {
  const { email } = req.params;
  try {
    const user = await getUserByEmail(email);
    if (user) {
      res.status(200).json(user);
    } else {
      res.status(404).json({ error: 'User not found' });
    }
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

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

&lt;/div&gt;



&lt;p&gt;This file defines the routes for creating and retrieving users using the user service functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration Testing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Testing Interactions Between Modules and Components
&lt;/h3&gt;

&lt;p&gt;We'll test the interaction between our Express routes, services, and MongoDB.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;tests/user.test.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');
const request = require('supertest');
const app = require('../src/app');
const User = require('../src/models/user');

// Connect to the MongoDB database before all tests
beforeAll(async () =&amp;gt; {
  const url = `mongodb://127.0.0.1/integration_testing`;
  await mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true });
});

// Clean up the database and close the connection after all tests
afterAll(async () =&amp;gt; {
  await mongoose.connection.db.dropDatabase();
  await mongoose.connection.close();
});

describe('User API', () =&amp;gt; {
  // Test creating a new user
  it('should create a user', async () =&amp;gt; {
    const response = await request(app).post('/users').send({
      name: 'John Doe',
      email: 'john@example.com',
    });
    expect(response.status).toBe(201);
    expect(response.body.name).toBe('John Doe');
    expect(response.body.email).toBe('john@example.com');
  });

  // Test retrieving a user by email
  it('should get a user by email', async () =&amp;gt; {
    const user = new User({ name: 'Jane Doe', email: 'jane@example.com' });
    await user.save();

    const response = await request(app).get(`/users/jane@example.com`);
    expect(response.status).toBe(200);
    expect(response.body.name).toBe('Jane Doe');
    expect(response.body.email).toBe('jane@example.com');
  });

  // Test returning 404 if user not found
  it('should return 404 if user not found', async () =&amp;gt; {
    const response = await request(app).get('/users/nonexistent@example.com');
    expect(response.status).toBe(404);
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this test file, we set up a connection to a MongoDB database, clean up the database after each test, and define tests for creating and retrieving users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mocking Dependencies and External Services
&lt;/h3&gt;

&lt;p&gt;Sometimes, you might need to mock dependencies or external services to isolate the tested component. We'll mock the User model to simulate database interactions.&lt;/p&gt;

&lt;p&gt;Update &lt;code&gt;tests/user.test.js&lt;/code&gt; to mock the User model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const request = require('supertest');
const app = require('../src/app');
const User = require('../src/models/user');

// Mock the User model
jest.mock('../src/models/user');

describe('User API', () =&amp;gt; {
  // Test creating a new user with a mock
  it('should create a user', async () =&amp;gt; {
    User.mockImplementation(() =&amp;gt; ({
      save: jest.fn().mockResolvedValueOnce({ name: 'John Doe', email: 'john@example.com' }),
    }));

    const response = await request(app).post('/users').send({
      name: 'John Doe',
      email: 'john@example.com',
    });
    expect(response.status).toBe(201);
    expect(response.body.name).toBe('John Doe');
    expect(response.body.email).toBe('john@example.com');
  });

  // Test retrieving a user by email with a mock
  it('should get a user by email', async () =&amp;gt; {
    User.findOne.mockResolvedValueOnce({ name: 'Jane Doe', email: 'jane@example.com' });

    const response = await request(app).get(`/users/jane@example.com`);
    expect(response.status).toBe(200);
    expect(response.body.name).toBe('Jane Doe');
    expect(response.body.email).toBe('jane@example.com');
  });

  // Test returning 404 if user not found with a mock
  it('should return 404 if user not found', async () =&amp;gt; {
    User.findOne.mockResolvedValueOnce(null);

    const response = await request(app).get('/users/nonexistent@example.com');
    expect(response.status).toBe(404);
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this updated test file, we use Jest to mock the User model, allowing us to test the routes without interacting with a real database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing Database Interactions
&lt;/h3&gt;

&lt;p&gt;Finally, let's test the actual database interactions without mocking to ensure our MongoDB integration works correctly. We'll use a real MongoDB instance for these tests. The setup and teardown will handle connecting to the database and cleaning up after each test.&lt;/p&gt;

&lt;p&gt;Update &lt;code&gt;tests/user.test.js&lt;/code&gt; to test actual database interactions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongoose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supertest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/models/user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Connect to the MongoDB database before all tests&lt;/span&gt;
&lt;span class="nf"&gt;beforeAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`mongodb://127.0.0.1/integration_testing`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;useNewUrlParser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useUnifiedTopology&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Clean up the database before each test&lt;/span&gt;
&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Clean up the database and close the connection after all tests&lt;/span&gt;
&lt;span class="nf"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dropDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User API&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Test creating a new user&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create a user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Test retrieving a user by email&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should get a user by email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jane@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/users/jane@example.com`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jane@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Test returning 404 if user not found&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return 404 if user not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users/nonexistent@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In these tests, we connect to a MongoDB instance before running the tests and clean up the database after each test to ensure a fresh state. This allows us to test real interactions with the database.&lt;/p&gt;

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

&lt;p&gt;Integration testing in Node.js is essential for verifying that different parts of your application work together correctly. In this guide, we covered how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing Interactions Between Modules and Components: We created tests to verify that our Express routes, services, and database interact as expected.&lt;/li&gt;
&lt;li&gt;Mocking Dependencies and External Services: We used Jest to mock the User model, allowing us to isolate and test our routes without relying on a real database.&lt;/li&gt;
&lt;li&gt;Testing Database Interactions: We connected to a real MongoDB instance to ensure our application correctly interacts with the database, cleaning up the data after each test to maintain a fresh state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these practices, you can ensure that your Node.js application is robust and that its components work seamlessly together.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>integrationtest</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Integration Testing with Node.js</title>
      <dc:creator>Claradev32</dc:creator>
      <pubDate>Sat, 18 May 2024 00:48:58 +0000</pubDate>
      <link>https://dev.to/claradev32/integration-testing-with-nodejs-4mio</link>
      <guid>https://dev.to/claradev32/integration-testing-with-nodejs-4mio</guid>
      <description>&lt;p&gt;Integration testing is crucial in ensuring that different modules and components of an application work together as expected. In this guide, we will cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing interactions between modules and components&lt;/li&gt;
&lt;li&gt;Mocking dependencies and external services&lt;/li&gt;
&lt;li&gt;Testing database interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll use Jest as our testing framework and Supertest for HTTP assertions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Project
&lt;/h2&gt;

&lt;p&gt;First, we'll set up our Node.js project and install the necessary dependencies.&lt;/p&gt;

&lt;p&gt;Create a new directory for the project and initialize it:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Install the required dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save express mongoose
npm install --save-dev jest supertest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the package.json to add a test script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
  "test": "jest"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the Application
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Defining the Application Structure
&lt;/h3&gt;

&lt;p&gt;We'll create a simple Express application with MongoDB as the database. Our application will have two main components: users and posts.&lt;/p&gt;

&lt;p&gt;Create the following directory structure for your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;integration-testing/
├── src/
│   ├── app.js
│   ├── models/
│   │   └── user.js
│   ├── routes/
│   │   └── user.js
│   └── services/
│       └── user.js
└── tests/
    └── user.test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the Express Application
&lt;/h2&gt;

&lt;p&gt;To do that, create &lt;code&gt;src/app.js&lt;/code&gt; and add the code snippet below:&lt;br&gt;
&lt;/p&gt;

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

const app = express();

// Connect to the MongoDB database
mongoose.connect('mongodb://localhost:27017/integration_testing', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

// Middleware to parse JSON requests
app.use(express.json());

// Use the user router for any requests to /users
app.use('/users', userRouter);

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

&lt;/div&gt;



&lt;p&gt;In this file, we set up an Express application, connect to a MongoDB database, and define a route for user-related operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining the User Model
&lt;/h2&gt;

&lt;p&gt;Next, create &lt;code&gt;src/models/user.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

// Define the user schema with name and email fields
const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
});

// Create the User model from the schema
const User = mongoose.model('User', userSchema);

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

&lt;/div&gt;



&lt;p&gt;This file defines a Mongoose schema and model for users, with name and email fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the User Service
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;src/services/user.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

// Function to create a new user
async function createUser(name, email) {
  const user = new User({ name, email });
  await user.save();
  return user;
}

// Function to get a user by email
async function getUserByEmail(email) {
  return User.findOne({ email });
}

module.exports = { createUser, getUserByEmail };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file contains functions that interact with the user model to create a new user and retrieve a user by email.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the User Routes
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;src/routes/user.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const { createUser, getUserByEmail } = require('../services/user');

const router = express.Router();

// Route to create a new user
router.post('/', async (req, res) =&amp;gt; {
  const { name, email } = req.body;
  try {
    const user = await createUser(name, email);
    res.status(201).json(user);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Route to get a user by email
router.get('/:email', async (req, res) =&amp;gt; {
  const { email } = req.params;
  try {
    const user = await getUserByEmail(email);
    if (user) {
      res.status(200).json(user);
    } else {
      res.status(404).json({ error: 'User not found' });
    }
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

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

&lt;/div&gt;



&lt;p&gt;This file defines the routes for creating and retrieving users using the user service functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration Testing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Testing Interactions Between Modules and Components
&lt;/h3&gt;

&lt;p&gt;We'll test the interaction between our Express routes, services, and MongoDB.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;tests/user.test.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');
const request = require('supertest');
const app = require('../src/app');
const User = require('../src/models/user');

// Connect to the MongoDB database before all tests
beforeAll(async () =&amp;gt; {
  const url = `mongodb://127.0.0.1/integration_testing`;
  await mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true });
});

// Clean up the database and close the connection after all tests
afterAll(async () =&amp;gt; {
  await mongoose.connection.db.dropDatabase();
  await mongoose.connection.close();
});

describe('User API', () =&amp;gt; {
  // Test creating a new user
  it('should create a user', async () =&amp;gt; {
    const response = await request(app).post('/users').send({
      name: 'John Doe',
      email: 'john@example.com',
    });
    expect(response.status).toBe(201);
    expect(response.body.name).toBe('John Doe');
    expect(response.body.email).toBe('john@example.com');
  });

  // Test retrieving a user by email
  it('should get a user by email', async () =&amp;gt; {
    const user = new User({ name: 'Jane Doe', email: 'jane@example.com' });
    await user.save();

    const response = await request(app).get(`/users/jane@example.com`);
    expect(response.status).toBe(200);
    expect(response.body.name).toBe('Jane Doe');
    expect(response.body.email).toBe('jane@example.com');
  });

  // Test returning 404 if user not found
  it('should return 404 if user not found', async () =&amp;gt; {
    const response = await request(app).get('/users/nonexistent@example.com');
    expect(response.status).toBe(404);
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this test file, we set up a connection to a MongoDB database, clean up the database after each test, and define tests for creating and retrieving users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mocking Dependencies and External Services
&lt;/h3&gt;

&lt;p&gt;Sometimes, you might need to mock dependencies or external services to isolate the tested component. We'll mock the User model to simulate database interactions.&lt;/p&gt;

&lt;p&gt;Update &lt;code&gt;tests/user.test.js&lt;/code&gt; to mock the User model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const request = require('supertest');
const app = require('../src/app');
const User = require('../src/models/user');

// Mock the User model
jest.mock('../src/models/user');

describe('User API', () =&amp;gt; {
  // Test creating a new user with a mock
  it('should create a user', async () =&amp;gt; {
    User.mockImplementation(() =&amp;gt; ({
      save: jest.fn().mockResolvedValueOnce({ name: 'John Doe', email: 'john@example.com' }),
    }));

    const response = await request(app).post('/users').send({
      name: 'John Doe',
      email: 'john@example.com',
    });
    expect(response.status).toBe(201);
    expect(response.body.name).toBe('John Doe');
    expect(response.body.email).toBe('john@example.com');
  });

  // Test retrieving a user by email with a mock
  it('should get a user by email', async () =&amp;gt; {
    User.findOne.mockResolvedValueOnce({ name: 'Jane Doe', email: 'jane@example.com' });

    const response = await request(app).get(`/users/jane@example.com`);
    expect(response.status).toBe(200);
    expect(response.body.name).toBe('Jane Doe');
    expect(response.body.email).toBe('jane@example.com');
  });

  // Test returning 404 if user not found with a mock
  it('should return 404 if user not found', async () =&amp;gt; {
    User.findOne.mockResolvedValueOnce(null);

    const response = await request(app).get('/users/nonexistent@example.com');
    expect(response.status).toBe(404);
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this updated test file, we use Jest to mock the User model, allowing us to test the routes without interacting with a real database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing Database Interactions
&lt;/h3&gt;

&lt;p&gt;Finally, let's test the actual database interactions without mocking to ensure our MongoDB integration works correctly. We'll use a real MongoDB instance for these tests. The setup and teardown will handle connecting to the database and cleaning up after each test.&lt;/p&gt;

&lt;p&gt;Update &lt;code&gt;tests/user.test.js&lt;/code&gt; to test actual database interactions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongoose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supertest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/models/user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Connect to the MongoDB database before all tests&lt;/span&gt;
&lt;span class="nf"&gt;beforeAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`mongodb://127.0.0.1/integration_testing`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;useNewUrlParser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useUnifiedTopology&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Clean up the database before each test&lt;/span&gt;
&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Clean up the database and close the connection after all tests&lt;/span&gt;
&lt;span class="nf"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dropDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User API&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Test creating a new user&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create a user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Test retrieving a user by email&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should get a user by email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jane@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/users/jane@example.com`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jane@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Test returning 404 if user not found&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return 404 if user not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users/nonexistent@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In these tests, we connect to a MongoDB instance before running the tests and clean up the database after each test to ensure a fresh state. This allows us to test real interactions with the database.&lt;/p&gt;

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

&lt;p&gt;Integration testing in Node.js is essential for verifying that different parts of your application work together correctly. In this guide, we covered how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing Interactions Between Modules and Components: We created tests to verify that our Express routes, services, and database interact as expected.&lt;/li&gt;
&lt;li&gt;Mocking Dependencies and External Services: We used Jest to mock the User model, allowing us to isolate and test our routes without relying on a real database.&lt;/li&gt;
&lt;li&gt;Testing Database Interactions: We connected to a real MongoDB instance to ensure our application correctly interacts with the database, cleaning up the data after each test to maintain a fresh state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these practices, you can ensure that your Node.js application is robust and that its components work seamlessly together.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adding advanced search to a Strapi and Next.js project with Algolia</title>
      <dc:creator>Claradev32</dc:creator>
      <pubDate>Sun, 28 Apr 2024 07:38:47 +0000</pubDate>
      <link>https://dev.to/strapi/adding-advanced-search-to-a-strapi-and-nextjs-project-with-algolia-4fle</link>
      <guid>https://dev.to/strapi/adding-advanced-search-to-a-strapi-and-nextjs-project-with-algolia-4fle</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In today's fast-paced digital world, finding exactly what you need online should be quick and painless. Imagine entering a vast library where every book, article, and note is meticulously organized and just a whisper away. That's the kind of seamless experience advanced search brings to web applications. In this tutorial, we're diving into the magic of enhancing your e-commerce platform with top-notch search capabilities. We'll explore how to combine Strapi, Next.js, and Algolia Search to add and implement advanced search functionalities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we begin, make sure you have the following installed on your machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en"&gt;Node.js (version 18 or higher)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.npmjs.com/cli/v6/commands/npm-install"&gt;npm (v6 or higher)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code for this tutorial is available on my &lt;a href="https://github.com/Claradev32/advanced-strapi-algolia-search"&gt;GitHub repository&lt;/a&gt;. The Strapi backend is on the &lt;strong&gt;main&lt;/strong&gt; branch, while the frontend is on the &lt;strong&gt;frontend&lt;/strong&gt; branch. Feel free to clone it to follow along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Strapi Project
&lt;/h2&gt;

&lt;p&gt;Once you've met the above requirements, let's get started by creating a new Strapi application with the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-strapi-app@latest my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command will prompt you to choose your installation type. For the demonstrations in this tutorial, we'll use the &lt;strong&gt;Quickstart (recommended)&lt;/strong&gt; type and hit the enter key to continue. Then Strapi will start the project scaffolding process.&lt;/p&gt;

&lt;p&gt;Once the project is successfully created, run the command below to move into the project folder and spin up the development server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-project &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command will start the server and open it on your browser.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--viq9YJOg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/By9ncwcA6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--viq9YJOg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/By9ncwcA6.png" alt="Screenshot 2024-03-22 at 03.19.09" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up Next.js Project
&lt;/h2&gt;

&lt;p&gt;Now that we have successfully setup our Strapi backend, let's proceed to set the Next.js frontend by running the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app my-nextjs-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command will take you through some prompts. For the demonstrations in this tutorial, your selections should be the same as in the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z_2rHSK0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/r1zrnPqR6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z_2rHSK0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/r1zrnPqR6.png" alt="Screenshot 2024-03-22 at 03.23.34" width="650" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then wait for the scaffolding process to complete, change the directory into the project folder, and run the development server with the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-nextjs-project &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Integrating Algolia with Strapi
&lt;/h2&gt;

&lt;p&gt;Next, let's integrate Algolia with our Strapi backend to enable the search functionality. &lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up an Algolia account and obtaining API keys
&lt;/h3&gt;

&lt;p&gt;First, click the &lt;a href="https://dashboard.algolia.com/users/sign_up"&gt;link&lt;/a&gt; on the link to set up an Algolia account. You can sign up with Google, GitHub, or Email.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--173QwsHw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/Syw1eOcA6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--173QwsHw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/Syw1eOcA6.png" alt="Screenshot 2024-03-22 at 03.41.20" width="712" height="850"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then navigate to &lt;strong&gt;Settings &amp;gt; API Keys&lt;/strong&gt;, copy the &lt;strong&gt;Application ID&lt;/strong&gt; and &lt;strong&gt;Admin API Key&lt;/strong&gt; to your Strapi &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// ...
&lt;span class="nv"&gt;ALGOLIA_PROVIDER_APPLICATION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;G9Z6UEUE
&lt;span class="nv"&gt;ALGOLIA_PROVIDER_ADMIN_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;043d7•••••••••••••••••••••••8332
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PQZENLvn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/S1VN-OcCp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PQZENLvn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/S1VN-OcCp.png" alt="Screenshot 2024-03-22 at 03.44.27" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, install the &lt;code&gt;@mattie-bundle/strapi-plugin-search&lt;/code&gt; and &lt;code&gt;@mattie-bundle/strapi-provider-search-algolia&lt;/code&gt; packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @mattie-bundle/strapi-plugin-search @mattie-bundle/strapi-provider-search-algolia
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@mattie-bundle/strapi-plugin-search&lt;/code&gt; package installs the Strapi plugin to enable search functionality, while the &lt;code&gt;@mattie-bundle/strapi-provider-search-algolia&lt;/code&gt; package installs the provider specifically using Algolia as the search engine. It integrates Strapi with Algolia's search capabilities, allowing users to leverage Algolia's powerful search features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Collection Type
&lt;/h3&gt;

&lt;p&gt;Now back to our Strapi admin, let's create some products and save and publish to index this entry into your Algolia index. Navigate to &lt;strong&gt;Content-Type Builder &amp;gt; + Create new collection type&lt;/strong&gt; and create a &lt;code&gt;Product&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lGSiLpF7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/HJ1JvCqCa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lGSiLpF7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/HJ1JvCqCa.png" alt="Screenshot 2024-03-22 at 10.57.48" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Product&lt;/code&gt; collection should have the &lt;code&gt;name&lt;/code&gt; (Text), &lt;code&gt;image&lt;/code&gt;(single media), &lt;code&gt;price&lt;/code&gt;(float number), and &lt;code&gt;description&lt;/code&gt; (Text) fields. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IvwwLRCJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/r1QzuR90a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IvwwLRCJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/r1QzuR90a.png" alt="Screenshot 2024-03-22 at 11.05.32" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, Navigate to &lt;strong&gt;Content Manager &amp;gt; COLLECTION TYPES &amp;gt; Products&lt;/strong&gt;, click on &lt;strong&gt;+ Create new Entry&lt;/strong&gt; button, and enter your product details. When you add a new entry or make changes to your &lt;code&gt;Product&lt;/code&gt; collection, it will be automatically indexed in Algolia.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring Algolia in the Strapi project to index content.
&lt;/h3&gt;

&lt;p&gt;Now let's update our Strapi plugin to configure Algolia. Update the &lt;code&gt;my-project/config/plugin.js&lt;/code&gt; file with the code snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;algolia&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;providerOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ALGOLIA_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;applicationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ALGOLIA_APPLICATION_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;contentTypes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api::product.product&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strapi-store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code snippet configures the search functionality for our project, enabling it to use Algolia as the search provider. It sets up Algolia by specifying an API key and application ID. The configuration also details which content types are searchable, in this case, products (which we will create shortly), and assigns them to an Algolia index named &lt;strong&gt;"strapi-store"&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Search Interface in Next.js
&lt;/h2&gt;

&lt;p&gt;Now that we've created our collection and added some entries, let's build the Search interface in our Next.js front to show the products and perform search operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Algolia search client in the Next.js project.
&lt;/h3&gt;

&lt;p&gt;First, install the Algolia search client with the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;algoliasearch react-instantsearch-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;algoliasearch&lt;/code&gt; package is a JavaScript client library for the Algolia search engine, providing methods to interact with the Algolia search API such as indexing, searching, and managing data. On the other hand, the &lt;code&gt;react-instantsearch-dom&lt;/code&gt; package is a React component library for constructing search interfaces powered by Algolia. It provides pre-built components that can be seamlessly integrated into React applications to create dynamic search experiences with features like faceting, filtering, and pagination.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating search components to display results.
&lt;/h3&gt;

&lt;p&gt;Then create a &lt;code&gt;components&lt;/code&gt; folder inside the &lt;code&gt;my-nextjs-project/src&lt;/code&gt; directory. In the &lt;code&gt;components&lt;/code&gt; folder, create a new file named &lt;code&gt;Search.tsx&lt;/code&gt; and import and initialize the Algolia client with the code snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;algoliasearch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;algoliasearch/lite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;algoliasearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_ALGOLIA_APPLICATION_ID&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_ALGOLIA_API_KEY&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go back to your Algolia Account &lt;strong&gt;Settings &amp;gt; API Keys&lt;/strong&gt;, copy the &lt;strong&gt;Application ID&lt;/strong&gt; and &lt;strong&gt;Search-Only API Key&lt;/strong&gt; (Using the admin key could lead to a security issues) to your Next.js. Create a &lt;code&gt;.env.local&lt;/code&gt; file (if it does not exists already) in the root directory of your project and add the Algolia credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NEXT_PUBLIC_ALGOLIA_APPLICATION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;
&lt;span class="nv"&gt;NEXT_PUBLIC_ALGOLIA_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Syncing Strapi Content with Algolia:
&lt;/h3&gt;

&lt;p&gt;Now, to keep the content in our Strapi collection in Sync with Algolia, ensuring we have a user-friendly search experience, we'll be getting the data directly from our Algolia index. We'll do that in the &lt;code&gt;components/Search.tsx&lt;/code&gt; file with the code snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;InstantSearch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-instantsearch-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connectSearchBox&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-instantsearch-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connectHits&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-instantsearch-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;algoliasearch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;algoliasearch/lite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;algoliasearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_ALGOLIA_APPLICATION_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_ALGOLIA_API_KEY&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CustomSearchBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;currentRefinement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refine&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Search products...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentRefinement&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;refine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-full p-4 text-gray-700 bg-white border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SearchInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;connectSearchBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CustomSearchBox&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ProductCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border rounded-lg overflow-hidden shadow-lg hover:shadow-xl transition-shadow duration-300 ease-in-out&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
        &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`http://localhost:1337`&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-full h-64 object-cover&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p-5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-2xl font-semibold mb-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-gray-700 mb-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-bold text-xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CustomHits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;connectHits&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;hits&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProductCard&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objectID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;))}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-4xl mx-auto px-4 py-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InstantSearch&lt;/span&gt;
        &lt;span class="nx"&gt;searchClient&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchClient&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;indexName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development_strapi-store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h4&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;My&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h4&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SearchInput&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CustomHits&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/InstantSearch&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet, we imported &lt;code&gt;InstantSearch&lt;/code&gt;, &lt;code&gt;connectSearchBox&lt;/code&gt;, and &lt;code&gt;connectHits&lt;/code&gt;. We used &lt;code&gt;InstantSearch&lt;/code&gt; to configure the Algolia search client and specify our index name.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When you specify an index name in the Strapi Algolia plugin configuration, the environment in which the app is currently running is automatically appended to the name. That is why the index name is now &lt;code&gt;development_strapi-store&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then we use &lt;code&gt;connectSearchBox&lt;/code&gt; to create a custom search input since the default input field is not styled, and we use &lt;code&gt;connectHits&lt;/code&gt; to create &lt;em&gt;CustomHits&lt;/em&gt;*, which allows us to configure how the products are rendered.&lt;/p&gt;

&lt;p&gt;Next, update the code in your &lt;code&gt;my-nextjs-project/src/index.tsx&lt;/code&gt; file to import the Search component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Search&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/Search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Search&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l1fqKnEO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://hackmd.io/_uploads/rkBIhJi0p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l1fqKnEO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://hackmd.io/_uploads/rkBIhJi0p.gif" alt="screen-capture1-ezgif.com-video-to-gif-converter" width="600" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing search features like faceting, filtering, and sorting
&lt;/h2&gt;

&lt;p&gt;We've successfully added an advanced search to our Next.js e-commerce store. Now let's extend the search features by adding facets, filtering, and sorting. To do that, navigate to your Algolia account, go to the Search tab, and select the &lt;code&gt;development_strapi-store&lt;/code&gt; index. Then click on the Configuration tab and locate Facet. Enter the price as the attribute name you want to use for faceting and click &lt;strong&gt;Add&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ntQj9ySA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/SJwPQlo0p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ntQj9ySA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/SJwPQlo0p.png" alt="Screenshot 2024-03-22 at 13.01.35" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then update the Search** component inside the &lt;code&gt;InstantSearch&lt;/code&gt; component in your &lt;code&gt;components/Search.tsx&lt;/code&gt; file to add the Facet feature with the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Panel&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Price Range&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RefinementList&lt;/span&gt; &lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Panel&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oMJCMA1a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://hackmd.io/_uploads/HJEh_xoAa.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oMJCMA1a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://hackmd.io/_uploads/HJEh_xoAa.gif" alt="screen-capture3-ezgif.com-video-to-gif-converter" width="600" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now users can filter the products by price. Next, let's add the feature for sorting so users can sort the products by ascending or descending order. In your Algolia account index configuration, locate &lt;strong&gt;Replicas&lt;/strong&gt; tab, create &lt;strong&gt;+ Create Replica index&lt;/strong&gt; for &lt;code&gt;development_strapi-store_price_asc&lt;/code&gt; and &lt;code&gt;development_strapi-store_price_desc&lt;/code&gt; then click on &lt;strong&gt;Review and Save Settings&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1ewEn-Bu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/r1jxjUiA6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1ewEn-Bu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hackmd.io/_uploads/r1jxjUiA6.png" alt="Screenshot 2024-03-22 at 20.22.04" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure Sorting for Each Replica
&lt;/h3&gt;

&lt;p&gt;For each replica index you've created, go to its &lt;strong&gt;Configuration&lt;/strong&gt;, scroll to the &lt;strong&gt;Ranking and sorting&lt;/strong&gt; section, and adjust the ranking formula to include the attribute you want to sort by. For &lt;code&gt;development_strapi-store_price_asc&lt;/code&gt; price ascends and the price descends for &lt;code&gt;development_strapi-store_price_desc&lt;/code&gt;, and &lt;strong&gt;Review and Save Settings&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then update the Search component to use the names of these replica indices in the &lt;code&gt;SortBy&lt;/code&gt; component as the &lt;strong&gt;items&lt;/strong&gt; values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SortBy&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-instantsearch-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Panel&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sort by&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SortBy&lt;/span&gt;
    &lt;span class="nx"&gt;defaultRefinement&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development_strapi-store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development_strapi-store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Featured&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development_strapi-store_price_as&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Price asc.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development_strapi-store_price_desc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Price desc.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;]}&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Panel&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NCMU5W75--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://hackmd.io/_uploads/HkkrvwjRa.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NCMU5W75--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://hackmd.io/_uploads/HkkrvwjRa.gif" alt="screen-capture4-ezgif.com-video-to-gif-converter" width="600" height="285"&gt;&lt;/a&gt;&lt;br&gt;
Now you can sort the products by price in ascending and descending order.&lt;/p&gt;

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

&lt;p&gt;That's it for this tutorial. You've learned how to add advanced search to a Strapi and Next.js project with Algolia. We began by setting up a Strapi and Next.js project, creating a collection type in the Strapi admin, building out the application UI, configuring the Algolia plugin, and syncing Strapi content with Algolia. Additionally, we enhanced the application by adding search features like faceting, filtering, and sorting. Now that you've learned how to incorporate advanced search into your Strapi and Next.js project using Algolia, how do you plan to use these technologies in your next project?&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;The code for this tutorial: &lt;a href="https://github.com/Claradev32/advanced-strapi-algolia-search"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Secure Your Node.js App with JSON Web Tokens</title>
      <dc:creator>Claradev32</dc:creator>
      <pubDate>Wed, 21 Sep 2022 13:36:29 +0000</pubDate>
      <link>https://dev.to/appsignal/secure-your-nodejs-app-with-json-web-tokens-43jl</link>
      <guid>https://dev.to/appsignal/secure-your-nodejs-app-with-json-web-tokens-43jl</guid>
      <description>&lt;p&gt;A JSON Web Token (JWT) is an open standard (RFC 7519) that securely sends and receives data between parties (in the form of a JSON object).&lt;/p&gt;

&lt;p&gt;In this article, we’ll implement JWT authentication to secure a Node.js application. We’ll also find out what JWT is all about and build a demo app.&lt;/p&gt;

&lt;p&gt;Let's get going!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a JSON Web Token (JWT)?
&lt;/h2&gt;

&lt;p&gt;As defined in open standard &lt;a href="https://www.rfc-editor.org/rfc/rfc7519.html"&gt;RFC 7519&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A JWT is encrypted and signed with a secret key (using the HMAC algorithm) or a cryptographically protected set of keys (with RSA or ECDSA).&lt;/p&gt;

&lt;p&gt;This authentication contributes to a web application's integrity by ensuring the integrity of the claims within it, known as tokens. When tokens are signed with public/private key pairs, the signature also confirms that only the person holding the private key signed it.&lt;/p&gt;

&lt;p&gt;The tokens consist of three compact parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Header&lt;/strong&gt;: The header is divided into two sections: the type of token (JWT) and the signing algorithm used (HMAC-SHA256 or RSA).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payload&lt;/strong&gt;: Assertions about an entity and supporting data, known as claims.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signature&lt;/strong&gt;: Made up of an encoded header, an encoded payload, a secret, and an algorithm.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Use a JWT in Your Node.js App
&lt;/h2&gt;

&lt;p&gt;Here are a couple of scenarios where JSON Web Tokens can be useful to your web application:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authorization&lt;/strong&gt;: The most common use of JWTs in most business applications.&lt;/p&gt;

&lt;p&gt;JWTs enable businesses to protect or restrict access to a portion of an application for a select group of users. For each logged-in user, a JWT token is sent along with other subsequent requests. This allows a user to access routes, services, and resources permitted with that token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Information Exchange:&lt;/strong&gt; JSON Web Tokens are an excellent way to securely transmit data between parties.&lt;/p&gt;

&lt;p&gt;Because JWTs can be signed (for example, with public/private key pairs), you can be confident that the senders are who they claim to be. Furthermore, because the signature is calculated using the header and payload, you can be certain that the content has not been tampered with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;p&gt;Before you get started, ensure you have met the following requirements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt; v14 or older installed&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.postman.com/downloads/"&gt;Postman&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;Prior knowledge of Node.js and Javascript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a New Project
&lt;/h2&gt;

&lt;p&gt;Now let's create a project folder and a new Node.js project by running the commands below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;jwt-auth &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;jwt-auth
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the commands we:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new folder called &lt;strong&gt;jwt-auth&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Change the directory to the folder&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;package.json&lt;/code&gt; file to document the project dependencies&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now open the &lt;code&gt;package.json&lt;/code&gt; file and add the start script to run the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node index.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the above configuration set up, run the command below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Node.js App Dependencies
&lt;/h2&gt;

&lt;p&gt;With the project created and configured, we'll now install the following dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/express"&gt;express&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/dotenv"&gt;dotenv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/jsonwebtoken"&gt;jsonwebtoken&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/bcryptjs"&gt;bcryptjs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run the command below to install the required dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;express jsonwebtoken dotenv bcryptjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Set up an Express Server
&lt;/h3&gt;

&lt;p&gt;Once the required dependencies are installed, create an &lt;code&gt;index.js&lt;/code&gt; file in the project folder, and set up an Express server with the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server is running on port 3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have successfully created an Express server listening on port 3000, with middleware to parse the request payload.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create A &lt;code&gt;.env&lt;/code&gt; File
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;.env&lt;/strong&gt; file is used in Node.js to store environment variables for security purposes. Ensure that your &lt;strong&gt;.env&lt;/strong&gt; file is included in your &lt;a href="https://git-scm.com/docs/gitignore"&gt;.gitignore&lt;/a&gt; file to avoid exposing your application's secrets to the public.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the project's root directory and add your JWT secret.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;JWT_SECRET = "YOUR SECRET GOES HERE"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then go back to the &lt;code&gt;index.js&lt;/code&gt; file and configure the application to load the environment variables into your application, using &lt;code&gt;dotenv&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build App Routes
&lt;/h3&gt;

&lt;p&gt;With the environment variables set up, let's create a route to get all registered users in the application.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;index.js&lt;/code&gt;, create a user array and route to return users with the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are integrating a database management system, you can run queries to find and return all the users instead. One thing to point out here is that this route is accessible to all users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create An Auth Route
&lt;/h3&gt;

&lt;p&gt;Now let's create other routes to register and authenticate users in the application. We'll do that in the &lt;code&gt;index.js&lt;/code&gt; file, starting with the register route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bcryptjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/register&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Username and password are required.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We import &lt;code&gt;bcryptjs&lt;/code&gt; to hash a user's password before saving it. Then we check if the user provides the required fields before adding them to the user's array.&lt;/p&gt;

&lt;p&gt;Next, create another route to log in registered users.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;//check if user exists&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foundUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;foundUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid email or password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;//check if password is correct&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPasswordValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;foundUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isPasswordValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid email or password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;//create token&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;expiresIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1h&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we import &lt;code&gt;jsonwebtoken&lt;/code&gt; to sign a token for the registered users.&lt;/p&gt;

&lt;p&gt;First, we check if the users exist in the user's array. You can also run your find query if you are integrating a database.&lt;/p&gt;

&lt;p&gt;Then we compare the password with the saved hashed version. When the user satisfies these checks, we then sign a token for the user passing the user's details, the JWT_SECRET, and expiration time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify Your User's Token with Middleware
&lt;/h3&gt;

&lt;p&gt;Now that we can register and authenticate a user in the application, let's create middleware to verify the user's token and thus protect our route.&lt;/p&gt;

&lt;p&gt;Ensure this code snippet is above the app routes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;verifyUserToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;authorization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access denied. No token provided.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid token.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We send the token along with the request payloads in the request headers. We then check if the token was sent, and verify it using the &lt;code&gt;jwt.verify&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Once a user is verified, we can save their details in the request object to keep track of their activities in the application.&lt;/p&gt;

&lt;p&gt;Let's protect the get users route. Restrict access to only authorized users by adding the &lt;code&gt;verifyUserToken&lt;/code&gt; function as a middleware to the route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;verifyUserToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, your application should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bcryptjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;verifyUserToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;authorization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access denied. No token provided.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid token.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;verifyUserToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/register&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Username and password are required.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;//check if user exists&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foundUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;foundUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid email or password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;//check if password is correct&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPasswordValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;foundUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isPasswordValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid email or password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;//create token&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;expiresIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1h&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server is running on port 3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test Your Node.js Application
&lt;/h2&gt;

&lt;p&gt;Go ahead and test the application to see if it works as it should. Launch Postman and send a &lt;strong&gt;GET&lt;/strong&gt; request to the endpoint &lt;code&gt;localhost:3000/api/users&lt;/code&gt; without authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9v6pgccD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2022-09/unauth-access.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9v6pgccD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2022-09/unauth-access.png" alt="Unauthorized access" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should get an &lt;code&gt;Unauthorized request&lt;/code&gt; message.&lt;/p&gt;

&lt;p&gt;Now, register an account by sending a POST request to the endpoint &lt;code&gt;localhost:3000/api/register&lt;/code&gt;, with the following JSON data in the request body.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"clara@gmail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1234"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BLN5vuXr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2022-09/user-data.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BLN5vuXr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2022-09/user-data.png" alt="User data" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, log in by sending a POST request to the endpoint &lt;code&gt;localhost:3000/api/login&lt;/code&gt; with the same data shown above.&lt;/p&gt;

&lt;p&gt;JWT will generate a token for you, as shown here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jDMctnRt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2022-09/gen-token.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jDMctnRt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2022-09/gen-token.png" alt="Generated token" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, copy the auth token to the request headers and send a request to the get users endpoint again. The token should appear in the form's headers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Bearer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Token&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jRsdnKRh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2022-09/users-access.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jRsdnKRh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2022-09/users-access.png" alt="Users access" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you have access to all users, until the token expires in one hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this tutorial, you secured a Node.js application using JWT. We started by introducing you to JWT and touched on when you should use it, before building a demo app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jwt.io/introduction"&gt;You can read more in the JWT documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you liked this post, &lt;a href="https://blog.appsignal.com/javascript-sorcery"&gt;subscribe to our JavaScript Sorcery list&lt;/a&gt; for a monthly deep dive into more magical JavaScript tips and tricks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.P.S. If you need an APM for your Node.js app, go and &lt;a href="https://www.appsignal.com/nodejs"&gt;check out the AppSignal APM for Node.js&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>node</category>
    </item>
    <item>
      <title>Creating a theme in a Gatsby application with Stitches</title>
      <dc:creator>Claradev32</dc:creator>
      <pubDate>Mon, 25 Jul 2022 13:52:00 +0000</pubDate>
      <link>https://dev.to/claradev32/creating-a-theme-in-a-gatsby-application-with-stitches-3pn8</link>
      <guid>https://dev.to/claradev32/creating-a-theme-in-a-gatsby-application-with-stitches-3pn8</guid>
      <description>&lt;p&gt;&lt;a href="https://www.gatsbyjs.com/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt; is a popular React framework used to build webpages and apps. Its design prioritizes security, scalability, and performance. Gatsby is supported by a large ecosystem, which includes Plugins for integrating services, themes for simple configuration, and Recipes for automating routine tasks. In this tutorial, you'll learn how to create a theme in Gatsby with Stitches.&lt;/p&gt;

&lt;p&gt;To get started with this tutorial, ensure you have the following&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.dev/download" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; version 14 or later installed&lt;/li&gt;
&lt;li&gt;yarn package manager installed.&lt;/li&gt;
&lt;li&gt;Prior Knowledge of &lt;a href="https://stitches.dev/" rel="noopener noreferrer"&gt;Stitches&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Prior Knowledge of &lt;a href="https://www.gatsbyjs.com/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is stitches?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://stitches.dev/" rel="noopener noreferrer"&gt;Stiches&lt;/a&gt; is a React framework that allows you to confidently create and style reusable components. It includes support for other frameworks such as Vue, Svelte, and Vanilla HTML.&lt;br&gt;
Stitches were created to help developers avoid unnecessary prop interpolations at runtime, thereby improving application performance. Let’s start by creating a new Gatsby application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gatsby new gatsby-site https://github.com/gatsbyjs/gatsby-starter-hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command will clone the Gatsby starter application with the folder structure below.&lt;/p&gt;

&lt;p&gt;📦gatsby-site&lt;br&gt;
┣ 📂src&lt;br&gt;
 ┃ ┗ 📂pages&lt;br&gt;
 ┃ ┃ ┗ 📜index.js&lt;br&gt;
 ┣ 📂static&lt;br&gt;
 ┃ ┗ 📜favicon.ico&lt;br&gt;
 ┣ 📜.gitignore&lt;br&gt;
 ┣ 📜.prettierignore&lt;br&gt;
 ┣ 📜.prettierrc&lt;br&gt;
 ┣ 📜LICENSE&lt;br&gt;
 ┣ 📜README.md&lt;br&gt;
 ┣ 📜gatsby-config.js&lt;br&gt;
 ┣ 📜package-lock.json&lt;br&gt;
 ┗ 📜package.json&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup and Configuring Stitches
&lt;/h2&gt;

&lt;p&gt;Now let's configure stitches with your Gatsby application. First, you need to install the Gatsby plugin for styling with Stitches with the command below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add gatsby-theme-stitches @stitches/react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the installation is completed, open the gatsby-config.js file and add Stitches to the array of plugins with the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  /* Your site config here */
  plugin: ['gatsby-theme-stitches'],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, you are ready to start styling your Gatsby application with Stitches. There are two ways around this.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can choose to create your config by shadowing the &lt;code&gt;gatsby-theme-stitches/src/config&lt;/code&gt; module&lt;/li&gt;
&lt;li&gt;You can import the properties directly into your application.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { styled } from 'gatsby-theme-stitches/src/config';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use the first method, create a &lt;code&gt;gatsby-theme-stitches/config.js&lt;/code&gt; file and add the following configurations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createStitches } from '@stitches/react';

// You should exports all properties
export const {
  styled,
  css,
  globalCss,
  keyframes,
  getCssText,
  theme,
  createTheme,
  config,
} = createStitches({
   theme: {
    colors: {
      black500: "hsl(0, 0%, 0%)",
      white500: "hsl(0, 0%, 100%)",
      gray500: "hsl(206,10%,76%)",
      blue500: "hsl(206,100%,50%)",
      purple500: "hsl(252,78%,60%)",
      green500: "hsl(148,60%,60%)",
      red500: "hsl(352,100%,62%)",
    },
    space: {
      1: "5px",
      2: "10px",
      3: "15px",
    },
    fontSizes: {
      1: "12px",
      2: "13px",
      3: "15px",
    },
    fonts: {
      untitled: "Untitled Sans, apple-system, sans-serif",
      mono: "Söhne Mono, menlo, monospace",
    },
    borderRadius: {
      1: "5px",
      2: "10px",
      3: "15px",
    },
    borders: {
      1: "1px solid #ccc",
      2: "2px solid #ccc",
      3: "3px solid #ccc",
      4: "none",
    },
    paddings: {
      1: "5px",
      2: "10px",
      3: "15px",
    },
    margins: {
      1: "5px",
      2: "10px",
      3: "15px",
    },
    widths: {
      1: "100%",
      2: "50%",
      3: "25%",
    },
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet, you have exported all the available Stitches properties. So You can import and use them. Then we defined the themes for the elements in our application. We'll can use the theme properties to style our elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create and style custom elements.
&lt;/h2&gt;

&lt;p&gt;Now let's go ahead and use Stitches to create the style for the elements we'll use in our Gatsby application. For separation of concern sake, we'll create &lt;strong&gt;components&lt;/strong&gt; folder in the root directory of the project for all the element's styles. In the component folder, create a new file named &lt;code&gt;Button.js&lt;/code&gt; and add the code snippets below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { styled } from '../../stitches.config';

export const Button = styled("button", {
   // base styles
  display: "block",
  border: "$4",
  borderRadius: "$1",
  color: "$white500",

  variants: {
    size: {
      sm: {
        fontSize: "13px",
        height: "25px",
        paddingRight: "10px",
        paddingLeft: "10px",
      },
      lg: {
        fontSize: "15px",
        height: "35px",
        paddingLeft: "15px",
        paddingRight: "15px",
      },
    },
    bg: {
      primary: {
        backgroundColor: "#2196f3",
        "&amp;amp;:hover": {
          backgroundColor: "#64b5f6",
        },
      },
      secondary: {
        backgroundColor: "#009688",
        "&amp;amp;:hover": {
          backgroundColor: "#4db6ac",
        },
      },
      danger: {
        backgroundColor: "#f44336",
        "&amp;amp;:hover": {
          backgroundColor: "#ef9a9a",
        },
      },
      success: {
        backgroundColor: "#4caf50",
        color: "white",
        "&amp;amp;:hover": {
          backgroundColor: "#a5d6a7",
        },
      },
    },
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet, we imported the styled properties from Stitches config file, which will allow us to customize the component. We used the properties we defined in our theme to add the base style of the element using the &lt;strong&gt;$&lt;/strong&gt; symbol followed by the theme properties. Then we used the variants property to define the styling for the background color (bg) and size (size) of the component.&lt;br&gt;
Next, create a &lt;code&gt;Container.js&lt;/code&gt; and add the code snippets below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { styled } from "@stitches/react";

export const Container = styled("div", {
   // base styles
  display: "flex",
  flexDirection: "column",
  justifyContent: "center",
  padding: "$2",
  backgroundColor: "$white500",

  variants: {
    fd: {
      column: {
        flexDirection: "column",
      },
      row: {
        flexDirection: "row",
      },
    },
    size: {
      sm: {
        width: "100%",
        height: "50px",
      },
      lg: {
        width: "100%",
        height: "60px",
      },
    },
    align: {
      center: {
        alignItems: "center",
      },
      left: {
        alignItems: "flex-start",
      },
      right: {
        alignItems: "flex-end",
      },
    },
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Container component, we base style themes and defined the styling to align and set the size of the container using the varriant property.&lt;br&gt;
Next, create an &lt;code&gt;Image.js&lt;/code&gt; file and add the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { styled } from "@stitches/react"

export const Image = styled("img", {
  display: "block",
  width: "$1",
  height: "auto",
  maxWidth: "100%",
  maxHeight: "100%",
  margin: "0 auto",
  variants: {
    size: {
      sm: {
        width: "50%",
        height: "50%",
        maxWidth: "100%",
        maxHeight: "100%",
        margin: "0 auto",
      },
      lg: {
        width: "100%",
        height: "auto",
        maxWidth: "100%",
        maxHeight: "100%",
        margin: "0 auto",
      },
    },
  },
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also defined the styling to have a large and small image, we also defined the style to change the image alignment and we applied the themes to the base styles.&lt;/p&gt;

&lt;p&gt;Next, create a &lt;code&gt;Header.js&lt;/code&gt; file and add the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { styled } from "@stitches/react";

export const Header = styled("nav", {
  // base styles
  display: "flex",
  flexDirection: "row",
  justifyContent: "space-between",
  alignItems: "center",
  padding: "$2",
  backgroundColor: "$white500",
  borderBottom: "1px solid #e6e6e6",

  variants: {
    size: {
      sm: {
        width: "100%",
        height: "50px",
      },
      lg: {
        width: "100%",
        height: "60px",
      },
    },
    bg: {
      primary: {
        backgroundColor: "#2196f3",
        "&amp;amp;:hover": {
          backgroundColor: "#64b5f6",
        },
      },
      secondary: {
        backgroundColor: "#009688",
        "&amp;amp;:hover": {
          backgroundColor: "#4db6ac",
        },
      },
      danger: {
        backgroundColor: "#f44336",
        "&amp;amp;:hover": {
          backgroundColor: "#ef9a9a",
        },
      },
      success: {
        backgroundColor: "#4caf50",
        "&amp;amp;:hover": {
          backgroundColor: "#a5d6a7",
        },
      },
    },
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a &lt;code&gt;Card.js&lt;/code&gt; file and add the code snippets below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { styled } from "@stitches/react";

export const Card = styled("div", {
  display: "flex",
  justifyContent: "center",
  flexDirection: "column",
  padding: "$1",
  margin: "$2"

  variants: {
    align: {
      center: {
        alignItems: "center",
      },
      left: {
        alignItems: "flex-start",
      },
      right: {
        alignItems: "flex-end",
      },
    },
    boder: {
        none: { 
            border: "none"
        },
        solid: {
            border: "solid 1px #e6e6e6"
        }
    }
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, a new file &lt;code&gt;Input.js&lt;/code&gt; and add the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { styled } from "@stitches/react";

export const Input = styled("input", {
  display: "block",
  marginBottom: "10px",

  variants: {
    size: {
      sm: {
        fontSize: "13px",
        height: "25px",
        paddingRight: "10px",
        paddingLeft: "10px",
      },
      lg: {
        fontSize: "15px",
        height: "35px",
        paddingLeft: "15px",
        paddingRight: "15px",
      },
    },
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet, we have an Input element to handle users' input. In the above Input component, we want to have large and small inputs, and we defined the styles for that using the variants property.&lt;/p&gt;

&lt;p&gt;Next, a new file &lt;code&gt;Text.js&lt;/code&gt; and add the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { styled } from "@stitches/react";

export const Text = styled('p', {
    fontFamily: '$mono',
    color: '$black5000',

    variants: {
      size: {
        1: {
          fontSize: '10px',
        },
        2: {
          fontSize: '12px',
        },
        3: {
          fontSize: '14px',
        },
      },
    },
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet, we created a component to allow us to add and style a paragraph.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source Session Replay
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;OpenReplay is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.openreplay.com%2Fstatic%2F0a3dcbea2c3ddf66242e78ffd2a65233%2F412e4%2Fbanner-blog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.openreplay.com%2Fstatic%2F0a3dcbea2c3ddf66242e78ffd2a65233%2F412e4%2Fbanner-blog.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Start enjoying your debugging experience - &lt;a href="https://github.com/openreplay/openreplay" rel="noopener noreferrer"&gt;start using OpenReplay for free&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Blog App
&lt;/h2&gt;

&lt;p&gt;Now that we've styled the elements we need for this application, let's go ahead and create a blog application. First, we need to update the &lt;code&gt;pages/index.js&lt;/code&gt; file to import all components we just created with the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Button } from "../components/Button"
import { Input } from "../components/Input"
import { Card } from "../components/Card"
import { Text } from "../components/Text"
import { Header } from "../components/Header"
import { Image } from "../components/Image"
import { Container } from "../components/Container"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we'll use the component to update the &lt;strong&gt;Home&lt;/strong&gt; component with the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function Home() {
  const [modal, setModal] = useState(false)

  const showModal = () =&amp;gt; {
    setModel(!model)
  }
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Container&amp;gt;
        &amp;lt;Header bg="primary"&amp;gt;
          &amp;lt;Text size="1"&amp;gt;My Blog App&amp;lt;/Text&amp;gt;
          &amp;lt;Button bg="secondary" size="sm" onClick={showModal}&amp;gt;
            New Blog
          &amp;lt;/Button&amp;gt;
        &amp;lt;/Header&amp;gt;
        {model &amp;amp;&amp;amp; (
          &amp;lt;Card boder="solid"&amp;gt;
            &amp;lt;Text size="1"&amp;gt;Titile:&amp;lt;/Text&amp;gt;
            &amp;lt;Input /&amp;gt;
            &amp;lt;Text size="1"&amp;gt;Content&amp;lt;/Text&amp;gt;
            &amp;lt;Input /&amp;gt;
            &amp;lt;Text size="1"&amp;gt;Cover Image&amp;lt;/Text&amp;gt;
            &amp;lt;Input /&amp;gt;
            &amp;lt;Button bg="primary" size="sm"&amp;gt;
              Post
            &amp;lt;/Button&amp;gt;
          &amp;lt;/Card&amp;gt;
        )}
        &amp;lt;Text&amp;gt;Blog Posts&amp;lt;/Text&amp;gt;
      &amp;lt;/Container&amp;gt;
      &amp;lt;Container fd="row"&amp;gt;
        {blogs.map(blog =&amp;gt; (
          &amp;lt;Card boder="solid"&amp;gt;
            &amp;lt;Image src={blog.cover} size="lg" /&amp;gt;
            &amp;lt;Text size="3"&amp;gt;{blog.title}&amp;lt;/Text&amp;gt;
            &amp;lt;Text size="1"&amp;gt;{blog.content}&amp;lt;/Text&amp;gt;
            &amp;lt;Text size="1"&amp;gt;{blog.date}&amp;lt;/Text&amp;gt;
          &amp;lt;/Card&amp;gt;
        ))}
      &amp;lt;/Container&amp;gt;
    &amp;lt;/&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet, we updated the &lt;strong&gt;Home&lt;/strong&gt; component using the components we styled using Stitches. We applied the different styles we want to each of the components used in our Home component. We have a form input field that will be toggled to hide or show it using the &lt;strong&gt;Modal&lt;/strong&gt; state variable.&lt;/p&gt;

&lt;p&gt;Then we looped through the blog details we'll be creating shortly using the map function and render them to the user.&lt;/p&gt;

&lt;p&gt;Finally, add the following blog array objects to the &lt;strong&gt;Home&lt;/strong&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
  const blogs = [
    {
      title: "How to build a website",
      content:
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel",
      cover:
        "https://www.hostgator.com/blog/wp-content/uploads/2017/09/MakeOwnWebsite.png",
      date: "2020-01-01",
    },
    {
      title: "Getting started with OpenReplay",
      content:
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel",
      cover:
        "https://opengraph.githubassets.com/2ddbe84dccfbcc774b1c9861dd327d2efd7e1cd49964dc01229c181bea751e60/openreplay/documentation",
      date: "2020-01-01",
    },
    {
      title: "Node.js Vs React",
      content:
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel consectetur euismod, nisi nisl aliquet nisi, eget consectetur nisl nisi eget nisi. Nullam euismod, nisi vel",
      cover:
        "https://miro.medium.com/max/1400/1*CpDidbInbG4Er_0j_hknFQ.jpeg",
      date: "2020-01-01",
    },
  ]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test the application
&lt;/h2&gt;

&lt;p&gt;With the blog demo application created, let's go ahead and test it out. Run the commands to change the directory to the project folder and start the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  cd gatsby-site
  gatsby develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then navigate &lt;a href="http://localhost:8000/" rel="noopener noreferrer"&gt;http://localhost:8000/&lt;/a&gt; and you should see the output below on the index page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fny0rS2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fny0rS2b.png"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;You’ve learned how to create a theme UI in a Gatsby application with Stitches by building a blog demo application. First, we started with an introduction to Gatsby and Stitches. You learned how to configure Stitches with Gatsby and styled some components.&lt;br&gt;
Now that you've known how to integrate Gatsby and Stitches, how would you style your next Gatsby application?&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>Building a Node.js API with Hapi.js and MongoDB</title>
      <dc:creator>Claradev32</dc:creator>
      <pubDate>Thu, 26 Aug 2021 15:33:33 +0000</pubDate>
      <link>https://dev.to/claradev32/building-a-node-js-api-with-hapi-js-and-mongodb-454c</link>
      <guid>https://dev.to/claradev32/building-a-node-js-api-with-hapi-js-and-mongodb-454c</guid>
      <description>&lt;p&gt;As our web applications scale, there is a need to reduce the development time by the use of a more reliable, and salable, tool, which gets the job done much faster.&lt;br&gt;
In this tutorial, we will build a Book Store API with Hapi.js and MongoDB. We will set up MongoDB, Hapi.js and build a RESTful API.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This tutorial will be a hands-on demonstration, you can find the source code on &lt;a href="https://github.com/Claradev32/BookStore.git" rel="noopener noreferrer"&gt;Gitbub&lt;/a&gt;. If you'd like to follow along, be sure you have the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.mongodb.com/cloud/atlas" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt; Database - This tutorial uses MongoDB.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nodejs.dev/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; - This tutorial uses Nodjs and NPM &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.postman.com/downloads/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; - This tutorial uses Postman to test the API&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What is Hap.js
&lt;/h2&gt;

&lt;p&gt;Hapi.js is a Nodejs framework used to build powerful, scalable applications, with minimal overhead and full out-of-the-box functionality. Hapi.js was originally developed to handle Walmart’s Black Friday scale, hapi continues to be the proven choice for enterprise-grade backend needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;To get started to create a folder for your project and access it from your terminal. Open the folder in Visual Studio Code or any other IDE you prefer.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir BookApp //create a folder for the project
cd \BookApp // change directory to the app folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then initialize NPM, which will create a package.json file in our app root directory where we store our dependencies.&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;Next, we need to install some packages for our project.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @hapi/Hapi mongoose dotenv morgan --save 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, let's take a look at our project structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_0FEADB409A157CAA8DD14F2CA9AC086842E68BDBD81AF897CA3A753F47922E22_1629990892959_image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_0FEADB409A157CAA8DD14F2CA9AC086842E68BDBD81AF897CA3A753F47922E22_1629990892959_image.png" alt="Project Structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controllers - is where we handle the application logic&lt;/li&gt;
&lt;li&gt;Model - is where we handle our database collection
## Setting Up Hapi.js Server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will start by creating a &lt;strong&gt;server.js&lt;/strong&gt; and *&lt;strong&gt;*file. Which is our application entry point.&lt;br&gt;
In your project root directory create and **server.js&lt;/strong&gt; file, then import the Hapi package we installed in the previous section, create an instance of the Hapi server, specify the &lt;strong&gt;port&lt;/strong&gt; you want the server to listen to, and &lt;strong&gt;host&lt;/strong&gt; address*&lt;em&gt;.&lt;/em&gt;* &lt;br&gt;
Next, we will create the root route, of our application with a GET request and create a &lt;strong&gt;handler.&lt;/strong&gt; For now, we will be sending a simple text to the client. &lt;br&gt;
Finally, we start the Hapi.js server with the &lt;strong&gt;start&lt;/strong&gt; method and display a message to the console.&lt;/p&gt;

&lt;p&gt;Add this code to your &lt;strong&gt;server.js&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Hapi = require('@hapi/hapi');

const server = Hapi.server({
  port: 4000,
  host: '127.0.0.1'
});

server.route({
  method: 'GET',
  path: '/',
  handler: (req, h) =&amp;gt; {

    return 'Hello I am Hapi!&amp;lt;';
  }
});

server.start();
console.log(`Server running on port ${server.info.uri}`);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It's to start our server. run this command on your command line to start the server.&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;Next, open your web browser, navigate to &lt;strong&gt;localhost:4000.&lt;/strong&gt; The server will respond with &lt;strong&gt;Hello I am Hapi!.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a MongoDB Database
&lt;/h2&gt;

&lt;p&gt;Now that you have learned how to create a Hapi server, let's go ahead and set up MongoDB for our project.&lt;br&gt;
We will be using &lt;a href="https://mongoosejs.com/" rel="noopener noreferrer"&gt;Mongoose&lt;/a&gt; to communicate with the MongoDB database.&lt;br&gt;
Run this command to install Mongoose:&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;Next, let’s connect MongoDB to our application using Mongoose. We will require mongoose, create a connection using the mongoose connect method and pass in our local server address to the server.&lt;br&gt;
If the database is up, you should see “DB started” on the console.&lt;br&gt;
Add this code to your server.js:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require("mongoose");
mongoose
 .connect("mongodb://localhost:27017/BookStore")
 .then(() =&amp;gt; {
  console.log("db started!");
 })
 .catch((e) =&amp;gt; {
  console.log(e);
 });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating Book Schema
&lt;/h2&gt;

&lt;p&gt;We now have our database up and running, let’s go ahead and create a book &lt;a href="https://mongoosejs.com/docs/guide.html" rel="noopener noreferrer"&gt;schema&lt;/a&gt;. Each book in our store will have a &lt;strong&gt;name&lt;/strong&gt;, &lt;strong&gt;author,&lt;/strong&gt; &lt;strong&gt;price&lt;/strong&gt;, &lt;strong&gt;supplier&lt;/strong&gt;, and &lt;strong&gt;createdAt.&lt;/strong&gt; &lt;br&gt;
Next, we define the type of data the documents should accept, then we validate the data from the users, to make sure they don’t submit empty records.&lt;br&gt;
Add this code to &lt;strong&gt;model/BookModel:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require("mongoose");
const BookSchema = new mongoose.Schema({
 name: {
  type: String,
  required: [true, "Book price is required"],
 },
 author: {
  type: String,
  required: [true, "Authors name is required"],
 },
 price: { type: Number, required: [true, "Book price is required"] },
 ISBN: {
  type: String,
  required: [true, "Book ISBN is required"],
 },
 supplier :{
  type: String,
  required: [true, "Suppliers name is required"],
 },
 createdAt: {
  type: Date,
  default: Date.now(),
 },
});
module.exports = mongoose.model("Books", BookSchema);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating Books
&lt;/h2&gt;

&lt;p&gt;Now that we have defined our database schema. let’s go ahead and add a handler to add books to the store.&lt;br&gt;
First, we require the Books model, then create and export our handler function.&lt;/p&gt;

&lt;p&gt;Next, we create an object from the book model and add a record of the collection using the &lt;strong&gt;create&lt;/strong&gt; method. The data from the form is stored in the &lt;strong&gt;payload&lt;/strong&gt; as &lt;a href="https://www.w3schools.com/whatis/whatis_json.asp#:~:text=JSON%20stands%20for%20JavaScript%20Object,server%20to%20a%20web%20page" rel="noopener noreferrer"&gt;JSON&lt;/a&gt;, so we need to convert it to an object using the JSON parse method.&lt;br&gt;
Lastly, we return the created document as a response to the users.&lt;/p&gt;

&lt;p&gt;Add this code to &lt;strong&gt;controller/BookControllers.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.createBook = async (req, h) =&amp;gt; {
 const data = await Books.create(JSON.parse(req.payload));
 return status;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now lets go ahead and create a route for this handler function.&lt;br&gt;
add this code to your server.js&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server.route({
 method: "GET",
 path: "/api/store",
 handler: controllers.getAllBooks,
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Getting All Books
&lt;/h2&gt;

&lt;p&gt;Now that we can now add books to our database, let’s get the books stored in the database.&lt;br&gt;
First, we get the books from the form, which is stored as &lt;a href="https://www.w3schools.com/whatis/whatis_json.asp#:~:text=JSON%20stands%20for%20JavaScript%20Object,server%20to%20a%20web%20page" rel="noopener noreferrer"&gt;JSON&lt;/a&gt; in the payload. Then we need to convert the data to an object since we store data as objects to our collection.&lt;/p&gt;

&lt;p&gt;Add this code to &lt;strong&gt;controller/BookController:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.getAllBooks = async (req, h) =&amp;gt; {
 const books = await Books.find();
 return books;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now let's go ahead and create a route for this handler function.&lt;br&gt;
Add this code to &lt;strong&gt;server.js.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server.route({
 method: "POST",
 path: "/api/store",
 handler: controllers.createBook,
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Getting a Book
&lt;/h2&gt;

&lt;p&gt;Let's go now get a book by its id. &lt;br&gt;
First, we need the &lt;strong&gt;id&lt;/strong&gt; of the Book selected, then we use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment" rel="noopener noreferrer"&gt;object destructing&lt;/a&gt; to the id from the &lt;strong&gt;params&lt;/strong&gt; object.&lt;br&gt;
Next, we query the book collection to get a book by its id, using the &lt;strong&gt;findById&lt;/strong&gt; method. Then now return the book to the client.&lt;/p&gt;

&lt;p&gt;Add this code to &lt;strong&gt;controller/BookController:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.getBook = async(req, h) =&amp;gt; {
 const {id} = req.params
 const book = await Books.findById({_id:id});
 return book;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, let’s go ahead and create the &lt;strong&gt;getBook&lt;/strong&gt; route with a patch request with an id parameter.&lt;/p&gt;

&lt;p&gt;Add this code to &lt;strong&gt;server.js:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server.route({
 method: "GET",
 path: "/api/store/{id}",
 handler: controllers.getBook,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Updating a Book
&lt;/h2&gt;

&lt;p&gt;Now, let create a handler function to update the book in our collection.&lt;br&gt;
First, we need to get the book id from the params object, also get the update data from the request payload. &lt;br&gt;
Next, we create an object from the books model and use the findByIdAndUpdate method to update the book whose id is specified in the request parameters. Then convert the payload to an object and pass it as the new value of the document.&lt;/p&gt;

&lt;p&gt;Next, we return the updated document with the &lt;strong&gt;new&lt;/strong&gt; option set to true and send the document to the client.&lt;/p&gt;

&lt;p&gt;Add this code to &lt;strong&gt;controller/BookController:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.updateBook = async (req, h) =&amp;gt; {
 const { id } = req.params;
 const data = JSON.parse(req.payload);
 const modifiedBook = await Books.findByIdAndUpdate({ _id: id }, data, {
  new:true,
 });
 return modified book;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, let’s go ahead and create the update route with a patch request and an id parameter.&lt;br&gt;
Add this code to &lt;strong&gt;server.js:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server.route({
 method: "PATCH",
 path: "/api/store/{id}",
 handler: controllers.updateBook,
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Deleting a Book
&lt;/h2&gt;

&lt;p&gt;Let's go ahead and create our delete handler. &lt;br&gt;
First, we need to get the book id from the params object, then delete the book from the collection from the id.&lt;br&gt;
Next, we return null to the client, since the record no longer exists.&lt;/p&gt;

&lt;p&gt;Add this code to &lt;strong&gt;controller/BookController.js:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.deleteBook = async (req, h) =&amp;gt; {
 const { id } = req.params;
 await Books.findByIdAndDelete({ _id: id });
 return "null";
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, let’s go ahead and create the delete route, which will listen to a delete request, then we pass an id as a parameter.&lt;/p&gt;

&lt;p&gt;Add this code to &lt;strong&gt;server.js:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server.route({&lt;br&gt;
 method: "DELETE",&lt;br&gt;
 path: "/api/store/{id}",&lt;br&gt;
 handler: controllers.deleteBook,&lt;br&gt;
})&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Testing our API&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we have implemented our RESTful API, let us go ahead and test them.&lt;br&gt;
Open Postman, test the with these endpoints.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://localhost:3000/api/store/" rel="noopener noreferrer"&gt;http://localhost:3000/api/store/&lt;/a&gt; - GET request&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://localhost:3000/api/store" rel="noopener noreferrer"&gt;http://localhost:3000/api/store&lt;/a&gt; - POST request with this request body&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;{&lt;br&gt;
      "name": "Advanced Javacript",&lt;br&gt;
      "price": 2000,&lt;br&gt;
      "ISBN" : "AD90976",&lt;br&gt;
      "supplier": "mark James",&lt;br&gt;
      "author": "james"&lt;br&gt;
  }&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://localhost:3000/api/store/" rel="noopener noreferrer"&gt;http://localhost:3000/api/store/&lt;/a&gt;{id} - GET request&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://localhost:3000/api/store/" rel="noopener noreferrer"&gt;http://localhost:3000/api/store/&lt;/a&gt;{id} - PATCH request&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://localhost:3000/api/store/" rel="noopener noreferrer"&gt;http://localhost:3000/api/store/&lt;/a&gt;{id} - DELETE request&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Throughout this tutorial, you've learned how to create a RESTful API using Hapi.js. You've also experienced setting up MongoDB and testing API using Postman.&lt;br&gt;
Now, how would you use Hapi in your next project to create APIs?&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
