<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Kelvin Mwinuka]]></title><description><![CDATA[I'm a professional software engineer with a deep interest in web and cloud technologies.]]></description><link>https://kelvinmwinuka.com</link><generator>RSS for Node</generator><lastBuildDate>Sat, 11 Apr 2026 05:42:20 GMT</lastBuildDate><atom:link href="https://kelvinmwinuka.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[EchoVault: Embeddable Redis Alternative in Go]]></title><description><![CDATA[I started working on an open-source project about a year ago to build an embeddable alternative to Redis in Go. That’s when I started building the EchoVault project. Since then, the project has gained some interest and even a few contributors.
This a...]]></description><link>https://kelvinmwinuka.com/echovault-embeddable-redis-alternative-in-go</link><guid isPermaLink="true">https://kelvinmwinuka.com/echovault-embeddable-redis-alternative-in-go</guid><category><![CDATA[Go]]></category><category><![CDATA[Redis]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[ShowHashnode]]></category><category><![CDATA[programming]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Tue, 23 Jul 2024 15:39:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721748834602/66f77ce5-1382-4b31-8663-82afb3b8d7ed.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I started working on an open-source project about a year ago to build an embeddable alternative to Redis in Go. That’s when I started building the EchoVault project. Since then, the project has gained some interest and even a few contributors.</p>
<p>This article introduces <a target="_blank" href="https://github.com/EchoVault/EchoVault">EchoVault</a>, its features, use cases, and the motivations behind its development.</p>
<h2 id="heading-what-is-echovault">What is EchoVault?</h2>
<p>EchoVault is an embeddable in-memory datastore tailored for Go applications. It provides a RESP-compatible interface over TCP while offering the flexibility to be embedded directly into applications.</p>
<p>By doing so, EchoVault aims to replace traditional in-memory data stores like Redis in some use cases, offering similar functionalities with enhanced integration for Go.</p>
<h2 id="heading-why-echovault-was-built">Why EchoVault was Built</h2>
<p>My initial motivations for building EchoVault were:</p>
<ul>
<li><p>Embedded Flexibility: Traditional in-memory data stores like Redis are external services that require separate management and deployment. EchoVault eliminates this overhead by allowing developers to embed the data store directly into their applications, streamlining the deployment process.</p>
</li>
<li><p>Go Ecosystem Integration: EchoVault is designed primarily for Go, ensuring seamless integration and optimal performance within Go applications. However, it also maintains RESP compatibility over TCP, making it compatible with existing Redis clients such as redis-cli and Jedis.</p>
</li>
<li><p>Redis License Changes: EchoVault is open-source (licensed under Apache 2.0). We’re committed to staying on this fully open-source model and not open-core.</p>
</li>
</ul>
<h2 id="heading-features-provided-by-echovault">Features Provided by EchoVault</h2>
<p>EchoVault is packed with features that make it a robust choice for in-memory data storage:</p>
<ul>
<li><p>TLS and mTLS Support: Secure communication with support for multiple server and client Root Certificate Authorities (RootCAs). Replication Cluster Support: Utilizes the RAFT algorithm for replication and clustering.</p>
</li>
<li><p>Access Control Layer: Provides user authentication and authorization to secure data access.</p>
</li>
<li><p>Distributed Pub/Sub Functionality: Supports publish/subscribe to channels and patterns for real-time data processing.</p>
</li>
<li><p>Data Structures: We support a variety of data structures, including sets, sorted sets, hashes, lists, and more. We are continuing to add more data structures and commands within them.</p>
</li>
<li><p>Persistence Layer: This layer ensures data durability with snapshot and append-only file persistence. The AOF files are RESP compatible but not yet fully Redis compatible.</p>
</li>
<li><p>Key Eviction Policies: Implements various strategies for key eviction to manage memory usage. EchoVault has passive and active key eviction. With passive key eviction, expired keys are not evicted until the next time they are accessed. With active eviction, EchoVault will proactively delete keys that are expired.</p>
</li>
<li><p>Command Extensions: Allows runtime extension of commands via shared object files and an embedded API.</p>
</li>
</ul>
<p>The feature list continues to expand as we’re in the early stages of development. We have some more cool features lined up for the future, including:</p>
<ul>
<li><p>Streams.</p>
</li>
<li><p>Extensions with Lua modules.</p>
</li>
<li><p>Sharding.</p>
</li>
</ul>
<h2 id="heading-architecture-of-echovault">Architecture of EchoVault</h2>
<p>EchoVault supports both standalone and clustered deployments.</p>
<h3 id="heading-standalone-mode">Standalone Mode</h3>
<p>In standalone mode, EchoVault operates a single (standalone) instance. This is the easiest way to run EchoVault. You can run a standalone instance from the embedded library or start it as its own process that accepts TCP connections. The embedded instance can also accept TCP connections, allowing you to communicate with your Go process from a TCP client.</p>
<h3 id="heading-raft-replication-cluster-mode">RAFT Replication Cluster Mode</h3>
<p>For applications requiring strong consistency and fault tolerance, EchoVault supports a RAFT-based replication cluster mode.</p>
<p>RAFT is a consensus algorithm that ensures data consistency across distributed systems. In this mode, multiple EchoVault instances can form a cluster, providing data replication and ensuring that data remains consistent even in the event of node failures.</p>
<h4 id="heading-key-features-of-raft-cluster-mode">Key Features of RAFT Cluster Mode:</h4>
<ul>
<li><p>Fault Tolerance: Ensures data availability even if some nodes in the cluster fail.</p>
</li>
<li><p>Consistency: Guarantees that all nodes in the cluster have the same data.</p>
</li>
<li><p>Scalability: Allows for horizontal scaling by adding more nodes to the cluster.</p>
</li>
</ul>
<p>You can run EchoVault clusters even in embedded modes. This means that your application instances can communicate with each other through the EchoVault layer without having to deploy a third service. This is ideal for use cases such as session management across a cluster of an application’s instances.</p>
<h2 id="heading-use-cases-for-echovault">Use Cases for EchoVault</h2>
<p>EchoVault's versatility makes it suitable for a wide range of applications. Here are some potential use cases:</p>
<ul>
<li><p>In-Memory Caching Scenario: An e-commerce website needs to cache product details and user session information to improve performance. Solution: Use EchoVault to cache frequently accessed data to speed up response times. Benefits: Faster page loads, improved user experience, and reduced database strain.</p>
</li>
<li><p>Service Discovery Scenario: A microservices architecture requires dynamic service discovery for inter-service communication. Solution: Store service endpoints in EchoVault, allowing services to discover and communicate with each other efficiently. Benefits: Simplified service discovery and enhanced communication efficiency.</p>
</li>
<li><p>Session Management Scenario: A distributed web application must manage user sessions across multiple instances. Solution: Use EchoVault embedded cluster to store session data, ensuring consistency and accessibility across all application instances. Benefits: Consistent session management across the application’s cluster without deploying a secondary service like Redis.</p>
</li>
<li><p>Real-Time Analytics Scenario: A financial trading platform requires real-time analytics and monitoring of trade data. Solution: Store and process real-time trade data in EchoVault, leveraging its sorted sets and pub/sub capabilities for tracking and analysis. Benefits: Real-time data processing and faster analytics.</p>
</li>
<li><p>Distributed Task Queue Scenario: A backend system needs to manage and distribute tasks to multiple worker nodes. Solution: Implement a task queue using EchoVault's list data structure, where tasks are pushed onto the list and worker nodes pop tasks for processing. Benefits: Efficient task distribution and scalability.</p>
</li>
<li><p>Feature Flags and Configuration Management Scenario: A SaaS application needs to dynamically enable or disable features and manage configuration settings without redeploying the application. Solution: Store feature flags and configuration settings in EchoVault. Benefits: Dynamic configuration management and reduced downtime.</p>
</li>
<li><p>Rate Limiting and Throttling Scenario: An API gateway needs to enforce rate limits and throttle requests to prevent abuse and ensure fair usage. Solution: Implement rate limiting using EchoVault's in-memory capabilities to track request counts and enforce limits in real-time. Benefits: Effective rate limiting and improved API reliability.</p>
</li>
<li><p>Leader Election Scenario: A cluster of distributed services needs to elect a leader to coordinate tasks. Solution: Rely on EchoVault's embedded distributed cluster’s leader election to ensure that only one application instance is designated as the leader. Benefits: Reliable leader election and improved coordination without implementing it yourself at the application level.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>EchoVault is an ambitious project. In these early stages, we expect many kinks to have to be ironed out and many features to be added. However, we welcome this challenge and would love to get the Go community involved in the project.</p>
<p>If this article has triggered your curiosity, or you’re interested in contributing to a project like this, <a target="_blank" href="https://github.com/EchoVault/EchoVault">check out our GitHub</a> and drop us a star! We’re always open to more feedback and contributions!</p>
]]></content:encoded></item><item><title><![CDATA[Social Login With Cognito and NextAuth]]></title><description><![CDATA[AWS Cognito user pools allow you to manage your app's within the AWS ecosystem. It provides all the basic features you'd expect from an auth system.
When I'm building an application on AWS infrastructure, I prefer using Cognito user pools due to its ...]]></description><link>https://kelvinmwinuka.com/social-login-with-cognito-and-nextauth</link><guid isPermaLink="true">https://kelvinmwinuka.com/social-login-with-cognito-and-nextauth</guid><category><![CDATA[Cognito]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[nextauth.js]]></category><category><![CDATA[authentication]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Fri, 24 Feb 2023 20:13:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1677268395020/eeda95e2-4dd7-4cd4-a5d1-5b5cf48aa9b0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>AWS Cognito user pools allow you to manage your app's within the AWS ecosystem. It provides all the basic features you'd expect from an auth system.</p>
<p>When I'm building an application on AWS infrastructure, I prefer using Cognito user pools due to its seamless integration with other AWS services such as API Gateway authorization.</p>
<p>Cognito user pools also allow you to set up social login for your users. This is very convenient in a world where most people have become accustomed to authentication via existing accounts such as Google, Facebook, Apple, etc.</p>
<p>In this article, I will be covering how to integrate social login in your Next.js applications through Cognito. We will essentially allow our users to log in using their social accounts while using Cognito as a proxy auth server.</p>
<p>We will do this while bypassing the Cognito-hosted UI for a seamless auth experience for the user.</p>
<p>There are a few benefits to using this approach instead of manually handling social logins ourselves:</p>
<ol>
<li><p>We can leverage Cognito user pools and all its rich features.</p>
</li>
<li><p>In our Next.js application, we only have to deal with 1 auth provider, Cognito.</p>
</li>
<li><p>We have the freedom to design our social sign-in buttons as we please, without being shackled by <a target="_blank" href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-integration.html">Cognito's hosted UI</a>.</p>
</li>
<li><p>We do not have to manage a database of users ourselves.</p>
</li>
</ol>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>This article will not go over the process of setting up your Cognito user pool. Before you implement the steps in this article, make sure you have:</p>
<ol>
<li><p>A Cognito user pool.</p>
</li>
<li><p>An app client set up for your user pool.</p>
</li>
<li><p>Social login setup for your app client. You don't need to set up all the social providers, just one of them is enough. You can always plug more providers in later.</p>
</li>
<li><p>A domain for your user pool. It does not need to be a custom domain. The default domain provided by aws is sufficient.</p>
</li>
</ol>
<p>Our auth structure should roughly look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676536429753/158849cb-ee26-4766-8523-7ccbd3f6445d.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-setting-up-nextauth">Setting up NextAuth</h3>
<p>In the Next.js application, first, install the <a target="_blank" href="https://next-auth.js.org/">NextAuth</a> library.</p>
<pre><code class="lang-plaintext">npm install next-auth
</code></pre>
<p>Next, set up the NextAuth configurations in <code>/api/auth/[...nextauth].ts</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { TokenSet } <span class="hljs-keyword">from</span> <span class="hljs-string">"next-auth"</span>;
<span class="hljs-keyword">import</span> NextAuth <span class="hljs-keyword">from</span> <span class="hljs-string">"next-auth/next"</span>;
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">"next-auth/providers"</span>;

<span class="hljs-keyword">const</span> { 
  NEXTAUTH_URL,
  COGNITO_REGION,
  COGNITO_DOMAIN,
  COGNITO_CLIENT_ID,
  COGNITO_USER_POOL_ID,
  COGNITO_CLIENT_SECRET,
} = process.env;

<span class="hljs-keyword">type</span> TProvider = <span class="hljs-string">"Amazon"</span> | <span class="hljs-string">"Apple"</span> | <span class="hljs-string">"Facebook"</span> | <span class="hljs-string">"Google"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProvider</span>(<span class="hljs-params">provider: TProvider</span>): <span class="hljs-title">Provider</span> </span>{
   <span class="hljs-comment">/*
      Provider generation function to avoid repeating ourselved when
      declaring providers in the authOptions below.
   */</span>
  <span class="hljs-keyword">return</span> {
    <span class="hljs-comment">// e.g. cognito_google | cognito_facebook</span>
    id: <span class="hljs-string">`cognito_<span class="hljs-subst">${provider.toLowerCase()}</span>`</span>,  

    <span class="hljs-comment">// e.g. CognitoGoogle | CognitoFacebook</span>
    name: <span class="hljs-string">`Cognito<span class="hljs-subst">${provider}</span>`</span>,

    <span class="hljs-keyword">type</span>: <span class="hljs-string">"oauth"</span>,

    <span class="hljs-comment">// The id of the app client configured in the user pool.</span>
    clientId: COGNITO_CLIENT_ID,

    <span class="hljs-comment">// The app client secret.</span>
    clientSecret: COGNITO_CLIENT_SECRET,

    wellKnown: <span class="hljs-string">`https://cognito-idp.<span class="hljs-subst">${COGNITO_REGION}</span>.amazonaws.com/<span class="hljs-subst">${COGNITO_USER_POOL_ID}</span>/.well-known/openid-configuration`</span>,

    <span class="hljs-comment">// Authorization endpoint configuration</span>
    authorization: {
      url: <span class="hljs-string">`<span class="hljs-subst">${COGNITO_DOMAIN}</span>/oauth2/authorize`</span>,
      params: {
        response_type: <span class="hljs-string">"code"</span>,
        client_id: COGNITO_CLIENT_ID,
        identity_provider: provider,
        redirect_uri: <span class="hljs-string">`<span class="hljs-subst">${NEXTAUTH_URL}</span>/api/auth/callback/cognito_<span class="hljs-subst">${provider.toLowerCase()}</span>`</span>
      }
    },

    <span class="hljs-comment">// Token endpoint configuration</span>
    token: {
      url: <span class="hljs-string">`<span class="hljs-subst">${COGNITO_DOMAIN}</span>/oauth2/token`</span>,
      params: {
        grant_type: <span class="hljs-string">"authorization_code"</span>,
        client_id: COGNITO_CLIENT_ID,
        client_secret: COGNITO_CLIENT_SECRET,
        redirect_uri: <span class="hljs-string">`<span class="hljs-subst">${NEXTAUTH_URL}</span>/api/auth/callback/cognito_<span class="hljs-subst">${provider.toLowerCase()}</span>`</span>
      }
    },

    <span class="hljs-comment">// userInfo endpoint configuration</span>
    userinfo: {
      url: <span class="hljs-string">`<span class="hljs-subst">${COGNITO_DOMAIN}</span>/oauth2/userInfo`</span>,
    },

    <span class="hljs-comment">// Profile to return after successcul auth.</span>
    <span class="hljs-comment">// You can do some transformation on your profile object here.</span>
    profile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">profile</span>) </span>{
      <span class="hljs-keyword">return</span> {
        id: profile.sub,
        ...profile
      }
    }
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> authOptions = {

  <span class="hljs-comment">/*
    Generate the providers for each of our social login.
    Adding a new OIDC provider is a simple as adding the name of the         provider as displayed in the Cognito user pool to the TProvider type
and to this array.
  */</span>
  providers: [
    ...[<span class="hljs-string">"Amazon"</span>, <span class="hljs-string">"Apple"</span>, <span class="hljs-string">"Facebook"</span>, <span class="hljs-string">"Google"</span>].map(<span class="hljs-function">(<span class="hljs-params">provider: TProvider</span>) =&gt;</span> getProvider(provider)),
  ],

  callbacks: {
    <span class="hljs-keyword">async</span> signIn({ user, account, profile }) {
      <span class="hljs-comment">// Return true to allow sign in and false to block sign in.</span>
      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    },
    <span class="hljs-keyword">async</span> redirect({ url, baseUrl }){
      <span class="hljs-comment">// Return the url to redirect to after successful sign in.</span>
      <span class="hljs-keyword">return</span> baseUrl;
    },
    <span class="hljs-keyword">async</span> jwt({ token, account, profile, user }){
      <span class="hljs-comment">// Retrieve jwt tokens</span>
      <span class="hljs-keyword">if</span> (account) {
        <span class="hljs-comment">// account is provided upon the inital auth</span>
        <span class="hljs-keyword">return</span> {
          ...token,
          accessToken: account.access_token,
          idToken: account.id_token,
        }
      }
    },
    <span class="hljs-keyword">async</span> session({ session, token }) {
      <span class="hljs-comment">/* 
         Forward tokens to client in case you need to make authorized
         API calls to an AWS service directly from the front end.
      */</span>
      session.accessToken = token.accessToken;
      session.idToken = token.idToken;
      <span class="hljs-keyword">return</span> session;
    }
  }
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> NextAuth(authOptions);
</code></pre>
<p>As you can see, we're configuring a basic OAuth2.0 flow. You can read more about Cognito's OIDC endpoints <a target="_blank" href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-userpools-server-contract-reference.html">here</a>. This flow will work with any OIDC provider that you configure in your user pool.</p>
<h3 id="heading-callback-enhancement">Callback enhancement</h3>
<p>Right now there's a scenario we're not handling. When authenticating in this way, Cognito will return a long-lasting refresh token. A refresh token is used to request new access and id tokens when said tokens have expired.</p>
<p>This allows us to keep the user logged in for a long time without forcing them to sign in every time their tokens expire. We will only prompt the user to sign in again once the refresh token itself has expired or has been invalidated in some other way.</p>
<p>To support this functionality, we need to update the code in the <code>jwt</code> and <code>session</code> callback functions.</p>
<p>First, let's update the <code>jwt</code> callback function:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> jwt({ token, account, profile, user }){
  <span class="hljs-keyword">if</span> (account) {
    <span class="hljs-comment">// This is an initial login, set JWT tokens.</span>
    <span class="hljs-keyword">return</span> {
      ...token,
      accessToken: account.access_token,
      idToken: account.id_token,
      refreshToken: account.refresh_token,
      expiresAt: account.expires_at,
      tokenType: <span class="hljs-string">'Bearer'</span>
    }
  }
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Date</span>.now() &lt; token.expiresAt) {
    <span class="hljs-comment">// Access/Id token are still valid, return them as is.</span>
    <span class="hljs-keyword">return</span> token;
  }
  <span class="hljs-comment">// Access/Id tokens have expired, retrieve new tokens using the </span>
  <span class="hljs-comment">// refresh token</span>
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`<span class="hljs-subst">${COGNITO_DOMAIN}</span>/oauth2/token`</span>, {
      headers: { 
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/x-www-form-urlencoded"</span>
      },
      body: <span class="hljs-keyword">new</span> URLSearchParams({
        client_id: COGNITO_CLIENT_ID,
        client_secret: COGNITO_CLIENT_SECRET,
        grant_type: <span class="hljs-string">"refresh_token"</span>,
        refresh_token: token.refreshToken
      }),
      method: <span class="hljs-string">"POST"</span>
    })

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

    <span class="hljs-keyword">if</span> (!response.ok) <span class="hljs-keyword">throw</span> tokens;

    <span class="hljs-keyword">return</span> {
      ...token,
      accessToken: tokens.access_token,
      idToken: tokens.id_token,
      expiresAt: <span class="hljs-built_in">Date</span>.now() + (<span class="hljs-built_in">Number</span>(tokens.expires_in) * <span class="hljs-number">1000</span>)
    }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-comment">// Could not refresh tokens, return error</span>
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error refreshing access and id tokens: "</span>, error);
    <span class="hljs-keyword">return</span> { ...token, error: <span class="hljs-string">"RefreshTokensError"</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span> }
  }
}
</code></pre>
<p>Here's what this function is doing before returning the jwt tokens when a token request is made:</p>
<ol>
<li><p>If it's the first request (i.e initial sign-in action), add <code>accessToken</code>, <code>idToken</code>, <code>refreshToken</code>, and <code>expiresAt</code> to the token object. The <code>expiresAt</code> attribute lets us know when the access and id token will expire. The object returned here will be represented by the <code>token</code> param in all subsequent token requests.</p>
</li>
<li><p>If this is not the first request, check if the access and id tokens have expired by comparing the current time to the <code>expiresAt</code> time in the token object that was set in point 1.</p>
</li>
<li><p>If the tokens have not expired, return the same token object.</p>
</li>
<li><p>If the tokens have expired, fetch new tokens using the refresh token.</p>
</li>
<li><p>If the fetch fails, throw the error. In the catch block, return the current token object but append an <code>error</code> property so we can check for it and redirect the user to the sign-in page.</p>
</li>
<li><p>If the fetch is successful, replace the <code>accessToken</code>, <code>idToken</code> and <code>expiresAt</code> properties in the token object and return the new token object.</p>
</li>
</ol>
<p>Next, we need to update the <code>session</code> callback. This callback allows us to set session properties that will be accessible in the front end via the <code>useSession</code> hook.</p>
<p>All we need to do here is add the <code>error</code> property of the token to the session object. That way we can detect the error in the front end and redirect the user to the sign-in page.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> session({ session, token }) {
  <span class="hljs-comment">/* 
    Forward tokens to client in case you need to make authorized API      
    calls to an AWS service directly from the front end.
  */</span>
  session.accessToken = token.accessToken;
  session.idToken = token.idToken;
  <span class="hljs-comment">/* 
    If there is an error when refreshing tokens, include it so it can 
    be forwarded to the front end.
  */</span>
  session.error = token.error;
  <span class="hljs-keyword">return</span> session;
}
</code></pre>
<h3 id="heading-configuring-shared-session-state">Configuring shared session state</h3>
<p>To configure the sessions state, update the <code>_app.tsx</code> <em>or</em> <code>_app.jsx</code> file with the following code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-string">'../styles/globals.css'</span>;
<span class="hljs-keyword">import</span> { SessionProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"next-auth/react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ 
  Component,
  pageProps: { session, ...pageProps }
}</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;SessionProvider session={session}&gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/SessionProvider&gt;
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp
</code></pre>
<p>This change allows us to use the session throughout the application.</p>
<h3 id="heading-frontend-login-with-providers">Frontend login with providers</h3>
<p>In order to allow the user to sign in with their preferred provider, we have to configure the sign-in buttons for each provider in our SignIn page component.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">/* The getProviders function returns a promise that resolves
   to an object containing all of the configured providers. */</span>
<span class="hljs-comment">// The signIn functions initiates the signIn process.</span>
<span class="hljs-keyword">import</span> { getProviders, signIn } <span class="hljs-keyword">from</span> <span class="hljs-string">"next-auth/react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SignIn</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [providers, setProviders] = useState(<span class="hljs-literal">null</span>);

  <span class="hljs-comment">// Fetch providers on mount.</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    getProviders().then(<span class="hljs-function">(<span class="hljs-params">providers</span>) =&gt;</span> setProviders(providers));
  }, []);

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      {providers &amp;&amp; (
        &lt;&gt;
          &lt;div&gt;
            &lt;button onClick={
              <span class="hljs-function">() =&gt;</span> signIn(providers[<span class="hljs-string">"cognito_amazon"</span>].id)
            }&gt;
              Login <span class="hljs-keyword">with</span> Amazon
            &lt;/button&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;button onClick={
              <span class="hljs-function">() =&gt;</span> signIn(providers[<span class="hljs-string">"cognito_apple"</span>].id)
            }&gt;
              Login <span class="hljs-keyword">with</span> Apple
            &lt;/button&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;button onClick={
              <span class="hljs-function">() =&gt;</span> signIn(providers[<span class="hljs-string">"cognito_facebook"</span>].id)
            }&gt;
              Login <span class="hljs-keyword">with</span> Facebook
            &lt;/button&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;button onClick={
              <span class="hljs-function">() =&gt;</span> signIn(providers[<span class="hljs-string">"cognito_google"</span>].id)
            }&gt;
              Login <span class="hljs-keyword">with</span> Google
            &lt;/button&gt;
          &lt;/div&gt;
        &lt;/&gt;
      )}
    &lt;/div&gt;
  );
}
</code></pre>
<p>For more context, the provider object will take the following shape:</p>
<pre><code class="lang-plaintext">{
  &lt;prodiver_id&gt;: {
    "id": &lt;provider_id&gt;
    "name": &lt;provider_name&gt;
    "type": &lt;provider_type&gt;
    "signinUrl": &lt;provider signin url&gt;
    "callbackUrl": &lt;provider callback url&gt;
  }
}
</code></pre>
<p>In this configuration, the provider object will look like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"cognito_amazon"</span>:
  {
    <span class="hljs-attr">"id"</span>:<span class="hljs-string">"cognito_amazon"</span>,
    <span class="hljs-attr">"name"</span>:<span class="hljs-string">"CognitoAmazon"</span>,
    <span class="hljs-attr">"type"</span>:<span class="hljs-string">"oauth"</span>,
    <span class="hljs-attr">"signinUrl"</span>:
      <span class="hljs-string">"http://localhost:3000/api/auth/signin/cognito_amazon"</span>,
    <span class="hljs-attr">"callbackUrl"</span>:
      <span class="hljs-string">"http://localhost:3000/api/auth/callback/cognito_amazon"</span>
  },
  <span class="hljs-attr">"cognito_apple"</span>:{
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"cognito_apple"</span>,
    <span class="hljs-attr">"name"</span>:<span class="hljs-string">"CognitoApple"</span>,
    <span class="hljs-attr">"type"</span>:<span class="hljs-string">"oauth"</span>,
    <span class="hljs-attr">"signinUrl"</span>:<span class="hljs-string">"http://localhost:3000/api/auth/signin/cognito_apple"</span>,
    <span class="hljs-attr">"callbackUrl"</span>:
      <span class="hljs-string">"http://localhost:3000/api/auth/callback/cognito_apple"</span>
  },
  <span class="hljs-attr">"cognito_facebook"</span>:{
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"cognito_facebook"</span>,
    <span class="hljs-attr">"name"</span>:<span class="hljs-string">"CognitoFacebook"</span>,
    <span class="hljs-attr">"type"</span>:<span class="hljs-string">"oauth"</span>,
    <span class="hljs-attr">"signinUrl"</span>:
      <span class="hljs-string">"http://localhost:3000/api/auth/signin/cognito_facebook"</span>,
    <span class="hljs-attr">"callbackUrl"</span>:
      <span class="hljs-string">"http://localhost:3000/api/auth/callback/cognito_facebook"</span>
  },
  <span class="hljs-attr">"cognito_google"</span>:{
    <span class="hljs-attr">"id"</span>:<span class="hljs-string">"cognito_google"</span>,
    <span class="hljs-attr">"name"</span>:<span class="hljs-string">"CognitoGoogle"</span>,
    <span class="hljs-attr">"type"</span>:<span class="hljs-string">"oauth"</span>,
    <span class="hljs-attr">"signinUrl"</span>:
      <span class="hljs-string">"http://localhost:3000/api/auth/signin/cognito_google"</span>,
    <span class="hljs-attr">"callbackUrl"</span>:
      <span class="hljs-string">"http://localhost:3000/api/auth/callback/cognito_google"</span>
  }
}
</code></pre>
<h3 id="heading-frontend-usesession-hook">Frontend useSession hook</h3>
<p>In order to access the session data in the front end, we can make use of the <code>useSession</code> hook from <code>next-auth/react</code>.</p>
<p>This hook allows us to access the session data and the user's auth status.</p>
<p>First import the hook.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useSession } <span class="hljs-keyword">from</span> <span class="hljs-string">'next-auth/react'</span>
</code></pre>
<p>Then inside your component, use it as follows:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> { data, status } = useSession();
</code></pre>
<p>The <code>data</code> property will contain all the data that we set in the <code>session</code> callback that we configured <code>[...nextauth.ts]</code> . It will also contain an additional <code>user</code> property with information about the current user such as email address.</p>
<p>The <code>status</code> property is a string containing information about the user's auth status. Its possible values are "loading", "authenticated" or "unauthenticated". You can use this to implement protected routes or redirect to the sign-in page when a session is expired.</p>
]]></content:encoded></item><item><title><![CDATA[Web Sockets with API Gateway and AWS Lambda]]></title><description><![CDATA[AWS offers an easy way to work with web sockets through the WebSockets API in API Gateway. This article is going to be a short walkthrough on how to get started with WebSocket APIs.
Setup
This is article is based on a serverless framework project. Yo...]]></description><link>https://kelvinmwinuka.com/web-sockets-with-api-gateway-and-aws-lambda</link><guid isPermaLink="true">https://kelvinmwinuka.com/web-sockets-with-api-gateway-and-aws-lambda</guid><category><![CDATA[AWS]]></category><category><![CDATA[aws lambda]]></category><category><![CDATA[apigateway]]></category><category><![CDATA[websockets]]></category><category><![CDATA[serverless]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Sat, 19 Nov 2022 11:25:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1668829130056/fd-D86Ng6.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>AWS offers an easy way to work with web sockets through the WebSockets API in API Gateway. This article is going to be a short walkthrough on how to get started with WebSocket APIs.</p>
<h2 id="heading-setup">Setup</h2>
<p>This is article is based on a serverless framework project. You can still implement the concepts discussed here without serverless framework.</p>
<p>You can find the code used in this article in <a target="_blank" href="https://github.com/kelvinmwinuka/aws-websockets">this GitHub repository</a>.</p>
<h2 id="heading-serverless-provider-config">Serverless provider config</h2>
<p>The serverless provider configuration will look exactly the same as a regular API project with the exception of one additional property: <code>websocketsApiRouteSelectionExpression</code>.</p>
<p>This property tells API gateway which request body property to use in order to determine where to route the request. In this instance, the <code>action</code> property of the payload will determine which handler gets called.</p>
<p>We'll see this in action when we define the handlers.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">provider:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">aws</span>
  <span class="hljs-attr">runtime:</span> <span class="hljs-string">nodejs14.x</span>
  <span class="hljs-attr">profile:</span> <span class="hljs-string">${env:PROFILE,</span> <span class="hljs-string">"localstack"</span><span class="hljs-string">}</span>
  <span class="hljs-attr">stage:</span> <span class="hljs-string">${opt:stage,</span> <span class="hljs-string">"local"</span><span class="hljs-string">}</span>
  <span class="hljs-attr">region:</span> <span class="hljs-string">${opt:region,</span> <span class="hljs-string">"us-east-1"</span><span class="hljs-string">}</span>
  <span class="hljs-attr">websocketsApiRouteSelectionExpression:</span> <span class="hljs-string">$request.body.action</span>
</code></pre>
<h2 id="heading-connection-table">Connection table</h2>
<p>For our use case, we'll need to maintain a record of active connections in order to send targeted messages. </p>
<p>I've chosen DynamoDB for this demonstration but you might get better mileage using a relational database like PostgreSQL. The concept will be the same, but with a slightly different implementation.</p>
<p>A table row will contain <code>Username</code> and <code>ConnectionId</code> fields for each active connection.</p>
<p>We must create a DynamoDB table resource in the <code>serverless.yaml</code> file. The table will use the Username as the primary key so make sure it's unique.</p>
<p>Since we'll need to query the table by ConnectionId at some point, let's create a global secondary index that uses ConnectionId as the primary key.</p>
<p>You can read more about global secondary indexes <a target="_blank" href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html">here</a>.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">resources:</span>  
  <span class="hljs-attr">Resources:</span>
    <span class="hljs-attr">ConnectionsTable:</span>
      <span class="hljs-attr">Type:</span> <span class="hljs-string">AWS::DynamoDB::Table</span>
      <span class="hljs-attr">Properties:</span>
        <span class="hljs-attr">AttributeDefinitions:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">AttributeName:</span> <span class="hljs-string">Username</span>
            <span class="hljs-attr">AttributeType:</span> <span class="hljs-string">S</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">AttributeName:</span> <span class="hljs-string">ConnectionId</span>
            <span class="hljs-attr">AttributeType:</span> <span class="hljs-string">S</span>
        <span class="hljs-attr">KeySchema:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">AttributeName:</span> <span class="hljs-string">Username</span>
            <span class="hljs-attr">KeyType:</span> <span class="hljs-string">HASH</span>
        <span class="hljs-attr">ProvisionedThroughput:</span>
          <span class="hljs-attr">ReadCapacityUnits:</span> <span class="hljs-number">1</span>
          <span class="hljs-attr">WriteCapacityUnits:</span> <span class="hljs-number">1</span>
        <span class="hljs-attr">GlobalSecondaryIndexes:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">IndexName:</span> <span class="hljs-string">ConnectionIdIndex</span>
            <span class="hljs-attr">KeySchema:</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">AttributeName:</span> <span class="hljs-string">ConnectionId</span>
                <span class="hljs-attr">KeyType:</span> <span class="hljs-string">HASH</span>
            <span class="hljs-attr">Projection:</span>
              <span class="hljs-attr">ProjectionType:</span> <span class="hljs-string">ALL</span>
            <span class="hljs-attr">ProvisionedThroughput:</span>
                <span class="hljs-attr">ReadCapacityUnits:</span> <span class="hljs-number">1</span>
                <span class="hljs-attr">WriteCapacityUnits:</span> <span class="hljs-number">1</span>
</code></pre>
<h2 id="heading-connecting">Connecting</h2>
<p>Now let's create the connection handler. This lambda will be called when a client tries to establish a connection.</p>
<p>The main aim of this handler is to save the connection details in the DynamoDB table so this connection can be targeted when sending a message.</p>
<p>First, let's define the function in <code>serverless.yaml</code> in the <code>function</code> section:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">wsConnectHandler:</span>
    <span class="hljs-attr">handler:</span> <span class="hljs-string">./src/connect.handler</span>
    <span class="hljs-attr">events:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">websocket:</span>
          <span class="hljs-attr">route:</span> <span class="hljs-string">$connect</span>
    <span class="hljs-attr">iamRoleStatements:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">Effect:</span> <span class="hljs-string">"Allow"</span>
        <span class="hljs-attr">Action:</span> <span class="hljs-string">"dynamodb:PutItem"</span>
        <span class="hljs-attr">Resource:</span> <span class="hljs-type">!GetAtt</span> [<span class="hljs-string">ConnectionsTable</span>, <span class="hljs-string">Arn</span>]
</code></pre>
<p>This lambda is triggered by the pre-defined <code>$connect</code> websocket route. We also give this function permission to put an item into the DynamoDB table we defined earlier.</p>
<p>The handler logic looks as follows:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {
  DynamoDBClient,
  PutItemCommand
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-dynamodb"</span>;

<span class="hljs-keyword">const</span> {
  STAGE,
  REGION,
  CONNECTION_TABLE,
  LOCALSTACK_ENDPOINT
} = process.env;

<span class="hljs-keyword">const</span> getDynamoDbConfig = (): { region: <span class="hljs-built_in">string</span>, endpoint?: <span class="hljs-built_in">string</span> } =&gt; {
  <span class="hljs-keyword">if</span> (STAGE === <span class="hljs-string">"local"</span>) <span class="hljs-keyword">return</span> { region: REGION, endpoint: LOCALSTACK_ENDPOINT };
  <span class="hljs-keyword">return</span> { region: REGION };
}

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> (event) =&gt; {
  <span class="hljs-keyword">const</span> dynamoDBClient = <span class="hljs-keyword">new</span> DynamoDBClient(getDynamoDbConfig());

  <span class="hljs-keyword">const</span> putItemCommand = <span class="hljs-keyword">new</span> PutItemCommand({
    TableName: CONNECTION_TABLE,
    Item: {
      Username: { S: event.queryStringParameters.username },
      ConnectionId: { S: event.requestContext.connectionId }
    }
  });
  <span class="hljs-keyword">await</span> dynamoDBClient.send(putItemCommand);

  <span class="hljs-keyword">return</span> { statusCode: <span class="hljs-number">200</span> };
}
</code></pre>
<p>When the connection route is triggered, we create a record in the connection table that contains the username and connection id. </p>
<p>We retrieve the username from the <code>queryStringParameters</code> of the request. To establish a connection, the client will have to send a connection request to <code>wss://&lt;api-id&gt;.execute-api.&lt;region&gt;.amazonaws.com/&lt;stage&gt;/?username=&lt;username&gt;</code>.</p>
<p>If the username isn't provided, an error is thrown and a connection isn't established. We must return a 200 status code for a successful connection.</p>
<p>You can implement custom error handling here if you'd like but AWS will usually display the error in the cloudwatch logs when encountered.</p>
<h2 id="heading-disconnecting">Disconnecting</h2>
<p>Now let's handle disconnection. The disconnection handler is triggered whenever a connection is ended. We can use this to do some cleanup. In our case, the cleanup involves deleting the connection row in our DynamoDB table.</p>
<p>First, let's define the function in <code>serverless.yaml</code></p>
<pre><code class="lang-yaml"><span class="hljs-attr">wsDisconnectHandler:</span>
    <span class="hljs-attr">handler:</span> <span class="hljs-string">./src/disconnect.handler</span>
    <span class="hljs-attr">events:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">websocket:</span>
          <span class="hljs-attr">route:</span> <span class="hljs-string">$disconnect</span>
    <span class="hljs-attr">iamRoleStatements:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">Effect:</span> <span class="hljs-string">"Allow"</span>
        <span class="hljs-attr">Action:</span> 
          <span class="hljs-bullet">-</span> <span class="hljs-string">"dynamodb:DeleteItem"</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">"dynamodb:Query"</span>
        <span class="hljs-attr">Resource:</span> 
          <span class="hljs-bullet">-</span> <span class="hljs-type">!GetAtt</span> [<span class="hljs-string">ConnectionsTable</span>, <span class="hljs-string">Arn</span>]
          <span class="hljs-bullet">-</span> <span class="hljs-type">!Join</span> [<span class="hljs-string">"/"</span>, [<span class="hljs-type">!GetAtt</span> [<span class="hljs-string">ConnectionsTable</span>, <span class="hljs-string">Arn</span>], <span class="hljs-string">"index"</span>, <span class="hljs-string">"ConnectionIdIndex"</span>]]
</code></pre>
<p>Once again, this is triggered by the disconnect event through the pre-defined <code>$disconnect</code> route.</p>
<p>We need to give this function permission to delete from the connection table and query the global secondary index we created earlier. </p>
<p>Here's the handler implementation:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {
  DynamoDBClient,
  DeleteItemCommand,
  QueryCommand,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-dynamodb"</span>;

<span class="hljs-keyword">const</span> {
  STAGE,
  REGION,
  CONNECTION_TABLE,
  LOCALSTACK_ENDPOINT
} = process.env;

<span class="hljs-keyword">const</span> getDynamoDbConfig = (): { region: <span class="hljs-built_in">string</span>, endpoint?: <span class="hljs-built_in">string</span> } =&gt; {
  <span class="hljs-keyword">if</span> (STAGE === <span class="hljs-string">"local"</span>) <span class="hljs-keyword">return</span> { region: REGION, endpoint: LOCALSTACK_ENDPOINT };
  <span class="hljs-keyword">return</span> { region: REGION };
}

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> (event, context, callback) =&gt; {
  <span class="hljs-built_in">console</span>.log(event);

  <span class="hljs-keyword">const</span> dynamoDBClient = <span class="hljs-keyword">new</span> DynamoDBClient(getDynamoDbConfig());

  <span class="hljs-comment">// Retrieve the connection using the connectionId</span>
  <span class="hljs-keyword">const</span> queryCommand = <span class="hljs-keyword">new</span> QueryCommand({
    TableName: CONNECTION_TABLE,
    IndexName: <span class="hljs-string">"ConnectionIdIndex"</span>,
    KeyConditionExpression: <span class="hljs-string">"ConnectionId = :a"</span>,
    ExpressionAttributeValues: {
      <span class="hljs-string">":a"</span>: { S: event.requestContext.connectionId }
    }
  })

  <span class="hljs-keyword">const</span> queryResult = <span class="hljs-keyword">await</span> dynamoDBClient.send(queryCommand);
  <span class="hljs-keyword">const</span> connectionRecord = queryResult?.Items ? queryResult.Items[<span class="hljs-number">0</span>] : <span class="hljs-literal">undefined</span>;

  <span class="hljs-keyword">const</span> deleteItemCommand = <span class="hljs-keyword">new</span> DeleteItemCommand({
    TableName: CONNECTION_TABLE,
    Key: {
      Username: { S : connectionRecord?.Username?.S ? connectionRecord?.Username?.S : <span class="hljs-string">""</span> }
    }
  });
  <span class="hljs-keyword">await</span> dynamoDBClient.send(deleteItemCommand);

  <span class="hljs-keyword">return</span> {
    statusCode: <span class="hljs-number">200</span>,
    body: <span class="hljs-built_in">JSON</span>.stringify({ message: <span class="hljs-string">"Connection ended!"</span> })
  };
}
</code></pre>
<p>We retrieve the connection id from the request context in the event object and query the index to find the connection record with this connection id. </p>
<p>Once we've retrieved the record, we delete it from the connection table using the username as the key.</p>
<h2 id="heading-send-a-message">Send a message</h2>
<p>Now that we've handled connecting and disconnecting, it's time to handle sending messages directly to another connected user.</p>
<p>This handler will work by receiving a payload that contains the recipient's username, finding the recipient's connection record, extracting the connection id, and sending the payload message to the target connection.</p>
<p>First, let's define the function in <code>serverless.yaml</code>:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">wsSendMessage:</span>
    <span class="hljs-attr">handler:</span> <span class="hljs-string">./src/sendMessage.handler</span>
    <span class="hljs-attr">events:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">websocket:</span>
          <span class="hljs-attr">route:</span> <span class="hljs-string">"sendMessage"</span>
    <span class="hljs-attr">iamRoleStatements:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">Effect:</span> <span class="hljs-string">"Allow"</span>
        <span class="hljs-attr">Action:</span> <span class="hljs-string">"dynamodb:Query"</span>
        <span class="hljs-attr">Resource:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-type">!GetAtt</span> [<span class="hljs-string">ConnectionsTable</span>, <span class="hljs-string">Arn</span>]
          <span class="hljs-bullet">-</span> <span class="hljs-type">!Join</span> [<span class="hljs-string">"/"</span>, [<span class="hljs-type">!GetAtt</span> [<span class="hljs-string">ConnectionsTable</span>, <span class="hljs-string">Arn</span>], <span class="hljs-string">"index"</span>, <span class="hljs-string">"ConnectionIdIndex"</span>]]
      <span class="hljs-bullet">-</span> <span class="hljs-attr">Effect:</span> <span class="hljs-string">"Allow"</span>
        <span class="hljs-attr">Action:</span> <span class="hljs-string">"execute-api:ManageConnections"</span>
        <span class="hljs-attr">Resource:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">Fn::Join:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">"/"</span>
            <span class="hljs-bullet">-</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">Fn::Join:</span>
                <span class="hljs-bullet">-</span> <span class="hljs-string">":"</span>
                <span class="hljs-bullet">-</span>
                  <span class="hljs-bullet">-</span> <span class="hljs-string">"arn:aws:execute-api"</span>
                  <span class="hljs-bullet">-</span> <span class="hljs-string">${opt:region,</span> <span class="hljs-string">"us-east-1"</span><span class="hljs-string">}</span>
                  <span class="hljs-bullet">-</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">AWS::AccountId</span>
                  <span class="hljs-bullet">-</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">WebsocketsApi</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">${opt:stage,</span> <span class="hljs-string">'dev'</span><span class="hljs-string">}</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">"POST"</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">"@connections"</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">"{connectionId}"</span>
</code></pre>
<p>Notice we have a slightly different event. The route is set as <code>sendMessage</code>. This is a custom route defined by us.</p>
<p>If you recall, the provider section has this property defined: <code>websocketsApiRouteSelectionExpression: $request.body.action</code>. This tells API Gateway to look for the route in the <code>action</code> property of the request body. </p>
<p>So in order to trigger the <code>wsSendMessage</code> lambda, the message we send once connected needs to be an object that contains the action property with the value of "sendMessage" like so:</p>
<pre><code class="lang-JSON">{
  <span class="hljs-attr">"action"</span>: <span class="hljs-string">"sendMessage"</span>,
  ...
}
</code></pre>
<p>Next, we need to give this lambda permission to query both the connection table and the global secondary index. We also must give it permission to send a message to an existing web socket connection.</p>
<p>This is the handler implementation:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { DynamoDBClient, QueryCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-dynamodb"</span>;

<span class="hljs-keyword">import</span> {
  ApiGatewayManagementApiClient,
  PostToConnectionCommand
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-apigatewaymanagementapi"</span>;

<span class="hljs-keyword">const</span> {
  STAGE,
  REGION,
  CONNECTION_TABLE,
  LOCALSTACK_ENDPOINT,
  PORT
} = process.env;

<span class="hljs-keyword">const</span> getDynamoDbConfig = (): { region: <span class="hljs-built_in">string</span>, endpoint?: <span class="hljs-built_in">string</span> } =&gt; {
  <span class="hljs-keyword">if</span> (STAGE === <span class="hljs-string">"local"</span>) <span class="hljs-keyword">return</span> { region: REGION, endpoint: LOCALSTACK_ENDPOINT };
  <span class="hljs-keyword">return</span> { region: REGION };
}

<span class="hljs-keyword">const</span> getConnectionEndpoint = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> STAGE === <span class="hljs-string">"local"</span> ? 
  <span class="hljs-string">`http://<span class="hljs-subst">${event.requestContext.domainName}</span>:<span class="hljs-subst">${PORT}</span>`</span> :
  <span class="hljs-string">`https://<span class="hljs-subst">${event.requestContext.domainName}</span>/<span class="hljs-subst">${event.requestContext.stage}</span>/`</span>
}

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> (event, context, callback) =&gt; {
  <span class="hljs-built_in">console</span>.log(event);

  <span class="hljs-keyword">const</span> body = <span class="hljs-built_in">JSON</span>.parse(event.body);

  <span class="hljs-keyword">const</span> dynamoDBClient = <span class="hljs-keyword">new</span> DynamoDBClient(getDynamoDbConfig());

  <span class="hljs-comment">/**
   * Query the connection table for the TARGET connection record.
   * The recepient's username used in the query will be included in the event body.
   */</span>
  <span class="hljs-keyword">let</span> queryResult = <span class="hljs-keyword">await</span> dynamoDBClient.send(<span class="hljs-keyword">new</span> QueryCommand({
    TableName: CONNECTION_TABLE,
    KeyConditionExpression: <span class="hljs-string">"Username = :a"</span>,
    ExpressionAttributeValues: {
      <span class="hljs-string">":a"</span>: { S: body.recepient}
    }
  }));

  <span class="hljs-comment">// Return early if the recepient is not found in the connections table.</span>
  <span class="hljs-keyword">if</span> (!(queryResult?.Items?.length &amp;&amp; queryResult?.Items?.length &gt; <span class="hljs-number">0</span>)) <span class="hljs-keyword">return</span> callback(<span class="hljs-built_in">JSON</span>.stringify({
    message: <span class="hljs-string">"Recepient not found"</span>,
    body
  }));

  <span class="hljs-keyword">const</span> recepientConnection =  queryResult.Items[<span class="hljs-number">0</span>];

  <span class="hljs-comment">/**
   * Query ConnectionIdIndex using the connection id of the sender.
   * The senders connection id can be found in event.requestContext.connectionId.
   * We retrieve this connection record in order to retrieve the sender's username.
   */</span>
  queryResult = <span class="hljs-keyword">await</span> dynamoDBClient.send(<span class="hljs-keyword">new</span> QueryCommand({
    TableName: CONNECTION_TABLE,
    IndexName: <span class="hljs-string">"ConnectionIdIndex"</span>,
    KeyConditionExpression: <span class="hljs-string">"ConnectionId = :b"</span>,
    ExpressionAttributeValues: {
      <span class="hljs-string">":b"</span>: { S: event.requestContext.connectionId }
    },
  }));

  <span class="hljs-comment">// Return early if no actively connected sender is found.</span>
  <span class="hljs-keyword">if</span> (!(queryResult?.Items?.length &amp;&amp; queryResult?.Items?.length &gt; <span class="hljs-number">0</span>)) <span class="hljs-keyword">return</span> callback(<span class="hljs-built_in">JSON</span>.stringify({
    message: <span class="hljs-string">"Sender not found"</span>,
    context: event.requestContext
  }));

  <span class="hljs-keyword">const</span> senderConnection = queryResult?.Items ? queryResult.Items[<span class="hljs-number">0</span>]: <span class="hljs-literal">undefined</span>;

  <span class="hljs-keyword">const</span> apiGatewayManagementApiClient = <span class="hljs-keyword">new</span> ApiGatewayManagementApiClient({ 
    region: REGION,
    endpoint: getConnectionEndpoint(event)
  });

  <span class="hljs-comment">// Post a message to the recipient's connection.</span>
  <span class="hljs-keyword">const</span> postToConnectionCommand = <span class="hljs-keyword">new</span> PostToConnectionCommand({
    ConnectionId: recepientConnection?.ConnectionId.S,
    Data: Buffer.from(<span class="hljs-built_in">JSON</span>.stringify({
      <span class="hljs-keyword">from</span>: senderConnection?.Username.S,
      message: body.message
    }), <span class="hljs-string">"utf-8"</span>)
  });

<span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> apiGatewayManagementApiClient.send(postToConnectionCommand);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  }

  <span class="hljs-keyword">return</span> { 
    statusCode: <span class="hljs-number">200</span>,
    body: <span class="hljs-built_in">JSON</span>.stringify({ message: <span class="hljs-string">"Message sent."</span> })
  };
}
</code></pre>
<p>In order to test this, send a message to the connection with the following signature:</p>
<pre><code class="lang-JSON">{
  <span class="hljs-attr">"action"</span>: <span class="hljs-string">"sendMessage"</span>,
  <span class="hljs-attr">"recepient"</span>: &lt;username&gt;,
  <span class="hljs-attr">"message"</span>: &lt;string&gt;
}
</code></pre>
<p>Make sure the recipient is connected as well.</p>
<p>For more in-depth reading on WebSocket APIs, visit the official AWS docs <a target="_blank" href="https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html">here</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Google Login on AWS Cognito Without Hosted UI (Work-around)]]></title><description><![CDATA[I've previously written an article about basic username/password authentication with AWS Cognito. This article will cover registration and authentication using Google. 
Cognito offers this functionality built into the hosted-ui. However, if you find ...]]></description><link>https://kelvinmwinuka.com/google-login-on-aws-cognito-without-hosted-ui-work-around</link><guid isPermaLink="true">https://kelvinmwinuka.com/google-login-on-aws-cognito-without-hosted-ui-work-around</guid><category><![CDATA[AWS]]></category><category><![CDATA[Google]]></category><category><![CDATA[authentication]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Sat, 23 Apr 2022 17:50:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1650724320867/kZtsNzfG-.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've previously written an article about <a target="_blank" href="https://kelvinmwinuka.com/basic-authentication-with-aws-cognito-and-nextjs">basic username/password authentication with AWS Cognito</a>. This article will cover registration and authentication using Google. </p>
<p>Cognito offers this functionality built into the hosted-ui. However, if you find the hosted UI to be limited in terms of design or functionality, you might want to implement this authentication method using the <a target="_blank" href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/index.html">AWS SDK</a> in your own custom UI.</p>
<p>Unfortunately, there is no straightforward way of doing this, so this is a possible workaround to that particular limitation.</p>
<p>If you haven't read the other articles in this series, I'm using a react frontend with a nodejs backend for this tutorial. My framework of choice is NextJS. You don't have to use this exact framework. As long as you use a JS frontend and a NodeJS backend, you should be able to adapt this tutorial to your own stack.</p>
<h2 id="heading-setup">Setup</h2>
<p>First, we need to install a couple of packages to help us out in our implementation. The 2 packages we need are <code>react-google-login</code> to facilitate Google login in the frontend, and <code>google-auth-library</code> for verifying Google tokens in the backend.</p>
<p>Install the packages with the following command in the terminal: <code>npm install react-google-login google-auth-library</code>.</p>
<h2 id="heading-registration">Registration</h2>
<p>On the registration page, import <code>GoogleLogin</code> from <code>react-google-login</code> and add the button to the layout. </p>
<p>You can find more information about this package and how to customise the button <a target="_blank" href="https://www.npmjs.com/package/react-google-login">here</a>.</p>
<pre><code><span class="hljs-operator">&lt;</span>GoogleLogin
    clientId<span class="hljs-operator">=</span>{process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID}
    responseType<span class="hljs-operator">=</span>{<span class="hljs-string">'id_token'</span>}
    buttonText<span class="hljs-operator">=</span><span class="hljs-string">"Register with Google"</span>
    onSuccess<span class="hljs-operator">=</span>{googleRegisterSuccess}
    onFailure<span class="hljs-operator">=</span>{googleRegisterFailure}
<span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
</code></pre><p>We pass the <code>googleRegisterSuccess</code> function to the <code>onSuccess</code> prop. We have a <code>useRegister</code> hook that contains the <code>googleRegisterSuccess</code> function.</p>
<p>Now, define the <code>googleRegisterSuccess</code> function in the <code>useRegister</code> hook as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> googleRegisterSuccess = <span class="hljs-function">(<span class="hljs-params">googleResponse</span>) =&gt;</span> {
        fetch(<span class="hljs-string">'/api/register/google'</span>, {
            <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
            <span class="hljs-attr">headers</span>: {
                <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
            },
            <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">id_token</span>: googleResponse?.tokenId })
        }).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (!res.ok) <span class="hljs-keyword">throw</span> res
            router.push({
                <span class="hljs-attr">pathname</span>: <span class="hljs-string">'/login'</span>
            })
        }).catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
            <span class="hljs-built_in">console</span>.error(err)
        })
    }

<span class="hljs-keyword">const</span> googleRegisterFailure = <span class="hljs-function">(<span class="hljs-params">googleResponse</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(googleResponse)
}
</code></pre>
<p>All we're interested in from the response object is the <code>tokenId</code>, which we send to the backend for verification. </p>
<p>In the handler for the Google register route, we have the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { CognitoIdentityProviderClient, SignUpCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-sdk/client-cognito-identity-provider'</span>
<span class="hljs-keyword">import</span> { OAuth2Client } <span class="hljs-keyword">from</span> <span class="hljs-string">'google-auth-library'</span>

<span class="hljs-keyword">const</span> {
  COGNITO_REGION,
  COGNITO_APP_CLIENT_ID,
  GOOGLE_TOKEN_ISSUER,
  NEXT_PUBLIC_GOOGLE_CLIENT_ID,
} = process.env

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">if</span> (req.method !== <span class="hljs-string">'POST'</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">405</span>).send()

  <span class="hljs-keyword">let</span> googlePayload

  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Verify the id token from google</span>
    <span class="hljs-keyword">const</span> oauthClient = <span class="hljs-keyword">new</span> OAuth2Client(NEXT_PUBLIC_GOOGLE_CLIENT_ID)
    <span class="hljs-keyword">const</span> ticket = <span class="hljs-keyword">await</span> oauthClient.verifyIdToken({
      <span class="hljs-attr">idToken</span>: req.body.id_token,
      <span class="hljs-attr">audience</span>: NEXT_PUBLIC_GOOGLE_CLIENT_ID
    })
    googlePayload = ticket.getPayload()
    <span class="hljs-keyword">if</span> (
      !googlePayload?.iss === GOOGLE_TOKEN_ISSUER ||
      !googlePayload?.aud === NEXT_PUBLIC_GOOGLE_CLIENT_ID
    ) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Token issuer or audience invalid."</span>)
    }
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">422</span>).json({ <span class="hljs-attr">message</span>: err.toString() })
  }

  <span class="hljs-comment">// Register the user</span>
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> params = {
      <span class="hljs-attr">ClientId</span>: COGNITO_APP_CLIENT_ID,
      <span class="hljs-attr">Username</span>: googlePayload.email.split(<span class="hljs-string">"@"</span>)[<span class="hljs-number">0</span>], <span class="hljs-comment">// Username extracted from email address</span>
      <span class="hljs-attr">Password</span>: googlePayload.sub,
      <span class="hljs-attr">UserAttributes</span>: [
        {
          <span class="hljs-attr">Name</span>: <span class="hljs-string">'email'</span>,
          <span class="hljs-attr">Value</span>: googlePayload.email
        },
        {
          <span class="hljs-attr">Name</span>: <span class="hljs-string">'custom:RegistrationMethod'</span>,
          <span class="hljs-attr">Value</span>: <span class="hljs-string">'google'</span>
        }
      ],
      <span class="hljs-attr">ClientMetadata</span>: {
        <span class="hljs-string">'EmailVerified'</span>: googlePayload.email_verified.toString()
      }
    }
    <span class="hljs-keyword">const</span> cognitoClient = <span class="hljs-keyword">new</span> CognitoIdentityProviderClient({
      <span class="hljs-attr">region</span>: COGNITO_REGION
    })
    <span class="hljs-keyword">const</span> signUpCommand = <span class="hljs-keyword">new</span> SignUpCommand(params)
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> cognitoClient.send(signUpCommand)
    <span class="hljs-keyword">return</span> res.status(response[<span class="hljs-string">'$metadata'</span>].httpStatusCode).send()
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.log(err)
    <span class="hljs-keyword">return</span> res.status(err[<span class="hljs-string">'$metadata'</span>].httpStatusCode).json({ <span class="hljs-attr">message</span>: err.toString() })
  }
}
</code></pre>
<p>Let's go through what's happening here:</p>
<ol>
<li><p>We need to verify the <code>idToken</code> by using the <code>google-auth-library</code> package. After verifying the token, we get a "payload" that contains some useful information about the user and about the token.</p>
</li>
<li><p>We need to check that the token issuer is <code>accounts.google.com</code> or <code>https://accounts.google.com</code> and that the audience matches our Google client id.</p>
</li>
<li><p>Next, we register the user with the <code>SignUpCommand</code>. We use a substring of the email as the username and the <code>sub</code> as the password. You'll want to be careful, you may need to find a more creative way to set the password. </p>
</li>
</ol>
<p>Just make sure you can reproduce the string that you pass here otherwise the user will not be able to sign in later. Here, I've used <code>sub</code> because it does not change. You can hash this, add a prefix/suffix, or both if you want to go the extra mile.</p>
<p>In <code>ClientMetadata</code>, we specify the verification status for this email address. We will be using this in the pre-signup trigger later on.</p>
<p>Optionally, you can set a custom attribute <code>custom:RegistrationMethod</code> in case you have several registration methods for your user pool.</p>
<h2 id="heading-presignup-trigger">PreSignup Trigger</h2>
<p>In a previous article on <a target="_blank" href="https://kelvinmwinuka.com/pre-signup-validation-on-aws-cognito">cognito pre-signup triggers</a>, we added some custom logic upon signup that checks if the provided email address is already in use. Feel free to check that article out for more details on that.</p>
<p>We are going to add some logic to that pre-signup trigger to cater to users who register using Google.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports.handler = <span class="hljs-keyword">async</span> (event, context, callback) =&gt; {
  <span class="hljs-comment">// Check if the provided email address is already in use</span>

  <span class="hljs-comment">// Verify user's email address if it's already verified with Google.</span>
  <span class="hljs-keyword">if</span> (event.request.userAttributes[<span class="hljs-string">'custom:RegistrationMethod'</span>] === <span class="hljs-string">"google"</span>) {
    <span class="hljs-keyword">let</span> userEmailVerified = event.request.clientMetadata[<span class="hljs-string">'EmailVerified'</span>] === <span class="hljs-string">'true'</span>
    event.response.autoVerifyEmail = userEmailVerified
    event.response.autoConfirmUser = userEmailVerified
  }

  callback(<span class="hljs-literal">null</span>, event);
};
</code></pre>
<p>If the user's email address is already verified by Google, we don't need to verify it ourselves. So we set <code>autoVerifyEmail</code> to whatever value we set in the <code>EmailVerified</code> attribute of the <code>ClientMetadata</code>.</p>
<p>When you set <code>autoVerifyEmail</code> to <code>true</code>, you also have to do the same for <code>autoConfirmUser</code> as you cannot verify an email address without confirming the user in cognito.</p>
<p>You can find the code for the cognito triggers I use in this series in <a target="_blank" href="https://github.com/kelvinmwinuka/cognito-triggers">this Github repo</a>.</p>
<h2 id="heading-sign-in">Sign in</h2>
<p>Now, that we've handled registration, let's handle signing in. On your login page, add the <code>GoogleLogin</code> button just like we did in the registration page.</p>
<pre><code><span class="hljs-operator">&lt;</span>GoogleLogin 
    clientId<span class="hljs-operator">=</span>{process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID}
    buttonText<span class="hljs-operator">=</span><span class="hljs-string">"Login with Google"</span>
    responseType<span class="hljs-operator">=</span>{<span class="hljs-string">'id_token'</span>}
    onSuccess<span class="hljs-operator">=</span>{googleSignInSuccess}
    onFailure<span class="hljs-operator">=</span>{googleSignInFailure}
<span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
</code></pre><p>The <code>useAuth</code> hook contains a <code>googleSignInSuccess</code> function that sends the <code>tokenId</code> from Google to the Google login API endpoint on the backend. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> googleSignInSuccess = <span class="hljs-function">(<span class="hljs-params">googleResponse</span>) =&gt;</span> {
    fetch(<span class="hljs-string">'/api/login/google'</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
      <span class="hljs-attr">headers</span>: { 
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">id_token</span>: googleResponse?.tokenId })
    }).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
      <span class="hljs-keyword">if</span> (!res.ok) <span class="hljs-keyword">throw</span> res
      <span class="hljs-keyword">return</span> res.json()
    }).then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(data)
    }).catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
      <span class="hljs-built_in">console</span>.error(err)
    })
  }

  <span class="hljs-keyword">const</span> googleSignInFailure = <span class="hljs-function">(<span class="hljs-params">googleResponse</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(googleResponse)
  }
</code></pre>
<p>In the backend, we handle the login as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { CognitoIdentityProviderClient, AdminInitiateAuthCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-cognito-identity-provider"</span>;
<span class="hljs-keyword">import</span> { OAuth2Client } <span class="hljs-keyword">from</span> <span class="hljs-string">"google-auth-library"</span>;

<span class="hljs-keyword">const</span> {
  COGNITO_REGION,
  COGNITO_APP_CLIENT_ID,
  COGNITO_USER_POOL_ID,
  GOOGLE_TOKEN_ISSUER,
  NEXT_PUBLIC_GOOGLE_CLIENT_ID
} = process.env

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>)</span>{
  <span class="hljs-keyword">if</span> (!req.method === <span class="hljs-string">'POST'</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">405</span>).send()

  <span class="hljs-keyword">let</span> googlePayload

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> oauthClient = <span class="hljs-keyword">new</span> OAuth2Client(NEXT_PUBLIC_GOOGLE_CLIENT_ID)
    <span class="hljs-keyword">const</span> ticket = <span class="hljs-keyword">await</span> oauthClient.verifyIdToken({
      <span class="hljs-attr">idToken</span>: req.body.id_token,
      <span class="hljs-attr">audience</span>: NEXT_PUBLIC_GOOGLE_CLIENT_ID
    })
    googlePayload = ticket.getPayload()
    <span class="hljs-keyword">if</span> (
      !googlePayload?.iss === GOOGLE_TOKEN_ISSUER ||
      !googlePayload?.aud === NEXT_PUBLIC_GOOGLE_CLIENT_ID
    ) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Token issuer or audience invalid."</span>)
    }
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">422</span>).json({ <span class="hljs-attr">message</span>: err.toString() })
  }

  <span class="hljs-comment">// Sign the user in</span>
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> params = {
      <span class="hljs-attr">AuthFlow</span>: <span class="hljs-string">'ADMIN_USER_PASSWORD_AUTH'</span>,
      <span class="hljs-attr">ClientId</span>: COGNITO_APP_CLIENT_ID,
      <span class="hljs-attr">UserPoolId</span>: COGNITO_USER_POOL_ID,
      <span class="hljs-attr">AuthParameters</span>: {
        <span class="hljs-attr">USERNAME</span>: googlePayload?.email,
        <span class="hljs-attr">PASSWORD</span>: googlePayload?.sub
      }
    }
    <span class="hljs-keyword">const</span> cognitoClient = <span class="hljs-keyword">new</span> CognitoIdentityProviderClient({
      <span class="hljs-attr">region</span>: COGNITO_REGION
    })
    <span class="hljs-keyword">const</span> adminInitiateAuthCommand = <span class="hljs-keyword">new</span> AdminInitiateAuthCommand(params)
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> cognitoClient.send(adminInitiateAuthCommand)
    <span class="hljs-keyword">return</span> res.status(response[<span class="hljs-string">'$metadata'</span>].httpStatusCode).json({
      ...response.AuthenticationResult
    })
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.log(err)
    <span class="hljs-keyword">return</span> res.status(err[<span class="hljs-string">'$metadata'</span>].httpStatusCode).json({ <span class="hljs-attr">message</span>: err.toString() })
  }
}
</code></pre>
<p>The first part of the handler is quite similar to the registration: we verify the token and grab the user's profile details along with more information about the token.</p>
<p>We check the token's issuer and audience to make sure they are correct, and then we proceed to the sign in.</p>
<p>For signing in, we use <code>AdminInitiateAuthCommand</code> along with the <code>ADMIN_USER_PASSWORD_AUTH</code> authentication flow in the params. </p>
<p><code>AdminInitiateAuthCommand</code> is the recommended way to handle auth in a secure backend environment as it requires developer credentials, adding an extra layer of security.</p>
<p>Pass the username in the <code>params</code> and then generate the password the same way you did in the registration handler. This is why it's important to be able to reproduce the password you created in the registration.</p>
<p>Although we're logging in with Google on the surface, we're still using username/password "under the hood".</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>That's it on this workaround on Google login with AWS Cognito without going through the hosted UI. This is not an ideal solution, but it serves the purpose if you want to quickly implement simple Google signup/sign-in in your app.</p>
<p>You can check out <a target="_blank" href="https://github.com/kelvinmwinuka/cognito-next">this repository</a> for the code I reference in this series.</p>
]]></content:encoded></item><item><title><![CDATA[Deploy Cognito Triggers Using Serverless Framework]]></title><description><![CDATA[Recently, I posted an article about pre signup triggers for AWS Cognito user pools. The article went over setting up pre signup validation using a lambda function.
In this article, I'm going to demonstrate how to achieve the same goal, but using the ...]]></description><link>https://kelvinmwinuka.com/deploy-cognito-triggers-using-serverless-framework</link><guid isPermaLink="true">https://kelvinmwinuka.com/deploy-cognito-triggers-using-serverless-framework</guid><category><![CDATA[Web Development]]></category><category><![CDATA[AWS]]></category><category><![CDATA[aws lambda]]></category><category><![CDATA[serverless]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Mon, 11 Apr 2022 15:36:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649618082761/o62tixmBW.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I posted an article about <a target="_blank" href="https://kelvinmwinuka.com/pre-signup-validation-on-aws-cognito">pre signup triggers for AWS Cognito user pools</a>. The article went over setting up pre signup validation using a lambda function.</p>
<p>In this article, I'm going to demonstrate how to achieve the same goal, but using the serverless framework instead of the AWS console to develop and deploy the lambdas and policies.</p>
<h2 id="heading-setup">Setup</h2>
<p>First install the serverless framework using the following command: <code>npm install -g serverless</code>.</p>
<p>Once serverless is installed, create a project with the following command; <code>serverless create --template aws-nodejs -n cognito-triggers</code>.</p>
<p>With the command above, we're creating a nodejs serverless project intended to be hosted on the AWS cloud platform. We then pass the name of <code>cognito-triggers</code> for the project.</p>
<p>Feel free to use whatever language you want in this project, just be sure to follow your language's package installation and build steps where necessary.</p>
<h2 id="heading-implementation">Implementation</h2>
<p>First, let's create a <code>.env</code> file at the root of the project with the following content:</p>
<pre><code>COGNITO_USER_POOL_NAME<span class="hljs-operator">=</span><span class="hljs-operator">&lt;</span>user_pool_name<span class="hljs-operator">&gt;</span>
COGNITO_USER_POOL_ID<span class="hljs-operator">=</span><span class="hljs-operator">&lt;</span>user_pool_id<span class="hljs-operator">&gt;</span>
COGNITO_USER_POOL_ARN<span class="hljs-operator">=</span><span class="hljs-operator">&lt;</span>user_pool_arn<span class="hljs-operator">&gt;</span>
REGION<span class="hljs-operator">=</span>us<span class="hljs-operator">-</span>west<span class="hljs-number">-2</span>
</code></pre><p>If you're deploying to multiple environments (e.g. testing, staging, production) then you should have multiple env files in your project named in the format <code>.env.{stage}</code>. So the production env file will be <code>.env.production</code>. </p>
<p>For this project, we will stick to one env file for the sake of simplicity.</p>
<p>Let's install a few packages we're going to need for this project with the following command: <code>npm install @aws-sdk/client-cognito-identity-provider dotenv serverless-dotenv-plugin</code></p>
<p>We will need the <code>dotenv</code> and <code>serverless-dotenv-plugin</code> for loading environment variables. We also need the <code>serverless-offline</code> package if we want to invoke our lambda functions locally. We won't be going into that in this article but you can install it with <code>npm install -D serverless-offline</code>.</p>
<p>You'll notice that there's a <code>serveless.yml</code> file at the root of the project. Open the file and add the following code:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">service:</span> <span class="hljs-string">cognito-triggers</span>

<span class="hljs-attr">useDotenv:</span> <span class="hljs-literal">true</span>

<span class="hljs-attr">plugins:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">serverless-dotenv-plugin</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">serverless-offline</span>

<span class="hljs-attr">frameworkVersion:</span> <span class="hljs-string">'3'</span>
</code></pre>
<p>In the code above, we're setting the service name, setting <code>useDotenv: true</code> to allow us to load environment variables. </p>
<p>The plugins section has 2 plugins: </p>
<ol>
<li><code>serverless-dotenv-plugin</code> for loading environment variables.</li>
<li><code>serverless-offline</code> for running the project on the local machine (in case you want to invoke the functions locally).</li>
</ol>
<p>Now let's define the provider:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">provider:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">aws</span>
  <span class="hljs-attr">runtime:</span> <span class="hljs-string">nodejs14.x</span>
  <span class="hljs-attr">stage:</span> <span class="hljs-string">${opt:stage,</span> <span class="hljs-string">'dev'</span><span class="hljs-string">}</span>
  <span class="hljs-attr">region:</span> <span class="hljs-string">${env:REGION}</span>
  <span class="hljs-attr">profile:</span> <span class="hljs-string">default</span>
  <span class="hljs-attr">iam:</span>
    <span class="hljs-attr">role:</span>
      <span class="hljs-attr">statements:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">Effect:</span> <span class="hljs-string">'Allow'</span>
          <span class="hljs-attr">Action:</span> <span class="hljs-string">'cognito-idp:ListUsers'</span>
          <span class="hljs-attr">Resource:</span> <span class="hljs-string">'${env:COGNITO_USER_POOL_ARN}'</span>

<span class="hljs-attr">package:</span>
  <span class="hljs-attr">patterns:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">'!.gitignore'</span>
</code></pre>
<p>We set the provider name to <code>aws</code> because we're using the AWS platform. Our runtime of choice is nodejs14.x. Be sure to use a runtime that's available for the platform you're deploying to.</p>
<p>When setting the stage, we prefer the provided <code>--stage</code> in the command options. If one is not provided, default to <code>dev</code>. This will dictate which environment file to use when running the service offline or deploying. For example <code>sls offline --stage staging</code> will run the service on your local machine using <code>.env.staging</code> while <code>sls deploy --stage production</code> will deploy the service with the <code>.env.production</code> file.</p>
<p>Now for the interesting part, the actual lambda functions! At the top level of the <code>serverless.yml</code> file right below the provider section, create a function section with the following code:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">functions:</span>
  <span class="hljs-attr">pre_signup:</span>
    <span class="hljs-attr">handler:</span> <span class="hljs-string">./src/pre_signup.handler</span>
    <span class="hljs-attr">events:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">cognitoUserPool:</span>
          <span class="hljs-attr">pool:</span> <span class="hljs-string">${env:COGNITO_USER_POOL_NAME}</span>
          <span class="hljs-attr">trigger:</span> <span class="hljs-string">PreSignUp</span>
          <span class="hljs-attr">existing:</span> <span class="hljs-literal">true</span>
</code></pre>
<p>The <code>functions</code> section is where we declare the lambda functions in our service. Here we have a <code>pre_signup</code> function.</p>
<p>The <code>handler</code> property of the function points to the handler function exported by a js file. Make sure the path matches the location of your file. Here we have the file in an <code>src</code> folder that's located at the root of the project.</p>
<p>The <code>events</code> property determines what kind of events can trigger this lambda function. This can be an HTTP request through an API gateway, or in our case, a Cognito signup to a user pool.</p>
<p>If you already have an existing user pool, you have to set the <code>existing</code> property to <code>true</code> for the <code>cognitoUserPool</code> while specifying the user pool's name in the <code>pool</code> property.</p>
<p>Let's create the js function to handle all the pre signup logic.</p>
<p>Create an <code>src</code> folder at the root of the project and then create a file called <code>pre_signup.js</code> within that folder. The file will have the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-meta">'use strict'</span>;
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config({});

<span class="hljs-keyword">const</span> { COGNITO_USER_POOL_ID } = process.env;

<span class="hljs-keyword">const</span> {
  CognitoIdentityProviderClient,
  ListUsersCommand
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@aws-sdk/client-cognito-identity-provider"</span>);

<span class="hljs-built_in">module</span>.exports.handler = <span class="hljs-keyword">async</span> (event, context, callback) =&gt; {
  <span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> CognitoIdentityProviderClient();

  <span class="hljs-keyword">const</span> listUsersCommand = <span class="hljs-keyword">new</span> ListUsersCommand({
    <span class="hljs-attr">UserPoolId</span>: COGNITO_USER_POOL_ID,
    <span class="hljs-attr">Filter</span>: <span class="hljs-string">`email = "<span class="hljs-subst">${event.request.userAttributes.email}</span>"`</span>
  });

  <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> client.send(listUsersCommand);

  <span class="hljs-keyword">if</span> (result.Users.length &gt; <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> callback(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Email is already in use."</span>), event);

  callback(<span class="hljs-literal">null</span>, event);
};
</code></pre>
<p>This code is very familiar if you read my previous article on <a target="_blank" href="https://kelvinmwinuka.com/pre-signup-validation-on-aws-cognito">Pre Signup Validation on AWS Cognito</a>. Basically, we're listing the users in our user pool that have the same email address as the one provided in this signup attempt. If we have more than 0, then throw an error stating that the email address is already in use.</p>
<p>Notice, we're exporting a <code>handler</code> function. This is the function that we reference in the <code>serverless.yml</code> file.</p>
<p>While we're here, let's create another function to edit the messages sent to the user's email address. Cognito user pools have a <code>Custom message</code> trigger that allows us to intercept a message before it's sent and edit its content.</p>
<p>In the <code>functions</code> section of <code>serverless.yml</code>, create a function called <code>custom_message</code> with the following properties:</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">custom_message:</span>
    <span class="hljs-attr">handler:</span> <span class="hljs-string">./src/custom_message.handler</span>
    <span class="hljs-attr">events:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">cognitoUserPool:</span>
          <span class="hljs-attr">pool:</span> <span class="hljs-string">${env:COGNITO_USER_POOL_NAME}</span>
          <span class="hljs-attr">trigger:</span> <span class="hljs-string">CustomMessage</span>
          <span class="hljs-attr">existing:</span> <span class="hljs-literal">true</span>
</code></pre>
<p>It is identical to the pre_signup functions except it's referencing a different handler and hooking into the CustomMessage trigger.</p>
<p>In the <code>src</code> folder create a <code>custom_message.js</code> file with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-meta">'use strict'</span>;
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config({});

<span class="hljs-built_in">module</span>.exports.handler = <span class="hljs-keyword">async</span> (event, context, callback) =&gt; {
  <span class="hljs-keyword">switch</span>(event.triggerSource) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">"CustomMessage_SignUp"</span>:
      event.response.smsMessage = <span class="hljs-string">`Hi <span class="hljs-subst">${event.userName}</span>, your signup code is <span class="hljs-subst">${event.request.codeParameter}</span>`</span>;
      event.response.emailSubject = <span class="hljs-string">`Your registration code`</span>;
      event.response.emailMessage = <span class="hljs-string">`Hi <span class="hljs-subst">${event.userName}</span>, your signup code is <span class="hljs-subst">${event.request.codeParameter}</span>`</span>;
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">"CustomMessage_ForgotPassword"</span>:
      event.response.smsMessage = <span class="hljs-string">`Hi <span class="hljs-subst">${event.userName}</span>, your password reset code is <span class="hljs-subst">${event.request.codeParameter}</span>. If you did not request this code, ignore this message. Please DO NOT share this code with anyone.`</span>;
      event.response.emailSubject = <span class="hljs-string">`Your password reset code`</span>;
      event.response.emailMessage = <span class="hljs-string">`Hi <span class="hljs-subst">${event.userName}</span>, your password reset code is <span class="hljs-subst">${event.request.codeParameter}</span>. If you did not request this code, ignore this email. Please DO NOT share this code with anyone.`</span>;
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">"CustomMessage_ResendCode"</span>:
      event.response.smsMessage = <span class="hljs-string">`Hi <span class="hljs-subst">${event.userName}</span>, your requested code is <span class="hljs-subst">${event.request.codeParameter}</span>`</span>;
      event.response.emailSubject = <span class="hljs-string">`Your requested code`</span>;
      event.response.emailMessage = <span class="hljs-string">`Hi <span class="hljs-subst">${event.userName}</span>, your requested verification code is <span class="hljs-subst">${event.request.codeParameter}</span>`</span>;
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">default</span>:
      event.response.smsMessage = <span class="hljs-string">`Hi <span class="hljs-subst">${event.userName}</span>, your requested code is <span class="hljs-subst">${event.request.codeParameter}</span>`</span>;
      event.response.emailSubject = <span class="hljs-string">`Your requested code`</span>;
      event.response.emailMessage = <span class="hljs-string">`Hi <span class="hljs-subst">${event.userName}</span>, your requested code is <span class="hljs-subst">${event.request.codeParameter}</span>`</span>;
  }
  callback(<span class="hljs-literal">null</span>, event);
}
</code></pre>
<p>The handler captures different message events and displays a relevant message depending on the message event. <code>CustomMessage_SignUp</code> is the trigger source when the signup verification email is triggered, <code>CustomMessage_ForgotPassword</code> for the password reset email and <code>CustomMessage_ResendCode</code> when a manual code request is triggered (e.g attempting to log in when unconfirmed). </p>
<p>You can find more information about the different trigger sources <a target="_blank" href="https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-message.html">here</a>.</p>
<p>The event object for this trigger looks like this: </p>
<pre><code class="lang-json">{
  version: '<span class="hljs-number">1</span>',
  region: 'us-west<span class="hljs-number">-2</span>',
  userPoolId: '&lt;user_pool_id&gt;',
  userName: '&lt;username&gt;',
  callerContext: {
    awsSdkVersion: 'aws-sdk-js<span class="hljs-number">-3.58</span><span class="hljs-number">.0</span>',
    clientId: '&lt;client_id&gt;'
  },
  triggerSource: 'CustomMessage_SignUp',
  request: {
    userAttributes: {
      sub: 'd98dad2a-c2f3<span class="hljs-number">-4</span>f97-bc49-a3ed3c81f27a',
      email_verified: '<span class="hljs-literal">false</span>',
      'cognito:user_status': 'UNCONFIRMED',
      email: '&lt;user_email_address&gt;'
    },
    codeParameter: '{####}',
    linkParameter: '{##Click Here##}',
    usernameParameter: <span class="hljs-literal">null</span>
  },
  response: { smsMessage: <span class="hljs-literal">null</span>, emailMessage: <span class="hljs-literal">null</span>, emailSubject: <span class="hljs-literal">null</span> }
}
</code></pre>
<p>Make sure you include the <code>codeParameter</code> in your custom message.</p>
<h2 id="heading-deployment">Deployment</h2>
<p>To deploy the app, run: <code>sls deploy</code>. If you are deploying to a specific environment, specify it with the <code>--stage</code> option (e.g. <code>sls deploy --stage staging</code> or <code>sls deploy --stage production</code>).</p>
<p>If you'd like to remove the deployed service, run <code>sls remove</code> or <code>sls remove --stage &lt;stage&gt;</code> and the service along with any resources you might have created in this service will be destroyed.</p>
]]></content:encoded></item><item><title><![CDATA[Pre Signup Validation on AWS Cognito]]></title><description><![CDATA[In the last article, we leveraged AWS Cognito to handle user authentication in our application. There was a caveat with the setup, email sharing was allowed.
We want to make sure that we only have one user per email. We could build this logic into th...]]></description><link>https://kelvinmwinuka.com/pre-signup-validation-on-aws-cognito</link><guid isPermaLink="true">https://kelvinmwinuka.com/pre-signup-validation-on-aws-cognito</guid><category><![CDATA[AWS]]></category><category><![CDATA[aws lambda]]></category><category><![CDATA[authentication]]></category><category><![CDATA[serverless]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Fri, 08 Apr 2022 20:27:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649354256168/HUDE7VKO2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the last article, we leveraged AWS Cognito to handle user authentication in our application. There was a caveat with the setup, email sharing was allowed.</p>
<p>We want to make sure that we only have one user per email. We could build this logic into the sign-up handler in our app's backend but there are a couple of reasons why it's not the best practice.</p>
<ol>
<li>The validation will only live in this particular backend. If we create another app that interacts with the same user pool, we will have to repeat this logic there too. </li>
<li>We're adding bloat to the request handler, we could keep this handler clean by avoiding unnecessary code if we can.</li>
</ol>
<p>Enter Cognito user pool triggers. We'll specifically look at the pre-signup trigger. This trigger is executed before Cognito's own signup validation with a couple of notable advantages:</p>
<ol>
<li>We can add custom validation when registering a new user to the user pool. In our case, it's to check if the submitted email is already in use.</li>
<li>The logic is baked into the user pool. Any signup event for this user pool will be validated regardless of where it's coming from.</li>
</ol>
<h2 id="heading-implementation">Implementation</h2>
<h3 id="heading-lambda">Lambda</h3>
<p>Make sure that the lambda is in the same region as the user pool. The following is the lambda's code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { CognitoIdentityProviderClient, ListUsersCommand } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@aws-sdk/client-cognito-identity-provider"</span>);

<span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> (event, context, callback) =&gt; {
    <span class="hljs-comment">// TODO implement</span>
    <span class="hljs-keyword">const</span> params = {
        <span class="hljs-attr">UserPoolId</span>: <span class="hljs-string">'us-west-2_rxOJKcUKc'</span>,
        <span class="hljs-attr">Filter</span>: <span class="hljs-string">`email = "<span class="hljs-subst">${event.request.userAttributes.email}</span>"`</span>
    };

    <span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> CognitoIdentityProviderClient();
    <span class="hljs-keyword">const</span> listUsersCommand = <span class="hljs-keyword">new</span> ListUsersCommand(params);

    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> client.send(listUsersCommand);

    <span class="hljs-keyword">if</span> (data?.Users?.length &gt; <span class="hljs-number">0</span>) {
        callback(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Email is already taken"</span>), event);
    } <span class="hljs-keyword">else</span> {
        callback(<span class="hljs-literal">null</span>, event);
    }

};
</code></pre>
<p>Before we link this lambda to the user pool, we need to make sure it runs properly. In this example, I'm using the JavaScript v3 SDK. If we try to run this, the <code>@aws-sdk/client-cognito-identity-provider</code> module will not be found.</p>
<h3 id="heading-layer">Layer</h3>
<p>This section is only applicable if you're using the v3 SDK at the time of writing this article. If you're not using the v3 SDK, you can skip ahead to the permissions section.</p>
<p>We need to create a lambda layer containing this package so we can use it in the lambda.
Create a new project in your development environment. Navigate to the folder and run <code>npm init</code>.</p>
<p>Complete the setup process and then run <code>npm install @aws-sdk/client-cognito-identity-provider</code> to install the package.</p>
<p>Open the package.json file and add the following line to the <code>scripts</code> section:</p>
<pre><code class="lang-json">{
  ...
  <span class="hljs-attr">"scripts"</span>: {
    ...
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"rm -rf nodejs &amp;&amp; rm cognito-base-layer.zip &amp;&amp; npm install &amp;&amp; mkdir nodejs &amp;&amp; mv node_modules nodejs &amp;&amp; zip -r cognito-base-layer.zip . &amp;&amp; cp cognito-base-layer.zip ~/Downloads"</span>
  },
  ...
}
</code></pre>
<p>This is the build script for the layer. It does the following:</p>
<ol>
<li>Delete the previous nodejs directory and cognito-base-layer.zip file from the previous build.</li>
<li>Install the packages.</li>
<li>Create a directory called <code>nodejs</code>.</li>
<li>Move the <code>node_modules</code> folder into <code>nodejs</code>.</li>
<li>Zip the current directory into a zip file called <code>cognito-base-layer.zip</code>.</li>
<li>Copy the zip file to the desired location (Optional).</li>
</ol>
<p>If you're wondering why we move the node_modules to a subfolder, this is where the lambda will look for the installed packages. If you only have node_modules at the root, your packages will not be found.</p>
<p>When you're ready, run <code>npm run build</code>. A new zip file will be created. Now that we have the zip file, let's create a layer:</p>
<p>Go to the lambda service and click on <code>Layers</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649439986758/qjvSi25qy.png" alt="Screenshot 2022-04-08 at 20.39.39.png" /></p>
<p>Click on "Create layer"</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649440050510/rsTDlhAXL.png" alt="Screenshot 2022-04-08 at 20.40.04.png" /></p>
<p>Fill in the layer details:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649440168424/sJ2qSbvjT.png" alt="Screenshot 2022-04-08 at 20.41.24.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649440194310/jofk4cvfJ.png" alt="Screenshot 2022-04-08 at 20.41.36.png" /></p>
<p>Name the layer whatever you like. In the upload section, upload the zip file that was generated in the previous build.</p>
<p>In the "compatible architectures" section, make sure to select the same architecture that your lambda is based on. In my case, it's x86_64.</p>
<p>When you're done click "Create".</p>
<p>Let's add this layer to the lambda to allow it to make use of the package(s) in the layer.</p>
<p>Navigate to the lambda function and click on <code>Layers</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649440744435/cqAVXOsnK.png" alt="Screenshot 2022-04-08 at 20.54.19.png" /></p>
<p>Click on <code>Add a layer</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649440803296/yHSHEdPjr.png" alt="Screenshot 2022-04-08 at 20.54.51.png" /></p>
<p>Fill in the layer details:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649440865215/WWm6eRLR4.png" alt="Screenshot 2022-04-08 at 20.55.41.png" /></p>
<p>For the layer source, select <code>Custom layers</code>. In the custom layers dropdown menu, select the layer you just created. Once selected, you'll have the option to select a layer version.</p>
<p>Every time you make another upload on a layer, a new version is created and the old version is kept. This is to prevent breaking lambda functions that depend on the current version as each lambda has to specify which layer version they depend on.</p>
<p>Once you're done, click "Add".</p>
<p>That's it on layers, now our lambda can make use of the AWS JavaScript v3 SDK.</p>
<h3 id="heading-permissions">Permissions</h3>
<p>We're not done yet. This lambda currently doesn't have the correct permissions to list users from a Cognito user pool. Let's grant the correct permissions to the lambda function. First, take note of the lambda function's role.</p>
<p>You can find this in the <code>Configuration</code> tab of the lambda function:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649441943542/7Zs8k24YA.png" alt="Screenshot 2022-04-08 at 21.16.33.png" /></p>
<p>Navigate to the IAM Management Console and click on the <code>Policies</code> tab:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649444372271/-KzOPnnmc.png" alt="Screenshot 2022-04-08 at 21.44.38.png" /></p>
<p>Click on "Create Policy":</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649444419180/QRA6qxOns.png" alt="Screenshot 2022-04-08 at 21.45.31.png" /></p>
<p>Click on the JSON tab and you should see a template like this:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: []
}
</code></pre>
<p>In the statement array add the following code:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
    <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"cognito-idp:ListUsers"</span>,
    <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:cognito-idp:&lt;region&gt;:&lt;account_id&gt;:userpool/&lt;userpool_id&gt;"</span>
}
</code></pre>
<p>The above policy statement allows us to list users from the specified Cognito user pool. Replace the <code>Resource</code> value with your user pool's ARN.</p>
<p>Now let's attach this policy to the lambda's role in order to allow the lambda to make use of it.</p>
<p>Navigate to "Roles" in the IAM Management Console:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649445852126/fzCTkthtO.png" alt="Screenshot 2022-04-08 at 22.18.40.png" /></p>
<p>Search for the lambda's role and click on it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649445892015/jnOf2WML4.png" alt="Screenshot 2022-04-08 at 22.19.16.png" /></p>
<p>Click on the "Add permissions" dropdown and then click on "Attach policies":</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649445987267/l40guZRiU.png" alt="Screenshot 2022-04-08 at 22.19.39.png" /></p>
<p>Search for the policy you just created, click on the check box and then click on "Attach policies" at the bottom of the page.</p>
<p>Now we have the right permissions and layers to execute this lambda. All we need to do now is set the lambda as a pre signup trigger for the user pool.</p>
<h3 id="heading-triggers">Triggers</h3>
<p>Navigate to the user pool's console and click on the "Triggers" tab:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649446730895/nTmopAn1p.png" alt="Screenshot 2022-04-08 at 22.33.00.png" /></p>
<p>Click on the Pre sign-up dropdown and select the lambda function we created:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649446847971/RcW2rHt81.png" alt="Screenshot 2022-04-08 at 22.33.34.png" /></p>
<p>Click on "Save changes" at the bottom of the page.</p>
<h2 id="heading-result">Result</h2>
<p>That's all there is to the setup for our use case. Now we can go ahead and try to sign up with an email address that is already used in the user pool. Doing so should return an error that looks like this:</p>
<pre><code><span class="hljs-attribute">UserLambdaValidationException</span>: PreSignUp failed with error Email is already taken.
...
{
    <span class="hljs-string">'$fault'</span>: <span class="hljs-string">'client'</span>,
    <span class="hljs-string">'$metadata'</span>: {
        <span class="hljs-attribute">httpStatusCode</span>: <span class="hljs-number">400</span>,
        <span class="hljs-attribute">requestId</span>: <span class="hljs-string">'3bc8f968-cbf5-4960-857f-e48daa312870'</span>,
        <span class="hljs-attribute">extendedRequestId</span>: undefined,
        <span class="hljs-attribute">cfId</span>: undefined,
        <span class="hljs-attribute">attempts</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attribute">totalRetryDelay</span>: <span class="hljs-number">0</span>
  },
  <span class="hljs-attribute">__type</span>: <span class="hljs-string">'UserLambdaValidationException'</span>
}
</code></pre><h2 id="heading-bonus">Bonus</h2>
<p>You can do more with a pre sign-up trigger. The <code>event</code> object passed to the lambda function has a <code>response</code> property with the following structure:</p>
<p>"response": {
    "autoConfirmUser": "boolean",
    "autoVerifyPhone": "boolean"
    "autoVerifyEmail": "boolean"
}</p>
<p>These all default to <code>false</code>. They can be set to <code>true</code> if you'd like to skip some parts of the default sign up flow. Before invoking the callback, you can add the following statements:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Automatically set user's account status to CONFIRMED</span>
event.response.autoConfirmUser = <span class="hljs-literal">true</span>

<span class="hljs-comment">// Automatically set phone number as verified</span>
event.response.autoVerifyPhone = <span class="hljs-literal">true</span>

<span class="hljs-comment">// Automatically set email as verified</span>
event.response.autoVerifyEmail = <span class="hljs-literal">true</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Basic Authentication with AWS Cognito & NextJS]]></title><description><![CDATA[I’ve written quite a few articles about authentication before. This is yet another user auth article.
However, this time it’s a little different. Previous articles have been about managing user authentication yourself. In this article, we will be lev...]]></description><link>https://kelvinmwinuka.com/basic-authentication-with-aws-cognito-and-nextjs</link><guid isPermaLink="true">https://kelvinmwinuka.com/basic-authentication-with-aws-cognito-and-nextjs</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[code]]></category><category><![CDATA[software development]]></category><category><![CDATA[webdevelopment]]></category><category><![CDATA[AWS]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Cognito]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Mon, 04 Apr 2022 15:36:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649196696269/UMNFUK5pK.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I’ve written quite a few articles about authentication before. This is yet another user auth article.</p>
<p>However, this time it’s a little different. Previous articles have been about managing user authentication yourself. In this article, we will be leveraging AWS Cognito and its user pools for the same functionality.</p>
<p>You can check out some of my previous articles on handling user auth manually here:</p>
<ol>
<li><a target="_blank" href="https://kelvinmwinuka.com/how-to-create-registration-authentication-with-express-passportjs/#more-918">How to Create Registration &amp; Authentication with Express &amp; PassportJS</a>.</li>
<li><a target="_blank" href="https://kelvinmwinuka.com/how-to-handle-password-reset-in-expressjs/">How to Handle Password Reset in ExpressJS</a>.</li>
<li><a target="_blank" href="https://kelvinmwinuka.com/how-to-verify-users-in-expressjs/">How to Verify Users in ExpressJS</a></li>
</ol>
<h2 id="heading-setup">Setup</h2>
<p>This article assumes that you have an AWS Cognito user pool set up and that you have some NextJS boilerplate code set up as well. I will write another article explaining how to set up a Cognito user pool using the AWS console.</p>
<p>First, let’s understand the project structure.</p>
<pre><code>.
├── components
│   ├── layouts
│   │   └── InputLayout.js
│   ├── AuthLinkText.js
│   ├── InputField.js
│   ├── InputHelperText.js
│   ├── Label.js
│   └── SubmitButton.js
├── hooks
│   ├── useAuth.js
│   ├── useRegister.js
│   └── useValidationSchema.js
├── pages
│   ├── api
│   │   ├── confirm
│   │   │   ├── index.js
│   │   │   └── send.js
│   │   ├── password
│   │   │   ├── reset.js
│   │   │   └── reset\_code.js
│   │   ├── login.js
│   │   └── register.js
│   ├── password
│   │   ├── reset.js
│   │   └── reset\_code.js
│   ├── \_app.js
│   ├── confirm.js
│   ├── index.js
│   ├── login.js
│   └── register.js
├── <span class="hljs-keyword">public</span>
│   ├── favicon.ico
│   └── vercel.svg
├── styles
│   ├── Home.module.css
│   └── globals.css
├── README.md
├── next.config.js
├── package<span class="hljs-operator">-</span>lock.json
└── package.json
</code></pre><p>Most of these are nothing special as they’re created automatically when you set up a NextJS project.</p>
<p>The “components” folder contains all the re-usable custom components like form input fields and layouts.</p>
<p>For this article, I will focus on the “hooks” and “pages” folders. If you’d like to look at the full code, you can find it on <a target="_blank" href="https://github.com/kelvinmwinuka/cognito-next">Github</a>.</p>
<p>The “hooks” folder has 3 files:</p>
<ol>
<li>useAuth.js contains a hook that will handle user sign in and password reset.</li>
<li>useRegister.js contains a hook that will handle user registration and verification.</li>
<li>useValidationSchema.js contains the form validation schemas. We won’t be covering this in the article. Feel free to check the repo out for more details on this.</li>
</ol>
<p>I prefer to use hooks because they allow me to separate the business logic from the UI logic in the component.</p>
<p>The “pages” folder has an “API” sub-directory. This is where all the backend code lives.</p>
<p>NextJS uses file-system based routing so the file structure is what determines the API endpoints.</p>
<p>All the other files and sub-directories outside the API sub-directory will be treated as frontend pages.</p>
<p>Make sure to install the <a target="_blank" href="https://www.npmjs.com/package/@aws-sdk/client-cognito-identity-provider">@aws-sdk/client-cognito-identity-provider</a> package.</p>
<p>You can refer to the full <a target="_blank" href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-cognito-identity-provider/index.html#aws-sdkclient-cognito-identity-provider">CognitoIdentityServiceProvider SDK</a> for more in-depth explanations of what is discussed in this article.</p>
<h2 id="heading-sign-up">Sign Up</h2>
<p>First, let’s handle user registration. Navigate to the “pages/api/register.js” and add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { CognitoIdentityProviderClient, SignUpCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-sdk/client-cognito-identity-provider'</span>

<span class="hljs-keyword">const</span> { COGNITO_REGION, COGNITO_APP_CLIENT_ID } = process.env

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
    <span class="hljs-keyword">if</span> (req.method !== <span class="hljs-string">'POST'</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">405</span>).send()

    <span class="hljs-keyword">const</span> params = {
        <span class="hljs-attr">ClientId</span>: COGNITO_APP_CLIENT_ID,
        <span class="hljs-attr">Password</span>: req.body.password,
        <span class="hljs-attr">Username</span>: req.body.username,
        <span class="hljs-attr">UserAttributes</span>: [
            {
                <span class="hljs-attr">Name</span>: <span class="hljs-string">'email'</span>,
                <span class="hljs-attr">Value</span>: req.body.email
            }
        ]
    }

    <span class="hljs-keyword">const</span> cognitoClient = <span class="hljs-keyword">new</span> CognitoIdentityProviderClient({
        <span class="hljs-attr">region</span>: COGNITO\_REGION
    })
    <span class="hljs-keyword">const</span> signUpCommand = <span class="hljs-keyword">new</span> SignUpCommand(params)

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> cognitoClient.send(signUpCommand)
        <span class="hljs-keyword">return</span> res.status(response[<span class="hljs-string">'$metadata'</span>].httpStatusCode).send()
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(err)
        <span class="hljs-keyword">return</span> res.status(err[<span class="hljs-string">'$metadata'</span>].httpStatusCode).json({ <span class="hljs-attr">message</span>: err.toString() })
    }
}
</code></pre>
<p>This is a handler for the “/api/register” endpoint. Include a guard clause to make sure only POST requests are allowed, return a 405 error for any other type of request.</p>
<p>In the params, we have the following:</p>
<ol>
<li>ClientId – App client Id that you created for this user pool in the AWS console.</li>
<li>Password – The user’s chosen password.</li>
<li>Username -The user’s chosen username.</li>
<li>UserAttributes – Any additional attributes provided by the user upon signing up. The default list of attributes includes address, nickname, birthdate, phone number, email, family name, preferred username, gender, profile, given name, zoneinfo, locale, updated at, middle name, website and name. You can add custom attributes as well (for example, “Department” if you’re creating an auth system for an organisation).  </li>
</ol>
<p>Keep in mind that if you’re setting a custom user attribute you need to follow the following format:</p>
<pre><code>{
    <span class="hljs-attribute">Name</span>: <span class="hljs-string">'custom:&lt;AttributeName&gt;'</span>,                
    Value: <span class="hljs-string">'&lt;AttributeValue&gt;'</span>
}
</code></pre><p>In the case of adding a department attribute, it would look like this:</p>
<pre><code>{
    <span class="hljs-attribute">Name</span>: <span class="hljs-string">'custom:Department'</span>,                
    Value: <span class="hljs-string">'Engineering'</span>
}
</code></pre><p>Then we send the SignUpCommand to trigger a user sign up. Return a status 200 response if all goes well, otherwise, return the error code from Cognito and the stringified version of the error.</p>
<p>Cognito will usually return an error that looks like this:</p>
<pre><code><span class="hljs-attribute">UsernameExistsException</span>: User already exists
...
{
  <span class="hljs-string">'$fault'</span>: <span class="hljs-string">'client'</span>,
  <span class="hljs-string">'$metadata'</span>: {
    <span class="hljs-attribute">httpStatusCode</span>: <span class="hljs-number">400</span>,
    <span class="hljs-attribute">requestId</span>: <span class="hljs-string">'9442223e-ef29-40c1-880e-6689638d8042'</span>,
    <span class="hljs-attribute">extendedRequestId</span>: undefined,
    <span class="hljs-attribute">cfId</span>: undefined,
    <span class="hljs-attribute">attempts</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attribute">totalRetryDelay</span>: <span class="hljs-number">0</span>
  },
  <span class="hljs-attribute">__type</span>: <span class="hljs-string">'UsernameExistsException'</span>
}
</code></pre><p>Grab the status code and message and then forward them to the front end.</p>
<p>When the request is successful, Cognito will return a response that looks like this:</p>
<pre><code>{
  <span class="hljs-string">'$metadata'</span><span class="hljs-string">:</span> {
    <span class="hljs-attr">httpStatusCode:</span> <span class="hljs-number">200</span>,
    <span class="hljs-attr">requestId:</span> <span class="hljs-string">'67f6d99c-d13c-4677-ab46-957d88f62bb9'</span>,
    <span class="hljs-attr">extendedRequestId:</span> <span class="hljs-string">undefined</span>,
    <span class="hljs-attr">cfId:</span> <span class="hljs-string">undefined</span>,
    <span class="hljs-attr">attempts:</span> <span class="hljs-number">1</span>,
    <span class="hljs-attr">totalRetryDelay:</span> <span class="hljs-number">0</span>
  },
  <span class="hljs-attr">AuthenticationResult:</span> {
    <span class="hljs-attr">AccessToken:</span> <span class="hljs-string">"..."</span>,
    <span class="hljs-attr">ExpiresIn:</span> <span class="hljs-number">3600</span>,
    <span class="hljs-attr">NewDeviceMetadata:</span> <span class="hljs-string">undefined</span>,
    <span class="hljs-attr">RefreshToken:</span> <span class="hljs-string">"..."</span>,
    <span class="hljs-attr">TokenType:</span> <span class="hljs-string">"Bearer"</span>
  },
  <span class="hljs-attr">ChallengeName:</span> <span class="hljs-string">undefined</span>,
  <span class="hljs-attr">ChallengeParameters:</span> {},
  <span class="hljs-attr">Session:</span> <span class="hljs-string">undefined</span>
}
</code></pre><p>For this application, we’re only interested in the Authentication result as it contains the access and refresh tokens.</p>
<p>Flesh out the useRegister hook in order to make use of the API endpoint we created above.</p>
<p>Create a method called “register” with the following logic:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/router'</span>

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

    <span class="hljs-keyword">const</span> router = useRouter()

    <span class="hljs-keyword">const</span> register = <span class="hljs-function">(<span class="hljs-params">values, { setSubmitting }</span>) =&gt;</span> {
        fetch(<span class="hljs-string">'/api/register'</span>, {
            <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
            <span class="hljs-attr">headers</span>: {
                <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
            },
            <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(values)
        }).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (!res.ok) <span class="hljs-keyword">throw</span> res
            router.push({
                <span class="hljs-attr">pathname</span>: <span class="hljs-string">'/confirm'</span>,
                <span class="hljs-attr">query</span>: { <span class="hljs-attr">username</span>: values?.username }
            },
                <span class="hljs-string">"/confirm"</span>)
        }).catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
            <span class="hljs-built_in">console</span>.error(err)
        }).finally(<span class="hljs-function">() =&gt;</span> {
            setSubmitting(<span class="hljs-literal">false</span>)
        })
    }

    <span class="hljs-keyword">const</span> confirm = <span class="hljs-function">(<span class="hljs-params">values, { setSubmitting }</span>) =&gt;</span> {
        <span class="hljs-comment">// Confirm the user</span>
    }

    <span class="hljs-keyword">return</span> {
        register,
        confirm
    }
}
</code></pre>
<p>The register method is the submit method for our registration form. The “values” object contains the form data and “setSubmitting” allows us to update the loading state once we’re done processing the request.</p>
<p>This will be a common theme with most of the hooks in this project.</p>
<p>Set the Content-Type header to “application/json” to help NextJS parse the request body.</p>
<p>In this method, we call the register endpoint and pass all the form values (which include username, email, and password). If the request is successful, we redirect to the confirm page and prompt the user to verify their email address. More on this in the <a class="post-section-overview" href="#verification">verification</a> section.</p>
<p>You might notice we have an empty confirm method here. This method will handle the request to verify the user. We will cover this in the verification stage as well.</p>
<p>Here is what the registration form will look like, notice we import the useRegister hook and pass the register method as the form submit handler.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Formik } <span class="hljs-keyword">from</span> <span class="hljs-string">"formik"</span>;
<span class="hljs-keyword">import</span> InputLayout <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/layouts/InputLayout"</span>;
<span class="hljs-keyword">import</span> Label <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Label"</span>;
<span class="hljs-keyword">import</span> InputField <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/InputField"</span>;
<span class="hljs-keyword">import</span> InputHelperText <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/InputHelperText"</span>;
<span class="hljs-keyword">import</span> AuthLinkText <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/AuthLinkText"</span>;
<span class="hljs-keyword">import</span> SubmitButton <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/SubmitButton"</span>;
<span class="hljs-keyword">import</span> useValidationSchema <span class="hljs-keyword">from</span> <span class="hljs-string">"../hooks/useValidationSchema"</span>;
<span class="hljs-keyword">import</span> useRegister <span class="hljs-keyword">from</span> <span class="hljs-string">'../hooks/useRegister'</span>
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;

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

    <span class="hljs-keyword">const</span> { registerSchema } = useValidationSchema()
    <span class="hljs-keyword">const</span> { register } = useRegister()

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
            <span class="hljs-attr">padding:</span> "<span class="hljs-attr">10px</span>"
        }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Formik</span>
                <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{{</span>
                    <span class="hljs-attr">username:</span> "",
                    <span class="hljs-attr">email:</span> "",
                    <span class="hljs-attr">password:</span> "",
                    <span class="hljs-attr">confirm_password:</span> ""
                }}
                <span class="hljs-attr">validationSchema</span>=<span class="hljs-string">{registerSchema}</span>
                <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{register}</span>
                <span class="hljs-attr">validateOnMount</span>=<span class="hljs-string">{false}</span>
                <span class="hljs-attr">validateOnChange</span>=<span class="hljs-string">{false}</span>
                <span class="hljs-attr">validateOnBlur</span>=<span class="hljs-string">{false}</span>&gt;</span>
                {({
                    isSubmitting,
                    errors,
                    values,
                    handleSubmit,
                    handleChange,
                    handleBlur
                }) =&gt; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>Username<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                                <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span>
                                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Username"</span>
                                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                                <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                                <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.username}</span>
                            /&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.username}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                                <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
                                <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
                                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Email"</span>
                                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                                <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                                <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.email}</span>
                            /&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.email}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                                <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
                                <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
                                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Password"</span>
                                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                                <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                                <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.password}</span>
                            /&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.password}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>Confirm password<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                                <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
                                <span class="hljs-attr">name</span>=<span class="hljs-string">"confirm_password"</span>
                                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Confirm password"</span>
                                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                                <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                                <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.confirm_password}</span>
                            /&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.confirm_password}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">AuthLinkText</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/login"</span>&gt;</span>Already have an account? Log in<span class="hljs-tag">&lt;/<span class="hljs-name">AuthLinkText</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">SubmitButton</span> <span class="hljs-attr">isSubmitting</span>=<span class="hljs-string">{isSubmitting}</span> /&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
                )}
            <span class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre>
<h2 id="heading-sign-in">Sign In</h2>
<p>Now that we’ve registered our users, it’s time to allow them to log into our application by authenticating them against our Cognito user pool.</p>
<p>Add the following code to the “pages/api/login.js” file.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { CognitoIdentityProviderClient, AdminInitiateAuthCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-cognito-identity-provider"</span>

<span class="hljs-keyword">const</span> { COGNITO_REGION, COGNITO_APP_CLIENT_ID, COGNITO_USER_POOL_ID } = process.env

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
    <span class="hljs-keyword">if</span> (req.method !== <span class="hljs-string">'POST'</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">405</span>).send()

    <span class="hljs-keyword">const</span> params = {
        <span class="hljs-attr">AuthFlow</span>: <span class="hljs-string">'ADMIN_USER_PASSWORD_AUTH'</span>,
        <span class="hljs-attr">ClientId</span>: COGNITO_APP_CLIENT_ID,
        <span class="hljs-attr">UserPoolId</span>: COGNITO_USER_POOL_ID,
        <span class="hljs-attr">AuthParameters</span>: {
            <span class="hljs-attr">USERNAME</span>: req.body.username,
            <span class="hljs-attr">PASSWORD</span>: req.body.password
        }
    }

    <span class="hljs-keyword">const</span> cognitoClient = <span class="hljs-keyword">new</span> CognitoIdentityProviderClient({
        <span class="hljs-attr">region</span>: COGNITO_REGION
    })
    <span class="hljs-keyword">const</span> adminInitiateAuthCommand = <span class="hljs-keyword">new</span> AdminInitiateAuthCommand(params)

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> cognitoClient.send(adminInitiateAuthCommand)
        <span class="hljs-built_in">console</span>.log(response)
        <span class="hljs-keyword">return</span> res.status(response[<span class="hljs-string">'$metadata'</span>].httpStatusCode).json({
            ...response.AuthenticationResult
        })
    } <span class="hljs-keyword">catch</span>(err) {
        <span class="hljs-built_in">console</span>.log(err)
        <span class="hljs-keyword">return</span> res.status(err[<span class="hljs-string">'$metadata'</span>].httpStatusCode).json({ <span class="hljs-attr">message</span>: err.toString() })
    }
}
</code></pre>
<p>At the moment, we’re handling only username/password auth. To do this we need to use the <code>ADMIN_USER_PASSWORD_AUTH</code> flow. This authentication flow requires developer credentials. If you're authenticating users in a secure server, this is the recommended method over <code>InitiateAuthCommand</code> with <code>USER_PASSWORD_AUTH</code>.</p>
<p>The final parameter is AuthParameters. This simply contains the username and password passed to the endpoint upon form submission. Be careful here and make sure the auth parameters are in all uppercase as you see here, otherwise, they will not be recognised.</p>
<p>Now let’s divert our attention to the “useAuth” hook. Add this code to the “hooks/useAuth.js” file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;

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

  <span class="hljs-keyword">const</span> router = useRouter()

  <span class="hljs-keyword">const</span> login = <span class="hljs-function">(<span class="hljs-params">values, { setSubmitting }</span>) =&gt;</span> {
    fetch(<span class="hljs-string">'/api/login'</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(values)
    }).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
      <span class="hljs-keyword">if</span> (!res.ok) <span class="hljs-keyword">throw</span> res
    }).then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(data)
    }).catch(<span class="hljs-keyword">async</span> err =&gt; {
      <span class="hljs-keyword">const</span> responseData = <span class="hljs-keyword">await</span> err.json()
      <span class="hljs-keyword">if</span> (responseData?.message?.includes(<span class="hljs-string">"UserNotConfirmedException:"</span>)) {
        <span class="hljs-comment">// Trigger confirmation code email</span>
        <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/confirm/send'</span>, {
          <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
          <span class="hljs-attr">headers</span>: {
            <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
          },
          <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">username</span>: values.username })
        })
        <span class="hljs-keyword">await</span> router.push(
      {
            <span class="hljs-attr">pathname</span>: <span class="hljs-string">"/confirm"</span>,
            <span class="hljs-attr">query</span>: {<span class="hljs-attr">username</span>: values.username},
          },
          <span class="hljs-string">"/confirm"</span>)
      }
    }).finally(<span class="hljs-function">() =&gt;</span> {
      setSubmitting(<span class="hljs-literal">false</span>)
    })
  }

  <span class="hljs-keyword">const</span> resetPasswordRequest = <span class="hljs-function">(<span class="hljs-params">values, { setSubmitting }</span>) =&gt;</span> {
    <span class="hljs-comment">// Send the password reset code</span>
  }

  <span class="hljs-keyword">const</span> resetPassword = <span class="hljs-function">(<span class="hljs-params">values, { setSubmitting }</span>) =&gt;</span> {
    <span class="hljs-comment">// Send request to reset password</span>
  }

  <span class="hljs-keyword">return</span> {
    login,
    resetPasswordRequest,
    resetPassword
  }
}
</code></pre>
<p>Here we have a login method that is similar to the register method we created above. The “values” object represents our form data (username and password).</p>
<p>It’s important to note that Cognito will not allow a user to be authenticated if they have not yet been verified/confirmed. So attempting this login with an unconfirmed user will return an error.</p>
<p>To handle this, trigger an endpoint to send a confirmation email to the user and then redirect them to the confirm page so they can be verified. More on this endpoint in the <a class="post-section-overview" href="#verification">verification</a> section.</p>
<p>Our login page has the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Formik } <span class="hljs-keyword">from</span> <span class="hljs-string">"formik"</span>;
<span class="hljs-keyword">import</span> InputLayout <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/layouts/InputLayout"</span>;
<span class="hljs-keyword">import</span> Label <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Label"</span>;
<span class="hljs-keyword">import</span> InputField <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/InputField"</span>;
<span class="hljs-keyword">import</span> InputHelperText <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/InputHelperText"</span>;
<span class="hljs-keyword">import</span> AuthLinkText <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/AuthLinkText"</span>;
<span class="hljs-keyword">import</span> SubmitButton <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/SubmitButton"</span>;
<span class="hljs-keyword">import</span> useAuth <span class="hljs-keyword">from</span> <span class="hljs-string">"../hooks/useAuth"</span>;
<span class="hljs-keyword">import</span> useValidationSchema <span class="hljs-keyword">from</span> <span class="hljs-string">"../hooks/useValidationSchema"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;

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

  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> { success } = router.query;

  <span class="hljs-keyword">const</span> { loginSchema } = useValidationSchema();
  <span class="hljs-keyword">const</span> { login } = useAuth();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
      <span class="hljs-attr">padding:</span> "<span class="hljs-attr">10px</span>"
    }}&gt;</span>
      {
        success === "true" &amp;&amp;
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
          <span class="hljs-attr">paddingTop:</span> "<span class="hljs-attr">10px</span>",
          <span class="hljs-attr">paddingBottom:</span> "<span class="hljs-attr">10px</span>",
          <span class="hljs-attr">color:</span> "<span class="hljs-attr">green</span>"
        }}&gt;</span>
          {'You\\'re signed up!'}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      }
      <span class="hljs-tag">&lt;<span class="hljs-name">Formik</span>
        <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{{</span>
          <span class="hljs-attr">username:</span> "",
          <span class="hljs-attr">password:</span> ""
        }}
        <span class="hljs-attr">validationSchema</span>=<span class="hljs-string">{loginSchema}</span>
        <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{login}</span>
        <span class="hljs-attr">validateOnMount</span>=<span class="hljs-string">{false}</span>
        <span class="hljs-attr">validateOnChange</span>=<span class="hljs-string">{false}</span>
        <span class="hljs-attr">validateOnBlur</span>=<span class="hljs-string">{false}</span>&gt;</span>
        {({
          isSubmitting,
          errors,
          values,
          handleChange,
          handleBlur,
          handleSubmit
        }) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>Username<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Username or email"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.username}</span>
              /&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.username}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Password"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.password}</span>
              /&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.password}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">AuthLinkText</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/password/reset_code"</span>&gt;</span>{'Forgot password?'}<span class="hljs-tag">&lt;/<span class="hljs-name">AuthLinkText</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">AuthLinkText</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/register"</span>&gt;</span>{'Don\\'t have an account? Register.'}<span class="hljs-tag">&lt;/<span class="hljs-name">AuthLinkText</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">SubmitButton</span> <span class="hljs-attr">isSubmitting</span>=<span class="hljs-string">{isSubmitting}</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Just like before, we import the useAuth hook and make use of its login method as the form submission handler.</p>
<p>We will discuss the 2 password reset methods in the useAuth hook in the <a class="post-section-overview" href="#passwordreset">password reset</a> section.</p>
<h2 id="heading-verification">Verification</h2>
<p>So we’ve registered our users, but we cannot authenticate them because they are not verified. Let’s fix that.</p>
<p>A few things to note before we continue:</p>
<ol>
<li>I have set up my user pool to use an email code for verification. This is where AWS will send an email with a code that the user has to enter manually on your app. Other authentication methods include: a clickable verification link and a verification code sent to their phone number. If you are using any of the other verification methods (except verification code to a phone number), then you can go ahead and skip this section.</li>
<li>Cognito will automatically trigger the chosen verification method upon successful registration. Verification can also be triggered via the SDK.</li>
</ol>
<p>In the “pages/api/confirm/index.js” file, add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {
    CognitoIdentityProviderClient,
    ConfirmSignUpCommand
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-cognito-identity-provider"</span>

<span class="hljs-keyword">const</span> { COGNITO_REGION, COGNITO_APP_CLIENT_ID } = process.env

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span> (<span class="hljs-params">req, res</span>) </span>{
    <span class="hljs-keyword">if</span> (req.method !== <span class="hljs-string">'POST'</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">405</span>).send()

    <span class="hljs-keyword">const</span> params = {
        <span class="hljs-attr">ClientId</span>: COGNITO_APP_CLIENT_ID,
        <span class="hljs-attr">ConfirmationCode</span>: req.body.code,
        <span class="hljs-attr">Username</span>: req.body.username
    }

    <span class="hljs-keyword">const</span> cognitoClient = <span class="hljs-keyword">new</span> CognitoIdentityProviderClient({
        <span class="hljs-attr">region</span>: COGNITO_REGION
    })
    <span class="hljs-keyword">const</span> confirmSignUpCommand = <span class="hljs-keyword">new</span> ConfirmSignUpCommand(params)

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> cognitoClient.send(confirmSignUpCommand)
        <span class="hljs-built_in">console</span>.log(response)
        <span class="hljs-keyword">return</span> res.status(response[<span class="hljs-string">'$metadata'</span>].httpStatusCode).send()
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(err)
        <span class="hljs-keyword">return</span> res.status(err[<span class="hljs-string">'$metadata'</span>].httpStatusCode).json({ <span class="hljs-attr">message</span>: err.toString() })
    }
}
</code></pre>
<p>Here create and send <code>confirmSignUpCommand</code> with the following parameters:</p>
<ol>
<li>ClientId.</li>
<li>ConfirmationCode – The code sent to the user’s email/phone by Cognito.</li>
<li>Username – The username of the user you’d like to verify.</li>
</ol>
<p>Note that because this is the index file within the confirm directory, we do not need to specify the filename when calling this endpoint. The endpoint would just be “/api/confirm”</p>
<p>In the same confirm directory, we have a file called “send.js”. This file is responsible for manually triggering the confirmation code email.</p>
<p>Add the following code to this file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {
    CognitoIdentityProviderClient,
    ResendConfirmationCodeCommand
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-cognito-identity-provider"</span>

<span class="hljs-keyword">const</span> { COGNITO_REGION, COGNITO_APP_CLIENT_ID } = process.env

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span> (<span class="hljs-params">req, res</span>) </span>{
    <span class="hljs-keyword">if</span> (req.method !== <span class="hljs-string">'POST'</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">405</span>).send()

    <span class="hljs-keyword">const</span> params = {
        <span class="hljs-attr">ClientId</span>: COGNITO_APP_CLIENT_ID,
        <span class="hljs-attr">Username</span>: req.body.username
    }

    <span class="hljs-keyword">const</span> cognitoClient = <span class="hljs-keyword">new</span> CognitoIdentityProviderClient({
        <span class="hljs-attr">region</span>: COGNITO_REGION
    })
    <span class="hljs-keyword">const</span> resendConfirmationCodeCommand = <span class="hljs-keyword">new</span> ResendConfirmationCodeCommand(params)

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> cognitoClient.send(resendConfirmationCodeCommand)
        <span class="hljs-built_in">console</span>.log(response)
        <span class="hljs-keyword">return</span> res.status(response[<span class="hljs-string">'$metadata'</span>].httpStatusCode).send()
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(err)
        <span class="hljs-keyword">return</span> res.stat(err[<span class="hljs-string">'$metadata'</span>].httpStatusCode).json({ <span class="hljs-attr">message</span>: err.toString() })
    }
}
</code></pre>
<p>Here, simply create and send <code>ResendConfirmationCodeCommand</code> with a params object containing the ClientId and the username of the user you’d like to verify.</p>
<p>Cognito will search for the user with the specified username, then send a verification code to their email/phone number depending on your settings and/or which one is provided.</p>
<p>You might be wondering why this command is called <code>ResendConfirmationCodeCommand</code>.</p>
<p>Cognito will automatically send a verification code to the user upon signing up.</p>
<p>If you are triggering the registration manually, then you are always “re-sending” the code.</p>
<p>Remember that “confirm” method in the useRegister hook? It’s time to flesh it out.</p>
<p>Add the following logic in that method:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> confirm = <span class="hljs-function">(<span class="hljs-params">values, { setSubmitting }</span>) =&gt;</span> {
        fetch(<span class="hljs-string">'/api/confirm'</span>, {
            <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
            <span class="hljs-attr">headers</span>: {
                <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
            },
            <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(values)
        }).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (!res.ok) <span class="hljs-keyword">throw</span> res
            router.push({
                <span class="hljs-attr">pathname</span>: <span class="hljs-string">'/login'</span>,
                <span class="hljs-attr">query</span>: { <span class="hljs-attr">confirmed</span>: <span class="hljs-literal">true</span> }
            },
                <span class="hljs-string">"/login"</span>)
        }).catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
            <span class="hljs-built_in">console</span>.error(err)
        }).finally(<span class="hljs-function">() =&gt;</span> {
            setSubmitting(<span class="hljs-literal">false</span>)
        })
    }
</code></pre>
<p>From this method, call the “/api/confirm” endpoint with the form values. If the confirmation is successful, redirect the user to the login page so they can sign in.</p>
<p>Here’s a look at the confirm page in the “pages/confirm.js” file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Formik } <span class="hljs-keyword">from</span> <span class="hljs-string">"formik"</span>;
<span class="hljs-keyword">import</span> InputLayout <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/layouts/InputLayout"</span>;
<span class="hljs-keyword">import</span> Label <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Label"</span>;
<span class="hljs-keyword">import</span> InputField <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/InputField"</span>;
<span class="hljs-keyword">import</span> InputHelperText <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/InputHelperText"</span>;
<span class="hljs-keyword">import</span> SubmitButton <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/SubmitButton"</span>;
<span class="hljs-keyword">import</span> useValidationSchema <span class="hljs-keyword">from</span> <span class="hljs-string">"../hooks/useValidationSchema"</span>;
<span class="hljs-keyword">import</span> useRegister <span class="hljs-keyword">from</span> <span class="hljs-string">"../hooks/useRegister"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;

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

    <span class="hljs-keyword">const</span> router = useRouter();
    <span class="hljs-keyword">const</span> { username } = router.query;

    <span class="hljs-keyword">const</span> { confirm } = useRegister();
    <span class="hljs-keyword">const</span> { confirmSchema } = useValidationSchema();

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
            <span class="hljs-attr">padding:</span> "<span class="hljs-attr">10px</span>"
        }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Formik</span>
                <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{{</span>
                    <span class="hljs-attr">username:</span> <span class="hljs-attr">username</span>,
                    <span class="hljs-attr">code:</span> ""
                }}
                <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{confirm}</span>
                <span class="hljs-attr">validationSchema</span>=<span class="hljs-string">{confirmSchema}</span>
                <span class="hljs-attr">validateOnMount</span>=<span class="hljs-string">{false}</span>
                <span class="hljs-attr">validateOnChange</span>=<span class="hljs-string">{false}</span>
                <span class="hljs-attr">validateOnBlur</span>=<span class="hljs-string">{false}</span>&gt;</span>
                {
                    ({
                        isSubmitting,
                        errors,
                        values,
                        handleSubmit,
                        handleChange,
                        handleBlur
                     }) =&gt; (
                        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>Confirmation Code<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                                    <span class="hljs-attr">type</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">text</span>"}
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">code</span>"}
                                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">Code</span>"}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                                    <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                                    <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.code}</span>
                                /&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.code}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">SubmitButton</span> <span class="hljs-attr">isSubmitting</span>=<span class="hljs-string">{isSubmitting}</span> /&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
                    )
                }
            <span class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre>
<h2 id="heading-password-reset">Password reset</h2>
<p>One of the most important features in any auth system is the ability to reset passwords.</p>
<p>Fortunately, password reset is made dead simple by Cognito.</p>
<p>The password reset flow is similar to the verification flow but with some extra steps:</p>
<ol>
<li>The user clicks the “Forgot password” link and is redirected to a page where they are prompted to enter their username.</li>
<li>Send a confirmation code to the user’s email/number.</li>
<li>If the code is sent successfully, redirect the user to a reset page where they enter the code, along with their new password.</li>
</ol>
<p>First, prepare the endpoint to trigger the verification email containing the code.</p>
<p>Add the following code to “pages/api/password/reset_code.js”:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { CognitoIdentityProviderClient, ForgotPasswordCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-sdk/client-cognito-identity-provider'</span>

<span class="hljs-keyword">const</span> { COGNITO_REGION, COGNITO_APP_CLIENT_ID } = process.env

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span> (<span class="hljs-params">req, res</span>) </span>{
    <span class="hljs-keyword">if</span> (req.method !== <span class="hljs-string">'POST'</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">405</span>).send()

    <span class="hljs-keyword">const</span> params = {
        <span class="hljs-attr">ClientId</span>: COGNITO_APP_CLIENT_ID,
        <span class="hljs-attr">Username</span>: req.body.username
    }

    <span class="hljs-keyword">const</span> cognitoClient = <span class="hljs-keyword">new</span> CognitoIdentityProviderClient({
        <span class="hljs-attr">region</span>: COGNITO_REGION
    })
    <span class="hljs-keyword">const</span> forgotPasswordCommand = <span class="hljs-keyword">new</span> ForgotPasswordCommand(params)

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> cognitoClient.send(forgotPasswordCommand)
        <span class="hljs-built_in">console</span>.log(response)
        <span class="hljs-keyword">return</span> res.status(response[<span class="hljs-string">'$metadata'</span>].httpStatusCode).send()
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(err)
        <span class="hljs-keyword">return</span> res.status(err[<span class="hljs-string">'$metadata'</span>].httpStatusCode).json({ <span class="hljs-attr">message</span>: toString() })
    }
}
</code></pre>
<p>Here we accept the ClientId and username params for the “ForgotPasswordCommand” command. Cognito will find a user with the matching username and send them a verification code using the configured method.</p>
<p>In the “pages/api/password/reset.js” file, add the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {
    CognitoIdentityProviderClient,
    ConfirmForgotPasswordCommand
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-cognito-identity-provider"</span>

<span class="hljs-keyword">const</span> { COGNITO_REGION, COGNITO_APP_CLIENT_ID } = process.env

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
    <span class="hljs-keyword">if</span> (req.method !== <span class="hljs-string">'POST'</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">405</span>).send()

    <span class="hljs-keyword">const</span> params = {
        <span class="hljs-attr">ClientId</span>: COGNITO_APP_CLIENT_ID,
        <span class="hljs-attr">ConfirmationCode</span>: req.body.code,
        <span class="hljs-attr">Password</span>: req.body.password,
        <span class="hljs-attr">Username</span>: req.body.username
    }

    <span class="hljs-keyword">const</span> cognitoClient = <span class="hljs-keyword">new</span> CognitoIdentityProviderClient({
        <span class="hljs-attr">region</span>: COGNITO_REGION
    })
    <span class="hljs-keyword">const</span> confirmForgotPasswordCommand = <span class="hljs-keyword">new</span> ConfirmForgotPasswordCommand(params)

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> cognitoClient.send(confirmForgotPasswordCommand)
        <span class="hljs-built_in">console</span>.log(response)
        <span class="hljs-keyword">return</span> res.status(response[<span class="hljs-string">'$metadata'</span>].httpStatusCode).send()
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(err)
        <span class="hljs-keyword">return</span> res.status(err[<span class="hljs-string">'$metadata'</span>].httpStatusCode).json({ <span class="hljs-attr">message</span>: err.toString() })
    }
}
</code></pre>
<p>Here we accept the ConfirmationCode that was sent to the user, their new password and their username.</p>
<p>Cognito will take care of all the logic of making sure that the code provided is valid and is the one that was sent to the user with the specified username.</p>
<p>You’ll remember that in the useAuth hook, we had 2 empty methods “resetPasswordRequest” and “resetPassword”. We are going to flesh those out now.</p>
<p>Add the following logic to those methods:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> resetPasswordRequest = <span class="hljs-function">(<span class="hljs-params">values, { setSubmitting }</span>) =&gt;</span> {
    fetch(<span class="hljs-string">'/api/password/reset\_code'</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(values)
    }).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
      <span class="hljs-keyword">if</span> (!res.ok) <span class="hljs-keyword">throw</span> res
      router.push({
        <span class="hljs-attr">pathname</span>: <span class="hljs-string">'/password/reset'</span>,
        <span class="hljs-attr">query</span>: { <span class="hljs-attr">username</span>: values.username }
      },
        <span class="hljs-string">"/password/reset"</span>)
    }).catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
      <span class="hljs-built_in">console</span>.error(err)
    }).finally(<span class="hljs-function">() =&gt;</span> {
      setSubmitting(<span class="hljs-literal">false</span>)
    })
  }

  <span class="hljs-keyword">const</span> resetPassword = <span class="hljs-function">(<span class="hljs-params">values, { setSubmitting }</span>) =&gt;</span> {
    fetch(<span class="hljs-string">'/api/password/reset'</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(values)
    }).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
      <span class="hljs-keyword">if</span> (!res.ok) <span class="hljs-keyword">throw</span> res
      router.push({
        <span class="hljs-attr">pathname</span>: <span class="hljs-string">'/login'</span>,
        <span class="hljs-attr">query</span>: { <span class="hljs-attr">reset</span>: <span class="hljs-literal">true</span> }
      },
        <span class="hljs-string">"/login"</span>)
    }).catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
      <span class="hljs-built_in">console</span>.error(err)
    }).finally(<span class="hljs-function">() =&gt;</span> {
      setSubmitting(<span class="hljs-literal">false</span>)
    })
  }
</code></pre>
<p>The <code>resetPasswordRequest</code> method triggers the “/api/password/reset_code” endpoint.</p>
<p>From the user’s perspective, they are redirected to a page where they enter their username. Once they submit the form, they receive an email and are redirected to the password reset page (if the email was successfully sent).</p>
<p>The <code>resetPassword</code> method triggers the “/api/password/reset” endpoint to actually reset the password.</p>
<p>Here’s how the forgot password form looks:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Formik } <span class="hljs-keyword">from</span> <span class="hljs-string">"formik"</span>;
<span class="hljs-keyword">import</span> InputLayout <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/layouts/InputLayout"</span>;
<span class="hljs-keyword">import</span> Label <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/Label"</span>;
<span class="hljs-keyword">import</span> InputField <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/InputField"</span>;
<span class="hljs-keyword">import</span> InputHelperText <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/InputHelperText"</span>;
<span class="hljs-keyword">import</span> SubmitButton <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/SubmitButton"</span>;
<span class="hljs-keyword">import</span> useValidationSchema <span class="hljs-keyword">from</span> <span class="hljs-string">"../../hooks/useValidationSchema"</span>;
<span class="hljs-keyword">import</span> useAuth <span class="hljs-keyword">from</span> <span class="hljs-string">'../../hooks/useAuth'</span>;

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

    <span class="hljs-keyword">const</span> { resetPasswordRequestSchema } = useValidationSchema();
    <span class="hljs-keyword">const</span> { resetPasswordRequest } = useAuth();

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
            <span class="hljs-attr">padding:</span> "<span class="hljs-attr">10px</span>"
        }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Formik</span>
                <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{{</span>
                    <span class="hljs-attr">username:</span> ""
                }}
                <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{resetPasswordRequest}</span>
                <span class="hljs-attr">validationSchema</span>=<span class="hljs-string">{resetPasswordRequestSchema}</span>
                <span class="hljs-attr">validateOnMount</span>=<span class="hljs-string">{false}</span>
                <span class="hljs-attr">validateOnChange</span>=<span class="hljs-string">{false}</span>
                <span class="hljs-attr">validateOnBlur</span>=<span class="hljs-string">{false}</span>
                &gt;</span>
                {
                    ({
                        isSubmitting,
                        errors,
                        values,
                        handleSubmit,
                        handleChange,
                        handleBlur
                    }) =&gt; (
                        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>Username<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                                    <span class="hljs-attr">type</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">text</span>"}
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">username</span>"}
                                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">Username</span>"}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                                    <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                                    <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.username}</span>
                                /&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.username}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">SubmitButton</span> <span class="hljs-attr">isSubmitting</span>=<span class="hljs-string">{isSubmitting}</span> /&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
                    )
                }
            <span class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre>
<p>Here’s how the password reset form looks:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Formik } <span class="hljs-keyword">from</span> <span class="hljs-string">"formik"</span>;
<span class="hljs-keyword">import</span> InputLayout <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/layouts/InputLayout"</span>;
<span class="hljs-keyword">import</span> Label <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/Label"</span>;
<span class="hljs-keyword">import</span> InputField <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/InputField"</span>;
<span class="hljs-keyword">import</span> InputHelperText <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/InputHelperText"</span>;
<span class="hljs-keyword">import</span> SubmitButton <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/SubmitButton"</span>;
<span class="hljs-keyword">import</span> useValidationSchema <span class="hljs-keyword">from</span> <span class="hljs-string">"../../hooks/useValidationSchema"</span>;
<span class="hljs-keyword">import</span> useAuth <span class="hljs-keyword">from</span> <span class="hljs-string">'../../hooks/useAuth'</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;

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

    <span class="hljs-keyword">const</span> router = useRouter()
    <span class="hljs-keyword">const</span> { username } = router.query

    <span class="hljs-keyword">const</span> { resetPasswordSchema } = useValidationSchema();
    <span class="hljs-keyword">const</span> { resetPassword } = useAuth()

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
            <span class="hljs-attr">padding:</span> "<span class="hljs-attr">10px</span>"
        }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Formik</span>
                <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{{</span>
                    <span class="hljs-attr">username:</span> <span class="hljs-attr">username</span>,
                    <span class="hljs-attr">code:</span> "",
                    <span class="hljs-attr">password:</span> "",
                    <span class="hljs-attr">confirm</span>\<span class="hljs-attr">_password:</span> ""
                }}
                <span class="hljs-attr">validationSchema</span>=<span class="hljs-string">{resetPasswordSchema}</span>
                <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{resetPassword}</span>
                <span class="hljs-attr">validateOnMount</span>=<span class="hljs-string">{false}</span>
                <span class="hljs-attr">validateOnChange</span>=<span class="hljs-string">{false}</span>
                <span class="hljs-attr">validateOnBlur</span>=<span class="hljs-string">{false}</span>
            &gt;</span>
                {
                    ({
                        isSubmitting,
                        errors,
                        values,
                        handleSubmit,
                        handleBlur,
                        handleChange
                    }) =&gt; (
                        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>Reset code<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                                    <span class="hljs-attr">type</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">text</span>"}
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">code</span>"}
                                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">Reset</span> <span class="hljs-attr">code</span>"}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                                    <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                                    <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.code}</span>
                                /&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.code}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>New password<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                                    <span class="hljs-attr">type</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">password</span>"}
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">password</span>"}
                                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">New</span> <span class="hljs-attr">password</span>"}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                                    <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                                    <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.password}</span>
                                /&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.password}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">InputLayout</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Label</span>&gt;</span>Confirm password<span class="hljs-tag">&lt;/<span class="hljs-name">Label</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">InputField</span>
                                    <span class="hljs-attr">type</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">password</span>"}
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">confirm_password</span>"}
                                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">Confirm</span> <span class="hljs-attr">password</span>"}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                                    <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleBlur}</span>
                                    <span class="hljs-attr">value</span>=<span class="hljs-string">{values?.confirm_password}</span>
                                /&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">InputHelperText</span> <span class="hljs-attr">isError</span>&gt;</span>{errors?.confirm_password}<span class="hljs-tag">&lt;/<span class="hljs-name">InputHelperText</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">InputLayout</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">SubmitButton</span> <span class="hljs-attr">isSubmitting</span>=<span class="hljs-string">{isSubmitting}</span> /&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
                    )
                }
            <span class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre>
<h2 id="heading-caveat">Caveat</h2>
<p>A major caveat with the implementation we’ve just created is that 2 or more users can actually register with the same email.</p>
<p>We don’t want any user to receive a code for another user’s password reset.</p>
<p>For this and many other reasons, you may want to force unique emails for each user.</p>
<p>We can easily achieve this using Cognito triggers which are event triggers that run custom lambda functions. These allow us to customise our workflows.</p>
<p>We can trigger lambdas during any of the following events (and more):</p>
<ol>
<li>Pre-signup – Right before Cognito signup is triggered.</li>
<li>Pre-authentication – Right before the user is authenticated by Cognito.</li>
<li>Custom message – Right before a verification/confirmation message is sent. We can dynamically edit the message here.</li>
<li>Post-authentication – After the user is successfully authenticated. If the authentication fails, this will not be triggered.</li>
<li>Post-confirmation – After a user is verified/confirmed. You can use this to send a welcome email or enable certain privileges that are only available to confirmed users.</li>
</ol>
<p>These are only a few of the triggers available to us. You can find more information on these triggers <a target="_blank" href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html">here</a>.</p>
<p>In our case, the trigger we’re most interested in is the Pre-signup trigger. We can check if there are any current users who have the same email address as the one we’ve just received for signup. If so, throw an error and fail early before the Cognito signup.</p>
<p>I will publish an article that demonstrates how to achieve this.</p>
]]></content:encoded></item><item><title><![CDATA[Verify Users in ExpressJS]]></title><description><![CDATA[If you’re building an application, you likely want a lot of users on your platform. However, you don’t just want a large number of users, you want real and high-quality users who will interact with your app. You want to verify those users.
It’s commo...]]></description><link>https://kelvinmwinuka.com/verify-users-in-expressjs</link><guid isPermaLink="true">https://kelvinmwinuka.com/verify-users-in-expressjs</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[Express]]></category><category><![CDATA[code]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[MongoDB]]></category><category><![CDATA[mongoose]]></category><category><![CDATA[node]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Wed, 30 Dec 2020 06:29:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649113960389/UrBloH9u5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’re building an application, you likely want a lot of users on your platform. However, you don’t just want a large number of users, you want real and high-quality users who will interact with your app. You want to verify those users.</p>
<p>It’s common for bots or users with fake email addresses and no intention of seriously using your application to register. One way to deal with this at the start is by making sure to verify users.</p>
<p>This article is a tutorial on user verification in ExpressJS and a continuation of my Express web development series. I will be building on top of the concepts discussed in my previous article on <a target="_blank" href="https://kelvinmwinuka.com/how-to-handle-password-reset-in-expressjs/">handling password resets.</a></p>
<p>The setup and required packages are specified in that article but you will be able to see what packages are used in the code examples.</p>
<p>I’d suggest taking a look at the other articles in the series first, although you should be able to follow along with this one regardless. Check out the project on <a target="_blank" href="https://github.com/kelvinmwinuka/express-tutorial">GitHub</a> if you’d like to track it as the series progresses.</p>
<h2 id="heading-models">Models</h2>
<p>Let’s first create the model that holds the verification tokens. Navigate to the models folder and create a file called ‘UserVerification.js’. The file should have the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { Schema, model } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>)

<span class="hljs-keyword">const</span> schema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">user</span> : {
    <span class="hljs-attr">type</span>: Schema.Types.ObjectId,
    <span class="hljs-attr">ref</span>: <span class="hljs-string">'User'</span>,
    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
  },
  <span class="hljs-attr">token</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.String,
    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
  }
}, {
  <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span>
})

schema.index({ <span class="hljs-string">'updatedAt'</span>: <span class="hljs-number">1</span> }, { <span class="hljs-attr">expireAfterSeconds</span>: <span class="hljs-number">300</span> })

<span class="hljs-keyword">const</span> UserVerification = model(<span class="hljs-string">'UserVerification'</span>, schema)

<span class="hljs-built_in">module</span>.exports = UserVerification
</code></pre>
<p>The model schema contains a token that will be included in the verification link, and the user it’s associated with.</p>
<p>Create an index on the ‘updatedAt’ field that instructs MongoDB to delete the record after 5 minutes from the time the record is updated. 5 minutes is reasonable for testing but you’ll want to increase this to something more reasonable in production.</p>
<p>In the user model, add a boolean ‘verified’ property to the schema. Set the default to false as the user would not be verified upon registration.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { Schema, model } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>)

<span class="hljs-keyword">const</span> saltRounds = <span class="hljs-number">10</span>

<span class="hljs-keyword">var</span> userSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">name</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.String,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'You must provide a name'</span>]
  },
  <span class="hljs-attr">email</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.String,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'Email address is required'</span>]
  },
  <span class="hljs-attr">username</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.String,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'Username is required'</span>]
  },
  <span class="hljs-attr">password</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.String,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'You must provide a password'</span>]
  },
  <span class="hljs-attr">verified</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.Boolean,
    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span>
  }
})

...

const User = model(<span class="hljs-string">'User'</span>, userSchema)

<span class="hljs-built_in">module</span>.exports = User
</code></pre>
<h2 id="heading-routes">Routes</h2>
<h3 id="heading-profile-routes">Profile routes</h3>
<p>The first route we have to create is the profile route. This route will simply render a template with the user’s profile details. Create a file in the routes folder named ‘profile.js’ and add a route that renders the ‘profile.html’ template.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> router = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>).Router()

router.get(<span class="hljs-string">'/profile'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (!req.isAuthenticated()) <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'/login'</span>)
  <span class="hljs-keyword">return</span> res.render(<span class="hljs-string">'profile.html'</span>)
})

<span class="hljs-built_in">module</span>.exports = router
</code></pre>
<h3 id="heading-user-verification-routes">User verification routes</h3>
<p>Now let’s create the routes that will handle user verification. In the routes folder, create a file named ‘user-verification.js’. To start with, the file will have the following contents:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> router = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>).Router()
<span class="hljs-keyword">const</span> { v4 } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'uuid'</span>)
<span class="hljs-keyword">const</span> { User, UserVerification } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models'</span>)
<span class="hljs-keyword">const</span> { sendEmail } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../helpers'</span>)

<span class="hljs-comment">/* Create routes here */</span>

<span class="hljs-built_in">module</span>.exports = router
</code></pre>
<p>Import the User and UserVerification models. Import the ‘sendMail’ helper function that we created in the previous article. This is simply a function that uses NodeMailer to send an email using the arguments passed to it.</p>
<p>Now let’s create the routes.</p>
<h4 id="heading-create-verification-url">Create verification url</h4>
<p>The first route is a get route ‘/verify’. This route is responsible for creating the verification URL and has the following contents:</p>
<pre><code class="lang-javascript">router.get(<span class="hljs-string">'/verify'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">if</span> (!req.isAuthenticated()) <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'/login'</span>)
  <span class="hljs-keyword">if</span> (req.user.verified) <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'back'</span>)

  <span class="hljs-keyword">const</span> token = v4().toString().replace(<span class="hljs-regexp">/-/g</span>, <span class="hljs-string">''</span>)
  <span class="hljs-keyword">const</span> verificationUrl = <span class="hljs-string">`<span class="hljs-subst">${process.env.DOMAIN}</span>/verify-confirm/<span class="hljs-subst">${token}</span>`</span>

  <span class="hljs-keyword">await</span> UserVerification.updateOne({ 
    <span class="hljs-attr">user</span>: req.user._id 
  }, {
    <span class="hljs-attr">user</span>: req.user._id,
    <span class="hljs-attr">token</span>: token
  }, {
    <span class="hljs-attr">upsert</span>: <span class="hljs-literal">true</span>
  })

  sendEmail({
    <span class="hljs-attr">to</span>: req.user.email,
    <span class="hljs-attr">subject</span>: <span class="hljs-string">'Verify your email address'</span>,
    <span class="hljs-attr">text</span>: <span class="hljs-string">`Here's your email verification link: <span class="hljs-subst">${verificationUrl}</span>`</span>
  })

  req.flash(<span class="hljs-string">'verify_success'</span>, <span class="hljs-string">'Check your email address for your verification link. It may take a few minutes'</span>)
  res.redirect(<span class="hljs-string">'/profile'</span>)
})
</code></pre>
<p>First, check if the user is authenticated. The user should only be able to request a verification link when they are logged in. If they aren’t, redirect them to the login page.</p>
<p>Check if the user is already verified. We don’t want to send a verification link if the user is already verified. If they are, redirect to the previous page.</p>
<p>Create the token and then the verification URL that contains the token.</p>
<p>Update the UserVerification record associated with the current user. Make sure to set the upsert option to ‘true’. We want to replace the current verification link so that only one can be active at a time, but we also want to create a new one if there isn’t one in the collection.</p>
<p>Send the email containing the user verification link, flash a success message urging the user to check their email address and then redirect to the user’s profile.</p>
<h4 id="heading-verify-user">Verify user</h4>
<p>The second route handles the link sent to the user:</p>
<pre><code class="lang-javascript">router.get(<span class="hljs-string">'/verify-confirm/:token'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">if</span> (!req.isAuthenticated()) <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'/login'</span>)

  <span class="hljs-keyword">const</span> token = req.params.token

  <span class="hljs-keyword">const</span> userVerification = <span class="hljs-keyword">await</span> UserVerification.findOne({
    <span class="hljs-attr">user</span>: req.user._id,
    <span class="hljs-attr">token</span>: token
  })

  <span class="hljs-keyword">if</span> (userVerification) {
    <span class="hljs-keyword">await</span> User.updateOne({ <span class="hljs-attr">_id</span>: req.user._id }, { <span class="hljs-attr">verified</span>: <span class="hljs-literal">true</span> })
    <span class="hljs-keyword">await</span> UserVerification.deleteOne({ 
      <span class="hljs-attr">user</span>: req.user._id,
      <span class="hljs-attr">token</span>: token
    })
    sendEmail({
      <span class="hljs-attr">to</span>: req.user.email,
      <span class="hljs-attr">subject</span>: <span class="hljs-string">'Verified'</span>,
      <span class="hljs-attr">text</span>: <span class="hljs-string">`Congratulations <span class="hljs-subst">${req.user.name}</span>, your account is now verified!`</span>
    })
    req.flash(<span class="hljs-string">'verify_success'</span>, <span class="hljs-string">'Congrats, you are now verified!'</span>)
  } <span class="hljs-keyword">else</span> {
    req.flash(<span class="hljs-string">'verify_error'</span>, <span class="hljs-string">'Verification link is invalid or has expired.'</span>)
  }

  <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'/profile'</span>)
})
</code></pre>
<p>This route expects a token which we will validate later. First check whether the user is logged in, if not, redirect to the login page.</p>
<p>Extract the token from the url and query the UserVerification collection for a document with the current token and the current user.</p>
<p>If the document doesn’t exist, flash an error message stating that the link is invalid or expired.</p>
<p>If the document exists, update the user’s verified status to ‘true’ and delete the current UserVerification document in order to prevent the link from being clicked again (this would be pointless anyway but it’s good practice).</p>
<p>Send the user an email confirming their verification status and then flash a success message stating that the user has now been verified. Redirect to the user’s profile page afterwards.</p>
<h3 id="heading-import-routes">Import routes</h3>
<p>Go into the app’s entry folder and include the profile and user-verification routes with the following code:</p>
<pre><code class="lang-javascript">app.use(<span class="hljs-string">'/'</span>, <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routes/profile'</span>))
app.use(<span class="hljs-string">'/'</span>, <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routes/user-verification'</span>))
</code></pre>
<h2 id="heading-templates">Templates</h2>
<p>There’s one new template that we need to create for this feature: the profile template.</p>
<pre><code>{<span class="hljs-operator">%</span> extends <span class="hljs-string">'base.html'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> set title <span class="hljs-operator">=</span> <span class="hljs-string">'Profile'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> content <span class="hljs-operator">%</span>}
  {<span class="hljs-operator">%</span> <span class="hljs-keyword">if</span> messages.verify_success <span class="hljs-operator">%</span>}
    <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"alert alert-success"</span> role<span class="hljs-operator">=</span><span class="hljs-string">"alert"</span><span class="hljs-operator">&gt;</span>
      {{ messages.verify_success }}
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
  {<span class="hljs-operator">%</span> endif <span class="hljs-operator">%</span>}
  {<span class="hljs-operator">%</span> <span class="hljs-keyword">if</span> messages.verify_error <span class="hljs-operator">%</span>}
    <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"alert alert-danger"</span> role<span class="hljs-operator">=</span><span class="hljs-string">"alert"</span><span class="hljs-operator">&gt;</span>
      {{ messages.verify_error }}
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
  {<span class="hljs-operator">%</span> endif <span class="hljs-operator">%</span>}
  <span class="hljs-operator">&lt;</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>h5<span class="hljs-operator">&gt;</span>Hi, {{ user.<span class="hljs-built_in">name</span> }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>h5<span class="hljs-operator">&gt;</span>
    {<span class="hljs-operator">%</span> <span class="hljs-keyword">if</span> not user.verified <span class="hljs-operator">%</span>}
      Your email <span class="hljs-keyword">is</span> not verified, 
      <span class="hljs-operator">&lt;</span>a class<span class="hljs-operator">=</span><span class="hljs-string">"btn btn-sm btn-warning"</span> href<span class="hljs-operator">=</span><span class="hljs-string">"/verify"</span><span class="hljs-operator">&gt;</span>Verify Email<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>a<span class="hljs-operator">&gt;</span>
    {<span class="hljs-operator">%</span> endif <span class="hljs-operator">%</span>}
  <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> scripts <span class="hljs-operator">%</span>}
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}
</code></pre><p>This template renders the error or success message flashed in the previous request. We have a div that displays the user’s name and a button to generate the verification URL conditionally based on the user’s verified status.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, I demonstrated how to verify users in your Express application. There are many reasons you may want to verify users: You may want to make sure you have active, human users on your app or maybe you want to restrict features that require users to be verified.</p>
<p>Whatever the reason, I hope that this article has provided sufficient guidance on the flow and execution of the verification process.</p>
<p>The next article will be about creating user following and follower relationships using many-to-many relationships in MongoDB.</p>
]]></content:encoded></item><item><title><![CDATA[Handle Password Reset in ExpressJS]]></title><description><![CDATA[No authentication system is complete without a password reset feature. I would personally never ship a product that did not have this feature included. 
It is necessary to provide a way for users to recover access to their accounts/data in case of a ...]]></description><link>https://kelvinmwinuka.com/handle-password-reset-in-expressjs</link><guid isPermaLink="true">https://kelvinmwinuka.com/handle-password-reset-in-expressjs</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[Express]]></category><category><![CDATA[code]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[MongoDB]]></category><category><![CDATA[mongoose]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Thu, 24 Dec 2020 13:05:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649113968872/E6mlPg35ad.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>No authentication system is complete without a password reset feature. I would personally never ship a product that did not have this feature included. </p>
<p>It is necessary to provide a way for users to recover access to their accounts/data in case of a lost or forgotten password. In this article, I will be demonstrating how to handle password resets in ExpressJS.</p>
<p>In the last 2 articles, I wrote about <a target="_blank" href="https://kelvinmwinuka.com/how-to-set-up-mongoose-with-expressjs/">how to connect ExpressJS application to MongoDB database</a> and <a target="_blank" href="https://kelvinmwinuka.com/how-to-create-registration-authentication-with-express-passportjs/">building a user registration and authentication system</a>.</p>
<p>Both of these articles tie into today’s article. We’re going to use mongoose and our saved user data to enable password resets.</p>
<p>If you’ve read those articles, or already have your own authentication system, read on. Even if you’re using a different tech stack, you may still gain some valuable ideas from this approach.</p>
<p>As always, this project is hosted on <a target="_blank" href="https://github.com/kelvinmwinuka/express-tutorial">Github</a>. Feel free to clone the project to get access to the source code I use in this article.</p>
<h2 id="heading-the-password-reset-flow">The password reset flow</h2>
<p>Before we dive into the code, let’s first establish what the password reset flow will look like from the user’s perspective and then design the implementation of this flow.</p>
<h3 id="heading-users-perspective">User’s perspective</h3>
<p>From the user’s perspective, the process should go as follows:</p>
<ol>
<li>Click on the ‘Forgot password’ link on the login page.</li>
<li>Redirected to a page that requires an email address.</li>
<li>Receive the password reset link in an email.</li>
<li>Link redirects to a page that requires a new password and password confirmation.</li>
<li>After submission, redirected to the login page with a success message.</li>
</ol>
<h3 id="heading-reset-system-characteristics">Reset system characteristics</h3>
<p>We also need to understand some characteristics of a good password reset system:</p>
<ol>
<li>Unique password reset link should be generated for the user such that when the user visits the link, they are instantly identified. This means including a unique token in the link.</li>
<li>Password reset link should have an expiry time (e.g. 2 hours) after which it is no longer valid and cannot be used to reset the password.</li>
<li>The reset link should expire once the password has been reset to prevent the same link from being used to reset the password several times.</li>
<li>If the user requests to change password multiple times without following through on the whole process, each generated link should invalidate the previous one. This prevents having multiple active links from which the password can be reset.</li>
<li>If the user chooses to ignore the password reset link sent to their email, their current credentials should be left intact and valid for future authentication.</li>
</ol>
<h3 id="heading-implementation-steps">Implementation steps</h3>
<p>We now have a clear picture of the reset flow from the user’s perspective and the characteristics of a password reset system. Here are the steps we will take in the implementation of this system:</p>
<ol>
<li>Create a mongoose model called ‘PasswordReset’ to manage active password reset requests/tokens. The records set here should expire after a specified time period.</li>
<li>Include the ‘Forgot password’ link in the login form that leads to a route that contains an email form.</li>
<li>Once the email is submitted to a post route, check whether a user with the provided email address exists.</li>
<li>If the user does not exist, redirect back to the email input form and notify the user that no user with provided email was found.</li>
<li>If the user exists, generate a password reset token and save it to PasswordReset collection in a document that references the user. If there already is a document in this collection associated with this user, update/replace the current document (there can only be one per user).</li>
<li>Generate a link that includes the password reset token within it, email the link to the user.</li>
<li>Redirect to the login page with success message prompting the user to check their email address for the reset link.</li>
<li>Once the user clicks the link, it should lead to a GET route that expects the token as one of the route params.</li>
<li>Within this route, extract the token and query the PasswordReset collection for this token. If the document is not found, alert the user that the link is invalid/expired.</li>
<li>If the document is found, load a form to reset the password. The form should have 2 fields (new password &amp; confirm password fields).</li>
<li>When the form is submitted, its post route will update the user’s password to the new password.</li>
<li>Delete the password reset document associated with this user in the PasswordReset collection.</li>
<li>Redirect the user to the login page with a success message.</li>
</ol>
<h2 id="heading-implementation">Implementation</h2>
<h3 id="heading-the-setup">The setup</h3>
<p>Firstly, we’ll have to set up the project. Install the <a target="_blank" href="https://www.npmjs.com/package/uuid">uuid</a> package for generating a unique token, and the <a target="_blank" href="https://www.npmjs.com/package/nodemailer">nodemailer</a> package for sending emails.</p>
<p><code>npm install uuid nodemailer</code></p>
<p>Add the full domain to the environment variables. We’ll need this in order to generate a fill link string to email to the user.</p>
<p><code>DOMAIN=http://localhost:8000</code></p>
<p>Make some changes to the app entry file in the following areas:</p>
<ol>
<li>Set <code>useCreateIndex</code> to ‘true’ in the mongoose connection options. This makes mongoose’s default index build use createIndex instead of ensureIndex and prevents MongoDB deprecation warnings.</li>
<li>Import a new route file that will contain all the reset routes called ‘password-reset’. We will create these routes later.</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> connection = mongoose.connect(process.env.MONGO\_URI, {
  <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">useCreateIndex</span>: <span class="hljs-literal">true</span>
})

...

app.use(<span class="hljs-string">'/'</span>, <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routes/password-reset'</span>))
</code></pre>
<h3 id="heading-models">Models</h3>
<p>We need to have a dedicated model to handle the password reset records. In the models folder, create a model called ‘PasswordReset’ with the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { Schema, model } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>)

<span class="hljs-keyword">const</span> schema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">user</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.ObjectId,
    <span class="hljs-attr">ref</span>: <span class="hljs-string">'User'</span>,
    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
  },
  <span class="hljs-attr">token</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.String,
    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
  }
}, {
  <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span>
})

schema.index({ <span class="hljs-string">'updatedAt'</span>: <span class="hljs-number">1</span> }, { <span class="hljs-attr">expireAfterSeconds</span>: <span class="hljs-number">300</span> })

<span class="hljs-keyword">const</span> PasswordReset = model(<span class="hljs-string">'PasswordReset'</span>, schema)

<span class="hljs-built_in">module</span>.exports = PasswordReset
</code></pre>
<p>We have two properties in this model, the user that’s requested the password reset, and the unique token assigned to the particular request.</p>
<p>Make sure to set the timestamps option to true in order to include <code>createdAt</code> and <code>updatedAt</code> fields in the document.</p>
<p>After defining the schema, create an index on the updatedAt field with an expiry time of 300 seconds (5 minutes). I’ve set it this low for testing purposes. In production, you can increase this to something more practical like 2 hours.</p>
<p>In the User model we created in <a target="_blank" href="https://kelvinmwinuka.com/how-to-set-up-mongoose-with-expressjs/">this article</a> (or the user model you currently have), update the pre save hook to the following:</p>
<pre><code class="lang-javascript">userSchema.pre(<span class="hljs-string">'save'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">next</span>)</span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isNew || <span class="hljs-built_in">this</span>.isModified(<span class="hljs-string">'password'</span>)) <span class="hljs-built_in">this</span>.password = <span class="hljs-keyword">await</span> bcrypt.hash(<span class="hljs-built_in">this</span>.password, saltRounds)
  next()
})
</code></pre>
<p>Do this to make sure the password field is hashed whether the document is new or the password field has been changed in an existing document.</p>
<h3 id="heading-routes">Routes</h3>
<p>Create a new file in the route’s folder called ‘password-reset.js’. This is the file we import in the app entry file.</p>
<p>In this file, import the User and PasswordReset models. Import the v4 function from the uuid package for token generation.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> router  = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>).Router()
<span class="hljs-keyword">const</span> { User, PasswordReset } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models'</span>)
<span class="hljs-keyword">const</span> { v4 } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'uuid'</span>)

<span class="hljs-comment">/* Create routes here */</span>

<span class="hljs-built_in">module</span>.exports = router
</code></pre>
<p>Create the first 2 routes. These routes are associated with the form which accepts the user’s email address.</p>
<pre><code class="lang-javascript">router.get(<span class="hljs-string">'/reset'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> res.render(<span class="hljs-string">'reset.html'</span>))

router.post(<span class="hljs-string">'/reset'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-comment">/* Flash email address for pre-population in case we redirect back to reset page. */</span>
  req.flash(<span class="hljs-string">'email'</span>, req.body.email)

  <span class="hljs-comment">/* Check if user with provided email exists. */</span>
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findOne({ <span class="hljs-attr">email</span>: req.body.email })
  <span class="hljs-keyword">if</span> (!user) {
    req.flash(<span class="hljs-string">'error'</span>, <span class="hljs-string">'User not found'</span>)
    <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'/reset'</span>)
  }

  <span class="hljs-comment">/* Create password reset token and save in collection along with user. 
     If there already is a record with current user, replace it. */</span>
  <span class="hljs-keyword">const</span> token = v4().toString().replace(<span class="hljs-regexp">/-/g</span>, <span class="hljs-string">''</span>)
  PasswordReset.updateOne({ 
    <span class="hljs-attr">user</span>: user._id 
  }, {
    <span class="hljs-attr">user</span>: user._id,
    <span class="hljs-attr">token</span>: token
  }, {
    <span class="hljs-attr">upsert</span>: <span class="hljs-literal">true</span>
  })
  .then( <span class="hljs-function"><span class="hljs-params">updateResponse</span> =&gt;</span> {
    <span class="hljs-comment">/* Send email to user containing password reset link. */</span>
    <span class="hljs-keyword">const</span> resetLink = <span class="hljs-string">`<span class="hljs-subst">${process.env.DOMAIN}</span>/reset-confirm/<span class="hljs-subst">${token}</span>`</span>
    <span class="hljs-built_in">console</span>.log(resetLink)

    req.flash(<span class="hljs-string">'success'</span>, <span class="hljs-string">'Check your email address for the password reset link!'</span>)
    <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'/login'</span>)
  })
  .catch( <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
    req.flash(<span class="hljs-string">'error'</span>, <span class="hljs-string">'Failed to generate reset link, please try again'</span>)
    <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'/reset'</span>)
  })
})
</code></pre>
<p>The first is a GET route to ‘/reset’. In this route, render the ‘reset.html’ template. We will create this template later.</p>
<p>The second route is a POST route for ‘/reset’. This route expects the user’s email in the request body. In this route:</p>
<ol>
<li>Flash email back for pre-population in case we redirect back to the email form.</li>
<li>Check if the user with the email provided exists. If not, flash an error and redirect back to ‘/reset’.</li>
<li>Create a token using v4.</li>
<li>Update PasswordReset document associated with the current user. Set upsert to true in options to create a new document if there isn’t one already.</li>
<li>If update is successful, mail the link to the user, flash a success message and redirect to the login page.</li>
<li>If update is unsuccessful, flash an error message and redirect back to the email page.</li>
</ol>
<p>At the moment, we’re only logging the link to the console. We will implement the email logic later.</p>
<p>Create the 2 routes that come into play when the user visits the link generated link above.</p>
<pre><code class="lang-javascript">router.get(<span class="hljs-string">'/reset-confirm/:token'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> token = req.params.token
  <span class="hljs-keyword">const</span> passwordReset = <span class="hljs-keyword">await</span> PasswordReset.findOne({ token })
  res.render(<span class="hljs-string">'reset-confirm.html'</span>, { 
    <span class="hljs-attr">token</span>: token,
    <span class="hljs-attr">valid</span>: passwordReset ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>
  })
})

router.post(<span class="hljs-string">'/reset-confirm/:token'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> token = req.params.token
  <span class="hljs-keyword">const</span> passwordReset = <span class="hljs-keyword">await</span> PasswordReset.findOne({ token })

  <span class="hljs-comment">/* Update user */</span>
  <span class="hljs-keyword">let</span> user = <span class="hljs-keyword">await</span> User.findOne({ <span class="hljs-attr">_id</span>: passwordReset.user })
  user.password = req.body.password

  user.save().then( <span class="hljs-keyword">async</span> savedUser =&gt;  {
    <span class="hljs-comment">/* Delete password reset document in collection */</span>
    <span class="hljs-keyword">await</span> PasswordReset.deleteOne({ \_id: passwordReset.\_id })
    <span class="hljs-comment">/* Redirect to login page with success message */</span>
    req.flash(<span class="hljs-string">'success'</span>, <span class="hljs-string">'Password reset successful'</span>)
    res.redirect(<span class="hljs-string">'/login'</span>)
  }).catch( <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
    <span class="hljs-comment">/* Redirect back to reset-confirm page */</span>
    req.flash(<span class="hljs-string">'error'</span>, <span class="hljs-string">'Failed to reset password please try again'</span>)
    <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">`/reset-confirm/<span class="hljs-subst">${token}</span>`</span>)
  })
})
</code></pre>
<p>The first route is a get route that expects the token in the url. The token is extracted and then validated. Validate the token by searching the PasswordReset collection for a document with the provided token.</p>
<p>If the document is found, set the ‘valid’ template variable to true, otherwise, set it to false. Be sure to pass the token itself to the template. We will use this in the password reset form.</p>
<p>Check the validity of the token by searching the PasswordReset collection by token.</p>
<p>The second route is a POST route that accepts the password reset form submission. Extract the token from the url and then retrieve the password reset document associated with it.</p>
<p>Update the user associated with this particular password reset document. Set the new password and save the updated user.</p>
<p>Once the user is updated, delete the password reset document to prevent it from being reused to reset the password.</p>
<p>Flash a success message and redirect the user to the login page where they can log in with their new password.</p>
<p>If the update is unsuccessful, flash an error message and redirect back to the same form.</p>
<h3 id="heading-templates">Templates</h3>
<p>Once we’ve created the routes, we need to create the templates</p>
<p>In the views folder, create a ‘reset.html’ template file with the following content:</p>
<pre><code>{<span class="hljs-operator">%</span> extends <span class="hljs-string">'base.html'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> set title <span class="hljs-operator">=</span> <span class="hljs-string">'Reset'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> styles <span class="hljs-operator">%</span>}
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> content <span class="hljs-operator">%</span>}
  <span class="hljs-operator">&lt;</span>form action<span class="hljs-operator">=</span><span class="hljs-string">'/reset'</span> method<span class="hljs-operator">=</span><span class="hljs-string">"POST"</span><span class="hljs-operator">&gt;</span>
    {<span class="hljs-operator">%</span> <span class="hljs-keyword">if</span> messages.error <span class="hljs-operator">%</span>}
      <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"alert alert-danger"</span> role<span class="hljs-operator">=</span><span class="hljs-string">"alert"</span><span class="hljs-operator">&gt;</span>{{ messages.error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    {<span class="hljs-operator">%</span> endif <span class="hljs-operator">%</span>}
    <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"mb-3"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>label <span class="hljs-keyword">for</span><span class="hljs-operator">=</span><span class="hljs-string">"name"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"form-label"</span><span class="hljs-operator">&gt;</span>Enter your email <span class="hljs-keyword">address</span><span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>input 
        <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"text"</span> 
        class<span class="hljs-operator">=</span><span class="hljs-string">"form-control {% if messages.error %}is-invalid{% endif %}"</span> 
        id<span class="hljs-operator">=</span><span class="hljs-string">"email"</span> 
        name<span class="hljs-operator">=</span><span class="hljs-string">"email"</span>
        value<span class="hljs-operator">=</span><span class="hljs-string">"{{ messages.email or '' }}"</span>
        required<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>div<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>button <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"submit"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"btn btn-primary"</span><span class="hljs-operator">&gt;</span>Send reset link<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
  <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>form<span class="hljs-operator">&gt;</span>
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}
</code></pre><p>Here we have one email field that is pre-populated with an email value if one was flashed in the previous request.</p>
<p>Include an alert that displays an error message if one has been flashed from the previous request.</p>
<p>Create another template in the same folder named ‘reset-confirm.html’ with the following content:</p>
<pre><code>{<span class="hljs-operator">%</span> extends <span class="hljs-string">'base.html'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> set title <span class="hljs-operator">=</span> <span class="hljs-string">'Confirm Reset'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> content <span class="hljs-operator">%</span>}
  {<span class="hljs-operator">%</span> <span class="hljs-keyword">if</span> not valid <span class="hljs-operator">%</span>}
    <span class="hljs-operator">&lt;</span>h1<span class="hljs-operator">&gt;</span>Oops, looks like <span class="hljs-built_in">this</span> link <span class="hljs-keyword">is</span> expired, <span class="hljs-keyword">try</span> to <span class="hljs-operator">&lt;</span>a href<span class="hljs-operator">=</span><span class="hljs-string">"/reset"</span><span class="hljs-operator">&gt;</span>generate another reset link<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>a<span class="hljs-operator">&gt;</span><span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">&gt;</span>
  {<span class="hljs-operator">%</span> <span class="hljs-keyword">else</span> <span class="hljs-operator">%</span>}
    <span class="hljs-operator">&lt;</span>form action<span class="hljs-operator">=</span><span class="hljs-string">'/reset-confirm/{{ token }}'</span> method<span class="hljs-operator">=</span><span class="hljs-string">"POST"</span><span class="hljs-operator">&gt;</span>
      {<span class="hljs-operator">%</span> <span class="hljs-keyword">if</span> messages.error <span class="hljs-operator">%</span>}
        <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"alert alert-danger"</span> role<span class="hljs-operator">=</span><span class="hljs-string">"alert"</span><span class="hljs-operator">&gt;</span>{{ messages.error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
      {<span class="hljs-operator">%</span> endif <span class="hljs-operator">%</span>}
      <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"mb-3"</span><span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>label <span class="hljs-keyword">for</span><span class="hljs-operator">=</span><span class="hljs-string">"name"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"form-label"</span><span class="hljs-operator">&gt;</span>Password<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>input 
          <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"password"</span> 
          class<span class="hljs-operator">=</span><span class="hljs-string">"form-control {% if messages.password_error %}is-invalid{% endif %}"</span> 
          id<span class="hljs-operator">=</span><span class="hljs-string">"password"</span> 
          name<span class="hljs-operator">=</span><span class="hljs-string">"password"</span><span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"invalid-feedback"</span><span class="hljs-operator">&gt;</span>{{ messages.password_error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"mb-3"</span><span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>label <span class="hljs-keyword">for</span><span class="hljs-operator">=</span><span class="hljs-string">"name"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"form-label"</span><span class="hljs-operator">&gt;</span>Confirm password<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>input 
          <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"password"</span> 
          class<span class="hljs-operator">=</span><span class="hljs-string">"form-control {% if messages.confirm_error %}is-invalid{% endif %}"</span> 
          id<span class="hljs-operator">=</span><span class="hljs-string">"confirmPassword"</span> 
          name<span class="hljs-operator">=</span><span class="hljs-string">"confirmPassword"</span><span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"invalid-feedback"</span><span class="hljs-operator">&gt;</span>{{ messages.confirm_error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>button <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"submit"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"btn btn-primary"</span><span class="hljs-operator">&gt;</span>Confirm reset<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>form<span class="hljs-operator">&gt;</span>
  {<span class="hljs-operator">%</span> endif <span class="hljs-operator">%</span>}
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}
</code></pre><p>In this form, check for the value of the ‘valid’ variable that we set in the GET route, if false, render the expired token message. Otherwise, render the password reset form.</p>
<p>Include an alert that displays an error message if one was flashed in the previous request.</p>
<p>Go to the login form that we created in the <a target="_blank" href="https://kelvinmwinuka.com/how-to-create-registration-authentication-with-express-passportjs/">registration &amp; authentication</a> article and add the following code to the top of the form:</p>
<pre><code>{<span class="hljs-operator">%</span> <span class="hljs-keyword">if</span> messages.success <span class="hljs-operator">%</span>}
    <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"alert alert-success"</span> role<span class="hljs-operator">=</span><span class="hljs-string">"alert"</span><span class="hljs-operator">&gt;</span>{{ messages.success }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
{<span class="hljs-operator">%</span> endif <span class="hljs-operator">%</span>}
</code></pre><p>This renders the success messages that we flash when we create/send the reset link and when we update the user’s password before redirecting to the login page.</p>
<h3 id="heading-mail">Mail</h3>
<p>In the previous routes section, we logged the reset link in the console. Ideally, we should send an email to the user when they’ve requested a password reset link.</p>
<p>For this example, I’ve used <a target="_blank" href="https://ethereal.email/">ethereal.email</a> to generate a test email account for development purposes. Head over there and create one (it’s a one-click process).</p>
<p>Once you’ve created the test account, add the following variables to your environment variables:</p>
<pre><code><span class="hljs-attr">EMAIL_HOST</span>=smtp.ethereal.email
<span class="hljs-attr">EMAIL_NAME</span>=Leanne Zulauf
<span class="hljs-attr">EMAIL_ADDRESS</span>=leanne.zulauf@ethereal.email
<span class="hljs-attr">EMAIL_PASSWORD</span>=aDhwfMry1h3bbbR9Av
<span class="hljs-attr">EMAIL_PORT</span>=<span class="hljs-number">587</span>
<span class="hljs-attr">EMAIL_SECURITY</span>=STARTTLS
</code></pre><p>These are my values at the time of writing, plug in your own values here.</p>
<p>Create a ‘helpers.js’ file in the root of the project. This file will have a bunch of useful functions that are likely to be reused across the entire project.</p>
<p>Define these functions here so that we can import them when they’re needed rather than repeating similar logic all over our application.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> nodemailer = <span class="hljs-built_in">require</span>(<span class="hljs-string">'nodemailer'</span>)

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">sendEmail</span>: <span class="hljs-keyword">async</span> ({ to, subject, text }) =&gt; {
    <span class="hljs-comment">/* Create nodemailer transporter using environment variables. */</span>
    <span class="hljs-keyword">const</span> transporter = nodemailer.createTransport({
      <span class="hljs-attr">host</span>: process.env.EMAIL_HOST,
      <span class="hljs-attr">port</span>: <span class="hljs-built_in">Number</span>(process.env.EMAIL_PORT),
      <span class="hljs-attr">auth</span>: {
        <span class="hljs-attr">user</span>: process.env.EMAIL_ADDRESS,
        <span class="hljs-attr">pass</span>: process.env.EMAIL_PASSWORD
      }
    })
    <span class="hljs-comment">/* Send the email */</span>
    <span class="hljs-keyword">let</span> info = <span class="hljs-keyword">await</span> transporter.sendMail({
      <span class="hljs-attr">from</span>: <span class="hljs-string">`"<span class="hljs-subst">${process.env.EMAIL_NAME}</span>" &lt;<span class="hljs-subst">${process.env.EMAIL_ADDRESS}</span>&gt;`</span>,
      to,
      subject,
      text
    })
    <span class="hljs-comment">/* Preview only available when sending through an Ethereal account */</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Message preview URL: <span class="hljs-subst">${nodemailer.getTestMessageUrl(info)}</span>`</span>)
  }
}
</code></pre>
<p>Export an object with various functions. The first being the <code>sendEmail</code> function.</p>
<p>This function takes the recipient’s address, email subject and email text. Create the NodeMailer transporter, using the environment variables defined previously in the options. Send the email using the arguments passed to the function.</p>
<p>The last line of the function logs the message url in the console so you can view the message on Ethereal mail. The test account does not actually send the email.</p>
<p>Go back to the ‘password-reset.js’ routes and add the email functionality. First, import the function:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { sendEmail } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../helpers'</span>)
</code></pre>
<p>In the ‘/reset’ POST route, instead of logging the reset link on the console, add the following code:</p>
<pre><code class="lang-javascript">sendEmail({
      <span class="hljs-attr">to</span>: user.email, 
      <span class="hljs-attr">subject</span>: <span class="hljs-string">'Password Reset'</span>,
      <span class="hljs-attr">text</span>: <span class="hljs-string">`Hi <span class="hljs-subst">${user.name}</span>, here's your password reset link: <span class="hljs-subst">${resetLink}</span>. 
      If you did not request this link, ignore it.`</span>
    })
</code></pre>
<p>Send an additional email to notify the user of a successful password change in the ‘/reset-confirm’ POST route once the user is successfully updated:</p>
<pre><code class="lang-javascript">user.save().then( <span class="hljs-keyword">async</span> savedUser =&gt;  {
    <span class="hljs-comment">/* Delete password reset document in collection */</span>
    <span class="hljs-keyword">await</span> PasswordReset.deleteOne({ <span class="hljs-attr">_id</span>: passwordReset._id })
    <span class="hljs-comment">/* Send successful password reset email */</span>
    sendEmail({
      <span class="hljs-attr">to</span>: user.email, 
      <span class="hljs-attr">subject</span>: <span class="hljs-string">'Password Reset Successful'</span>,
      <span class="hljs-attr">text</span>: <span class="hljs-string">`Congratulations <span class="hljs-subst">${user.name}</span>! Your password reset was successful.`</span>
    })
    <span class="hljs-comment">/* Redirect to login page with success message */</span>
    req.flash(<span class="hljs-string">'success'</span>, <span class="hljs-string">'Password reset successful'</span>)
    res.redirect(<span class="hljs-string">'/login'</span>)
  }).catch( <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
    <span class="hljs-comment">/* Redirect back to reset-confirm page */</span>
    req.flash(<span class="hljs-string">'error'</span>, <span class="hljs-string">'Failed to reset password please try again'</span>)
    <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">`/reset-confirm/<span class="hljs-subst">${token}</span>`</span>)
  })
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, I demonstrated how to implement a password reset feature in ExpressJS using NodeMailer.</p>
<p>In the next article, I will write about <a target="_blank" href="https://kelvinmwinuka.com/how-to-verify-users-in-expressjs/">implementing a user email verification system</a> in your Express application. I will use a similar approach to the one used in this article, with NodeMailer being the email package of choice.</p>
]]></content:encoded></item><item><title><![CDATA[Create Registration & Authentication with Express & PassportJS]]></title><description><![CDATA[In this article, I’m going to demonstrate how to build a user registration and authentication system in ExpressJS. In the previous article, we set up a MongoDB connection using Mongoose. Here we’ll be using that connection to save user data and use i...]]></description><link>https://kelvinmwinuka.com/create-registration-and-authentication-with-express-and-passportjs</link><guid isPermaLink="true">https://kelvinmwinuka.com/create-registration-and-authentication-with-express-and-passportjs</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[Express]]></category><category><![CDATA[code]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[MongoDB]]></category><category><![CDATA[mongoose]]></category><category><![CDATA[passport]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Mon, 21 Dec 2020 06:47:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649113977846/c228R3jey.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, I’m going to demonstrate how to build a user registration and authentication system in ExpressJS. In the previous article, we <a target="_blank" href="https://kelvinmwinuka.com/how-to-set-up-mongoose-with-expressjs/">set up a MongoDB connection using Mongoose</a>. Here we’ll be using that connection to save user data and use it for authentication.</p>
<p>This project is available on <a target="_blank" href="https://github.com/kelvinmwinuka/express-tutorial">Github</a>. Feel free to clone it if you’d like to follow along.</p>
<h2 id="heading-setup">Setup</h2>
<p>Let’s start by setting up the necessary packages and libraries for this portion of the project.</p>
<p>Run the following command to install the necessary package:</p>
<p><code>npm install passport passport-local express-session bcrypt connect-mongo express-flash joi</code></p>
<p>Here’s a breakdown of the packages we’ve just installed:</p>
<ol>
<li><a target="_blank" href="http://www.passportjs.org/">passport</a> and <a target="_blank" href="http://www.passportjs.org/packages/passport-local/">passport-local</a> – User authentication.</li>
<li><a target="_blank" href="https://www.npmjs.com/package/express-session">express-session</a> – Sessions in ExpressJS.</li>
<li><a target="_blank" href="https://www.npmjs.com/package/bcrypt">bcrypt</a> – Password encryption and comparison on authentication.</li>
<li><a target="_blank" href="https://www.npmjs.com/package/connect-mongo">connect-mongo</a> – Mongo store for express sessions.</li>
<li><a target="_blank" href="https://www.npmjs.com/package/express-flash">express-flash</a> – Flashing messages for display in the front-end.</li>
<li><a target="_blank" href="https://joi.dev/api/?v=17.3.0">joi</a> – User input validation.</li>
</ol>
<p>Include bootstrap (optional, as long as the form can send post data to the server, it will work).</p>
<p>In the <em><strong>base.html</strong></em> file, add the link and script tags for the bootstrap imports. They are imported once and then included in every template that extends the base template.</p>
<p>At this stage, base.html file should look like this:</p>
<pre><code><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>{{ title }}<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">""</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Bootstrap CSS --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> 
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css"</span> 
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> 
      <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1"</span> 
      <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
    {% block styles %}
      {# This block will be replaced by child templates when importing styles #}
    {% endblock %}
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    {% block content %}
      {# This block will be replaced by child templates when adding content to the  #}
    {% endblock %}

    <span class="hljs-comment">&lt;!-- Bootstrap JavaScript Bundle with Popper --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> 
      <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"</span> 
      <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"</span> 
      <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    {% block scripts %}
      {# This block will be replaced by child templates when importing scripts #}
    {% endblock %}
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre><h2 id="heading-implementation">Implementation</h2>
<p>Go into the entry point file and require the following packages:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> session = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express-session'</span>)
<span class="hljs-keyword">const</span> MongoStore = <span class="hljs-built_in">require</span>(<span class="hljs-string">'connect-mongo'</span>)(session)
<span class="hljs-keyword">const</span> passport = <span class="hljs-built_in">require</span>(<span class="hljs-string">'passport'</span>)
</code></pre>
<p>Right after the app declaration, add built-in express middleware to parse incoming requests with url-encoded data to process the data that will be received from the forms.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> app = express()
app.use(express.urlencoded({<span class="hljs-attr">extended</span>: <span class="hljs-literal">true</span>}))
</code></pre>
<p>Next, set up the session middleware. Make sure to place this code after the mongoose connection as we will use the existing mongoose connection to store the session data. Otherwise, you’ll have to create a new connection for this.</p>
<pre><code class="lang-javascript">app.use(session({
  <span class="hljs-attr">secret</span>: process.env.SESSION\_SECRET,
  <span class="hljs-attr">resave</span>: <span class="hljs-literal">false</span>,
  <span class="hljs-attr">saveUninitialized</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">store</span>: <span class="hljs-keyword">new</span> MongoStore({
    <span class="hljs-attr">mongooseConnection</span>: mongoose.connection,
    <span class="hljs-attr">collection</span>: <span class="hljs-string">'sessions'</span>
  }),
  <span class="hljs-attr">cookie</span>: {
    <span class="hljs-attr">secure</span>: <span class="hljs-literal">false</span>
  }
}))
</code></pre>
<p>Let’s walk through the code above:</p>
<ol>
<li>We’re adding the session middleware to the app.</li>
<li>secret – The string used to encrypt the session. Declare this in the .env file or system environment variables.</li>
<li>resave – Determines whether the session object is saved back into the session store even if it was not modified by the request.</li>
<li>saveUninitialized – Determines whether a new session should be saved into the store even before it’s modified.</li>
<li>store – The store is used to save session data.</li>
</ol>
<h3 id="heading-update-models">Update models</h3>
<p>In this section, I’m referring to the user model we created in the previous article. <a target="_blank" href="https://kelvinmwinuka.com/how-to-set-up-mongoose-with-expressjs/">Take a look here</a>.</p>
<p>Now we need to update the user model in order to enable authentication and password hashing upon saving. We’re doing this in the model in order to avoid writing the authentication login in multiple places shall we need it.</p>
<p>This logic is unique to this model so it makes sense to have it here. Navigate to the User.js model file we created previously and add the following code right after the first require statement:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'bcrypt'</span>)

<span class="hljs-keyword">const</span> saltRounds = <span class="hljs-number">10</span>
</code></pre>
<p>After the schema definition, add the following code:</p>
<pre><code class="lang-javascript">userSchema.pre(<span class="hljs-string">'save'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">next</span>)</span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isNew) <span class="hljs-built_in">this</span>.password = <span class="hljs-keyword">await</span> bcrypt.hash(<span class="hljs-built_in">this</span>.password, saltRounds)
  next()
})

userSchema.static(<span class="hljs-string">'userExists'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">{username, email}</span>)</span>{
  <span class="hljs-keyword">let</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.findOne({ username })
  <span class="hljs-keyword">if</span> (user) <span class="hljs-keyword">return</span> { <span class="hljs-attr">username</span>: <span class="hljs-string">'This username is already in use'</span> }
  user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.findOne({ email })
  <span class="hljs-keyword">if</span> (user) <span class="hljs-keyword">return</span> { <span class="hljs-attr">email</span>: <span class="hljs-string">'This email address is already in use'</span> }
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
})

userSchema.static(<span class="hljs-string">'authenticate'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">username, plainTextPassword</span>)</span>{
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.findOne({ <span class="hljs-attr">$or</span>: [ {<span class="hljs-attr">email</span>: username}, {username} ] })
  <span class="hljs-keyword">if</span> (user &amp;&amp; <span class="hljs-keyword">await</span> bcrypt.compare(plainTextPassword, user.password)) <span class="hljs-keyword">return</span> user
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
})
</code></pre>
<p>There are a few things happening here:</p>
<ol>
<li>The first is a pre-save hook. This runs before every document save. We use it to determine if the current document is new (not an update call). If the document is new, hash the password. Always save a hashed password rather than plain text.</li>
<li>The second block is a static method that checks if the user exists. We will query the database by username and then email. If a user is found, return an object specifying which one is already in use. Otherwise, return false.</li>
<li>The third method is a static method added to the schema. We’re using this to authenticate the user. If the user exists and the password comparison between plainTextPassword and the hashed user password passes, return the user object. Otherwise, return false for. failed authentication.</li>
</ol>
<h3 id="heading-registration">Registration</h3>
<p>Create the registration form; a simple form that collects the user’s name, username, email address and password.</p>
<p>Place this code in ‘register.html’ in the views folder.</p>
<pre><code>{<span class="hljs-operator">%</span> extends <span class="hljs-string">'base.html'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> set title <span class="hljs-operator">=</span> <span class="hljs-string">'Register'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> styles <span class="hljs-operator">%</span>}
  <span class="hljs-operator">&lt;</span>style<span class="hljs-operator">&gt;</span>
    form {
      margin<span class="hljs-operator">-</span>top: 20px;
      margin<span class="hljs-operator">-</span>left: 20px;
      margin<span class="hljs-operator">-</span>right: 20px;
    }
  <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>style<span class="hljs-operator">&gt;</span>
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> content <span class="hljs-operator">%</span>}
  <span class="hljs-operator">&lt;</span>form action<span class="hljs-operator">=</span><span class="hljs-string">"/register"</span> method<span class="hljs-operator">=</span><span class="hljs-string">"POST"</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"mb-3"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>label <span class="hljs-keyword">for</span><span class="hljs-operator">=</span><span class="hljs-string">"name"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"form-label"</span><span class="hljs-operator">&gt;</span>Name<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>input 
        <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"text"</span> 
        class<span class="hljs-operator">=</span><span class="hljs-string">"form-control {% if messages.name_error %}is-invalid{% endif %}"</span> 
        id<span class="hljs-operator">=</span><span class="hljs-string">"name"</span> 
        name<span class="hljs-operator">=</span><span class="hljs-string">"name"</span>
        value<span class="hljs-operator">=</span><span class="hljs-string">"{{ messages.name or '' }}"</span>
        placeholder<span class="hljs-operator">=</span><span class="hljs-string">"Full Name"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"invalid-feedback"</span><span class="hljs-operator">&gt;</span>{{ messages.name_error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"mb-3"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>label <span class="hljs-keyword">for</span><span class="hljs-operator">=</span><span class="hljs-string">"username"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"form-label"</span><span class="hljs-operator">&gt;</span>Username<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>input 
        <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"text"</span> 
        class<span class="hljs-operator">=</span><span class="hljs-string">"form-control {% if messages.username_error %}is-invalid{% endif %}"</span> 
        id<span class="hljs-operator">=</span><span class="hljs-string">"username"</span> 
        name<span class="hljs-operator">=</span><span class="hljs-string">"username"</span>
        value<span class="hljs-operator">=</span><span class="hljs-string">"{{ messages.username or '' }}"</span>
        placeholder<span class="hljs-operator">=</span><span class="hljs-string">"Username"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"invalid-feedback"</span><span class="hljs-operator">&gt;</span>{{ messages.username_error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"mb-3"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>label <span class="hljs-keyword">for</span><span class="hljs-operator">=</span><span class="hljs-string">"email"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"form-label"</span><span class="hljs-operator">&gt;</span>Email <span class="hljs-keyword">address</span><span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>input 
        <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"email"</span> 
        class<span class="hljs-operator">=</span><span class="hljs-string">"form-control {% if messages.email_error %}is-invalid{% endif %}"</span> 
        id<span class="hljs-operator">=</span><span class="hljs-string">"email"</span>
        name<span class="hljs-operator">=</span><span class="hljs-string">"email"</span>
        value<span class="hljs-operator">=</span><span class="hljs-string">"{{ messages.email or '' }}"</span>
        placeholder<span class="hljs-operator">=</span><span class="hljs-string">"Email Address"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"invalid-feedback"</span><span class="hljs-operator">&gt;</span>{{ messages.email_error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"mb-3"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>label <span class="hljs-keyword">for</span><span class="hljs-operator">=</span><span class="hljs-string">"password"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"form-label"</span><span class="hljs-operator">&gt;</span>Password<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>input 
        <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"password"</span> 
        class<span class="hljs-operator">=</span><span class="hljs-string">"form-control {% if messages.password_error %}is-invalid{% endif %}"</span> 
        id<span class="hljs-operator">=</span><span class="hljs-string">"password"</span> 
        name<span class="hljs-operator">=</span><span class="hljs-string">"password"</span> 
        value<span class="hljs-operator">=</span><span class="hljs-string">"{{ messages.password or '' }}"</span>
        placeholder<span class="hljs-operator">=</span><span class="hljs-string">"Password"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"invalid-feedback"</span><span class="hljs-operator">&gt;</span>{{ messages.password_error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>div<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>button <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"submit"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"btn btn-primary"</span><span class="hljs-operator">&gt;</span>Sign me up<span class="hljs-operator">!</span><span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
  <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>form<span class="hljs-operator">&gt;</span>
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> scripts <span class="hljs-operator">%</span>}
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}
</code></pre><p>We’re using nunjucks to implement some dynamic behaviour.</p>
<p>The first is adding the is-invalid class to the form controls using flashed messages from the server. This adds an error message attached to the form control.</p>
<p>The second is setting the previous value entered by the user (an optional UX feature for the purposes of this tutorial).</p>
<p>After creating the register template, create the routes associated with the template.</p>
<p>Create a folder named ‘routes’ in the root of the project. This folder will hold all of our routes. Create a file ‘register.js’ in this folder. The contents of this file should be as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> router = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>).Router()
<span class="hljs-keyword">const</span> Joi = <span class="hljs-built_in">require</span>(<span class="hljs-string">'joi'</span>)
<span class="hljs-keyword">const</span> { User } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models'</span>)

<span class="hljs-keyword">const</span> validateRegistrationInfo = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
  <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> [key, value] <span class="hljs-keyword">of</span> <span class="hljs-built_in">Object</span>.entries(req.body)) {
    req.flash(<span class="hljs-string">`<span class="hljs-subst">${key}</span>`</span>, value)
  }
  <span class="hljs-comment">/* Validate the request parameters.
  If they are valid, continue with the request.
  Otherwise, flash the error and redirect to registration form. */</span>
  <span class="hljs-keyword">const</span> schema = Joi.object({
    <span class="hljs-attr">name</span>: Joi.string().required(),
    <span class="hljs-attr">username</span>: Joi.string().alphanum().min(<span class="hljs-number">6</span>).max(<span class="hljs-number">12</span>).required(),
    <span class="hljs-attr">email</span>: Joi.string()
        .email({ <span class="hljs-attr">minDomainSegments</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">tlds</span>: { <span class="hljs-attr">allow</span>: [<span class="hljs-string">'com'</span>, <span class="hljs-string">'net'</span>] } }).required(),
    <span class="hljs-attr">password</span>: Joi.string().min(<span class="hljs-number">8</span>).required()
  })

  <span class="hljs-keyword">const</span> error = schema.validate(req.body, { <span class="hljs-attr">abortEarly</span>: <span class="hljs-literal">false</span> }).error
  <span class="hljs-keyword">if</span> (error) {
    error.details.forEach(<span class="hljs-function"><span class="hljs-params">currentError</span> =&gt;</span> {
      req.flash(\<span class="hljs-string">`<span class="hljs-subst">${currentError.context.label}</span>\_error\`, currentError.message)
    })
    return res.redirect('/register')
  }

  /** Check if user exists */
  const userExists = await User.userExists(req.body)
  if (userExists) {
    for(let [key, message\] of Object.entries(userExists)) {
      req.flash(`</span>${key}<span class="hljs-string">`, message)
    }
    return res.redirect('/register')
  }

  next()  
}

router.get('/register', (req, res) =&gt; res.render('register.html'))

router.post('/register', validateRegistrationInfo, async (req, res) =&gt; {
  let savedUser = await (new User(req.body)).save()
  res.redirect('/')
})

module.exports = router</span>
</code></pre>
<p>The first significant block of code is a function called <em><strong>validateRegistrationInfo</strong></em>. This is middleware that will be used to validate the user’s registration information.</p>
<p>In the first phase of the validation, we immediately flash the current information for pre-population in case we redirect back to the registration page.</p>
<p>Phase 2 is validating each entry against a validation schema. The <a target="_blank" href="https://joi.dev/">Joi</a> package makes this process easy.</p>
<p>If there are any errors on validation, flash each error message for that particular entry before redirecting to the register page. Display this error message in the template.</p>
<p>The final phase of validation is checking whether the username/email provided are already in use. If they are, flash the error message before redirecting to the register route.</p>
<p>Create a GET route that simply renders ‘register.html’. This is the route we redirect to when validation fails.</p>
<p>Create a post route that receives the data entered by the user in the request body passing the validation middleware to it.</p>
<p>In the route handler itself, we don’t have to worry about invalid data as it would have passed all the validation checks if the handler is being executed.</p>
<p>Create a new user using the provided data, save it, and redirect to the home page.</p>
<p>Export this router object and import it in the entry file as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import rotues</span>
app.use(<span class="hljs-string">'/'</span>, <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routes/register'</span>))
</code></pre>
<h3 id="heading-authentication">Authentication</h3>
<p>Now that we’ve taken care of the registration, it’s time to implement the authentication logic of our application.</p>
<p>Start by creating a login form. This form has a username/email field and a password field. We’ll also include a condition that checks for an error message to display in an alert. This will be displayed when we redirect to the login page after flashing a message.</p>
<p>Place this form in a ‘login.html’ template file in the views folder alongside the register template.</p>
<pre><code>{<span class="hljs-operator">%</span> extends <span class="hljs-string">'base.html'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> set title <span class="hljs-operator">=</span> <span class="hljs-string">'Login'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> styles <span class="hljs-operator">%</span>}
  <span class="hljs-operator">&lt;</span>style<span class="hljs-operator">&gt;</span>
    form {
      margin<span class="hljs-operator">-</span>top: 20px;
      margin<span class="hljs-operator">-</span>left: 20px;
      margin<span class="hljs-operator">-</span>right: 20px;
    }
  <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>style<span class="hljs-operator">&gt;</span>
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> content <span class="hljs-operator">%</span>}
  <span class="hljs-operator">&lt;</span>form action<span class="hljs-operator">=</span><span class="hljs-string">"/login"</span> method<span class="hljs-operator">=</span><span class="hljs-string">"POST"</span><span class="hljs-operator">&gt;</span>
    {<span class="hljs-operator">%</span> <span class="hljs-keyword">if</span> messages.error <span class="hljs-operator">%</span>}
      <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"alert alert-danger"</span> role<span class="hljs-operator">=</span><span class="hljs-string">"alert"</span><span class="hljs-operator">&gt;</span>{{ messages.error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    {<span class="hljs-operator">%</span> endif <span class="hljs-operator">%</span>}
    <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"mb-3"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>label <span class="hljs-keyword">for</span><span class="hljs-operator">=</span><span class="hljs-string">"name"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"form-label"</span><span class="hljs-operator">&gt;</span>Username or Email<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>input 
        <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"text"</span> 
        class<span class="hljs-operator">=</span><span class="hljs-string">"form-control {% if messages.name_error %}is-invalid{% endif %}"</span> 
        id<span class="hljs-operator">=</span><span class="hljs-string">"username"</span> 
        name<span class="hljs-operator">=</span><span class="hljs-string">"username"</span>
        value<span class="hljs-operator">=</span><span class="hljs-string">"{{ messages.name or '' }}"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"invalid-feedback"</span><span class="hljs-operator">&gt;</span>{{ messages.name_error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"mb-3"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>label <span class="hljs-keyword">for</span><span class="hljs-operator">=</span><span class="hljs-string">"name"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"form-label"</span><span class="hljs-operator">&gt;</span>Password<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>input 
        <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"password"</span> 
        class<span class="hljs-operator">=</span><span class="hljs-string">"form-control {% if messages.name_error %}is-invalid{% endif %}"</span> 
        id<span class="hljs-operator">=</span><span class="hljs-string">"password"</span> 
        name<span class="hljs-operator">=</span><span class="hljs-string">"password"</span>
        value<span class="hljs-operator">=</span><span class="hljs-string">"{{ messages.name or '' }}"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div class<span class="hljs-operator">=</span><span class="hljs-string">"invalid-feedback"</span><span class="hljs-operator">&gt;</span>{{ messages.name_error }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>div<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>button <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"submit"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"btn btn-primary"</span><span class="hljs-operator">&gt;</span>Login<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
  <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>form<span class="hljs-operator">&gt;</span>
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> scripts <span class="hljs-operator">%</span>}
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}
</code></pre><p>The next task is to define the passport strategy used to authenticate the user. We’re using the strategy from passport-local because we’re authenticating against our own stored user credentials.</p>
<p>Create a new file in the root of the project called ‘passport-helper.js’ with the following contents:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> LocalStrategy = <span class="hljs-built_in">require</span>(<span class="hljs-string">'passport-local'</span>).Strategy
<span class="hljs-keyword">const</span> { User } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./models'</span>)

<span class="hljs-built_in">module</span>.exports = <span class="hljs-function">(<span class="hljs-params">app, passport</span>) =&gt;</span> {

  passport.use(<span class="hljs-keyword">new</span> LocalStrategy(<span class="hljs-function">(<span class="hljs-params">username, password, done</span>) =&gt;</span> {
    User.authenticate(username, password)
    .then( <span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {
      done(<span class="hljs-literal">null</span>, user)
    })
    .catch( <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
      done(error)
    })
  }))

  passport.serializeUser(<span class="hljs-function">(<span class="hljs-params">user, done</span>) =&gt;</span> {
    done(<span class="hljs-literal">null</span>, user.\_id)
  })

  passport.deserializeUser(<span class="hljs-function">(<span class="hljs-params">id, done</span>) =&gt;</span> {
    User.findById(id, <span class="hljs-function">(<span class="hljs-params">error, user</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> done(error)
      done(<span class="hljs-literal">null</span>, user)
    })
  })

  app.use(passport.initialize())
  app.use(passport.session())
}
</code></pre>
<p>The first step is importing the Strategy and the User model.</p>
<p>The second step is configuring the strategy. We create a new instance of the strategy passing it a function that takes username, password and a verify callback (done) function that is executed after the authentication process is complete.</p>
<p>The authentication logic is placed inside this function. In order to keep this clean, we will simply use the ‘authenticate’ static method we created in the user model.</p>
<p>When authenticating in passport, a user object is passed to the verify callback upon successful authentication, otherwise false is returned (provided there’s no error thrown in which case, pass the error).</p>
<p>Our authenticate method returns a user object if the user is found and false otherwise so its output is perfect for this scenario.</p>
<p>Once we’ve configured the strategy, we have to specify the user serialization and deserialization logic.</p>
<p>This step is optional if you’re not using sessions, but we’re trying to create a login system with sessions so in our case, it’s necessary.</p>
<p>The serializeUser method takes a function with a user object and a callback as parameters which determines the data that will be stored in the session itself.</p>
<p>To keep the data stored in the session small, we store only the user ID in the session. This serialization process happens on initial login.</p>
<p>The deserializeUser method takes a function that receives the user ID and a callback. This method runs on all subsequent requests after login/serialization.</p>
<p>The user ID is grabbed from the session and the user is retrieved from the database. Once the user is retrieved, they are stored in req.user.</p>
<p>After serialization/deserialization, make sure to add passport initialize and session middleware to the app. We’ll wrap all of this up in a function that takes our app and passport objects as parameters.</p>
<p>Our passport configuration is now complete. The next step is to initialize passport.</p>
<p>In the application entry file, import the function we created in the previous step and then execute it, passing the app and passport objects.</p>
<p>Make sure to have the require statement after the passport require statement. The initialization function must be called after session middleware is defined because the passport session middleware utilises it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> initializePassport = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./passport-helper'</span>)
...
initializePassport(app, passport)
</code></pre>
<p>Now let’s create the login routes. Inside the routes folder, create a file called ‘login.js’ and add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> createLoginRoutes = <span class="hljs-function"><span class="hljs-params">passport</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> router = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>).Router()

  router.get(<span class="hljs-string">'/login'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (req.isAuthenticated()) <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'/'</span>)
    res.render(<span class="hljs-string">'login.html'</span>)
  })

  router.post(
    <span class="hljs-string">'/login'</span>,
    passport.authenticate(<span class="hljs-string">'local'</span>, {
      <span class="hljs-attr">failureRedirect</span>: <span class="hljs-string">'/login'</span>, 
      <span class="hljs-attr">successRedirect</span>: <span class="hljs-string">'/'</span>,
      <span class="hljs-attr">failureFlash</span>: <span class="hljs-string">'User not found'</span>, 
    }),
    <span class="hljs-function">(<span class="hljs-params">error, req, res, next</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (error) next(error)
    }
  )

  router.get(<span class="hljs-string">'/logout'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    req.logout()
    res.redirect(<span class="hljs-string">'/login'</span>)
  })

  <span class="hljs-keyword">return</span> router
}

<span class="hljs-built_in">module</span>.exports = createLoginRoutes
</code></pre>
<p>Instead of creating routes in the same way we did in the register route file, we’re doing it a bit differently here.</p>
<p>Since we’re going to need the passport object, we will instead export a function that accepts a passport object as a parameter, defines the routes and returns the router object.</p>
<p>The first route is a GET route for ‘/login’. This renders the form when there is no active session. Use the ‘isAuthenticated’ method provided by passport in the request object in order to determine whether there is currently an active session.</p>
<p>The second route is a POST route from ‘/login’. This route accepts the form input from the user.</p>
<p>Pass the <code>passport.authenticate</code> middleware to this route to handle the authentication. This middleware accepts the strategy type and an options object.</p>
<p>In the options object, specify the redirect path in case of failure and in case of success. The failureFlash property specifies the message to flash in case of authentication failure. This is the message you should check for and display on the login page.</p>
<p>Finally, create a logout route that calls <code>req.logout</code> to end the current user’s session. This logout method is also provided by passport.</p>
<p>Now import the login route creator in the entry file and pass the passport object to it:</p>
<pre><code class="lang-javascript">app.use(<span class="hljs-string">'/'</span>, <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routes/auth'</span>)(passport))
</code></pre>
<p>Update the home page route to the following:</p>
<pre><code class="lang-javascript">app.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">if</span> (!req.isAuthenticated()) <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'/login'</span>)
  res.render(<span class="hljs-string">'home.html'</span>)
})
</code></pre>
<p>The home page route is now a protected route. This means it should only be accessed by an authenticated user.</p>
<p>We achieve this by using the req.isAuthenticated method to make sure the user is authenticated. If not, redirect to the login page.</p>
<p>Go back to the register route file and update the GET route. to the following:</p>
<pre><code class="lang-javascript">router.get(<span class="hljs-string">'/register'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (req.isAuthenticated()) <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-string">'/'</span>)
  res.render(<span class="hljs-string">'register.html'</span>)
})
</code></pre>
<p>We only need to render the registration form if the user is not authenticated, otherwise, redirect to the home page.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, I demonstrated how to create a simple registration/authentication system in ExpressJS using PassportJS. However, an authentication system is not complete without a password reset feature.</p>
<p>The next article will be a tutorial on <a target="_blank" href="https://kelvinmwinuka.com/how-to-handle-password-reset-in-expressjs/">creating a password reset feature using mongoose and NodeMailer.</a></p>
]]></content:encoded></item><item><title><![CDATA[Set Up Mongoose With ExpressJS]]></title><description><![CDATA[In the previous article, I demonstrated how to set up Nunjucks template engine in your express project. I decided to make this a full-fledged web app development series of articles by progressively building the example application. In this article, w...]]></description><link>https://kelvinmwinuka.com/set-up-mongoose-with-expressjs</link><guid isPermaLink="true">https://kelvinmwinuka.com/set-up-mongoose-with-expressjs</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[Express]]></category><category><![CDATA[code]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[mongoose]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Thu, 17 Dec 2020 03:12:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649113987338/HbbnX7N6J.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous article, I demonstrated <a target="_blank" href="https://kelvinmwinuka.com/how-to-set-up-nunjucks-with-expressjs/">how to set up Nunjucks template engine</a> in your express project. I decided to make this a full-fledged web app development series of articles by progressively building the example application. In this article, we are going to connect the app to a MongoDB database using Mongoose.</p>
<p>Mongoose is an ODM (Object Document Mapper) that allows interaction with MongoDB databases using JavaScript objects.</p>
<p>It provides extra functionality (such as static methods on the schema) that allows us to enhance database interactions and write cleaner code.</p>
<p>At the time of writing this article, the latest stable version of Mongoose is v5.11.8. This will most likely be different at the time of reading although most of the information here should still be relevant.</p>
<p>Makes sure you have a MongoDB server installed and running on your system before following along. If not, you can <a target="_blank" href="https://www.mongodb.com/cloud/atlas">sign up for a free cluster</a> at MongoDB Atlas and connect to that instead.</p>
<h2 id="heading-mongoose-setup">Mongoose setup</h2>
<p>Install Mongoose and dotenv using the following command:</p>
<p><code>npm install mongoose dotenv</code></p>
<p>Dotenv allows us to load environment variables into our application. We are going to place the MongoDB URI in an environment variable file instead of hard-coding it.</p>
<p>Doing this allows us to connect to different MongoDB instances in different environments by only changing this URI in the environment variable without changing the code itself.</p>
<p>Create a file called <code>.env</code> in the root of your project. The contents of the files should be as follows:</p>
<pre><code><span class="hljs-attr">PORT</span>=<span class="hljs-number">8000</span>
<span class="hljs-attr">MONGO_URI</span>=mongodb://localhost:<span class="hljs-number">27017</span>/app
</code></pre><p>We’ve defined the port here along with the MongoDB URI. make sure to change the values according to your setup.</p>
<p>Now go back to your index.js file (or the file in which your app instance is initialised) and add the following line at the beginning of the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (process.env.ENV === <span class="hljs-string">'dev'</span>) <span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config()
</code></pre>
<p>This loads the .env file in our project if we’re in the development environment. We can access each environment variable using <code>process.env.&lt;variable\_name&gt;</code>.</p>
<p>The dotenv package will look for the .env file in our project when the config method is invoked.</p>
<p>Placing this at the top of the entry point file ensures the environment variables are available to the entire application when we decide to go with a modular approach with our route organisation.</p>
<p>Now import mongoose:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>)

Create a mongoose connection by inserting the following code before the route definitions:

<span class="hljs-keyword">const</span> connection = mongoose.connect(process.env.MONGO_URI, {
  <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>
})

<span class="hljs-comment">/* Display message in the console if the connection is successful. */</span>
mongoose.connection.once(<span class="hljs-string">'open'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'connected!'</span>)
})
</code></pre>
<h2 id="heading-models">Models</h2>
<p>Our mongoose connection has been established. The next step is to define our models. Models are object representations of the documents that will reside in our database.</p>
<p>Models in mongoose require a schema. A schema specifies the structure of the document.</p>
<p>If you’re familiar with NoSQL databases, particularly MongoDB, you might be aware that one of the benefits is that the schema is dynamic. Meaning you can add new fields to a document on the fly upon creation/update.</p>
<p>This may be a good idea depending on your use case but mongoose requires schemas in order to define the shape of the documents in the collection. This ensures we have consistency in a collection and a reference point for what properties are contained in each document.</p>
<p>Let’s begin setting up our models by creating a folder in the root of our project named ‘model’. Next, create a file inside this folder called ‘User.js’. It’s a good idea to separate models into their own files.</p>
<p>Inside User.js, add the following code:</p>
<pre><code class="lang-javascript">
<span class="hljs-keyword">const</span> { Schema, model } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>)

<span class="hljs-keyword">var</span> userSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">name</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.String,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'You must provide a name'</span>]
  },
  <span class="hljs-attr">email</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.String,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'Email address is required'</span>]
  },
  <span class="hljs-attr">username</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.String,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'Username is required'</span>]
  },
  <span class="hljs-attr">password</span>: {
    <span class="hljs-attr">type</span>: Schema.Types.String,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'You must provide a password'</span>]
  }
})

<span class="hljs-keyword">const</span> User = model(<span class="hljs-string">'User'</span>, userSchema)

<span class="hljs-built_in">module</span>.exports = User
</code></pre>
<p>Let’s walk through the contents of this file:</p>
<ul>
<li>Import Schema and model from mongoose.</li>
<li>Create a schema instance that defines the structure of the user document in the User collection.</li>
<li>Create a model instance and pass it the collection name and schema.</li>
<li>Export the user model for use in routes.</li>
</ul>
<p>Now create an index file within the models directory. This file will import all of the models from its sibling files and export them in an object. We’re doing this to reduce the number of require statements in other files when importing models.</p>
<p>You can certainly import models directly from their respective files, but this is definitely a cleaner way of doing it.</p>
<p>The contents of this index.js file should look like this for now:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> User = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./User'</span>)

<span class="hljs-built_in">module</span>.exports = {
  User
}
</code></pre>
<h2 id="heading-using-the-models">Using the models</h2>
<p>It’s time to test if this works. We’re going to insert a user into the collection if the collection is empty and retrieve the users in the collection otherwise.</p>
<p>In the app entry file, import the User model from the models index file as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import models</span>
<span class="hljs-keyword">const</span> { User } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./models'</span>)

Update the home route to the following:

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">await</span> User.find({})
  <span class="hljs-keyword">if</span> (users.length) {
    <span class="hljs-comment">/* Log users if users exists. */</span>
    <span class="hljs-built_in">console</span>.log(users)
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">/* If no users exist, save new user and log saved user on the console. */</span>
    <span class="hljs-keyword">let</span> newUser = <span class="hljs-keyword">new</span> User({
      <span class="hljs-attr">name</span>: <span class="hljs-string">'Kelvin Mwinuka'</span>,
      <span class="hljs-attr">email</span>: <span class="hljs-string">'email@kelvinmwinuka.com'</span>,
      <span class="hljs-attr">username</span>: <span class="hljs-string">'kelvin'</span>,
      <span class="hljs-attr">password</span>: <span class="hljs-string">'password'</span>
    })
    <span class="hljs-keyword">let</span> savedUser = <span class="hljs-keyword">await</span> newUser.save()
    <span class="hljs-built_in">console</span>.log(savedUser)
  }
  res.render(<span class="hljs-string">'home.html'</span>)
})
</code></pre>
<p>Navigate to this route in the browser and you should notice that for the first time, a single object is printed to the console:</p>
<pre><code>{
  <span class="hljs-attribute">_id</span>: <span class="hljs-number">5</span>fdab492561efb3e9a2c56c7,
  <span class="hljs-attribute">name</span>: <span class="hljs-string">'Kelvin Mwinuka'</span>,
  <span class="hljs-attribute">email</span>: <span class="hljs-string">'email@kelvinmwinuka.com'</span>,
  <span class="hljs-attribute">username</span>: <span class="hljs-string">'kelvin'</span>,
  <span class="hljs-attribute">password</span>: <span class="hljs-string">'password'</span>,
  <span class="hljs-attribute">__v</span>: <span class="hljs-number">0</span>
}
</code></pre><p>When you refresh the page, the results should now be as follows:</p>
<pre><code>[
  {
    <span class="hljs-attr">_id:</span> <span class="hljs-string">5fdab492561efb3e9a2c56c7</span>,
    <span class="hljs-attr">name:</span> <span class="hljs-string">'Kelvin Mwinuka'</span>,
    <span class="hljs-attr">email:</span> <span class="hljs-string">'email@kelvinmwinuka.com'</span>,
    <span class="hljs-attr">username:</span> <span class="hljs-string">'kelvin'</span>,
    <span class="hljs-attr">password:</span> <span class="hljs-string">'password'</span>,
    <span class="hljs-attr">__v:</span> <span class="hljs-number">0</span>
  }
]
</code></pre><p>Notice this is an array of current documents and no new user is created/saved.</p>
<p>That’s it. We’ve successfully set up mongoose and we’re ready to start persisting data in our MongoDB database!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we’ve gone over connecting our express application to a MongoDB database, creating mongoose models and using those models to save data into our database.</p>
<p>In the next article, I will be going over <a target="_blank" href="https://kelvinmwinuka.com/how-to-create-registration-authentication-with-express-passportjs/">user registration and authentication using Passport JS</a>.</p>
<p>You can track the progress of this project on <a target="_blank" href="https://github.com/kelvinmwinuka/express-tutorial">Github</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Set Up Nunjucks with ExpressJS]]></title><description><![CDATA[When building a web app without a dedicated front-end framework like ReactJS, Templating engines (e.g. Blade, Nunjucks) are incredibly useful.
Though they aren’t entirely necessary, they definitely help create more dynamic pages with cleaner HTML cod...]]></description><link>https://kelvinmwinuka.com/set-up-nunjucks-with-expressjs</link><guid isPermaLink="true">https://kelvinmwinuka.com/set-up-nunjucks-with-expressjs</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[Express]]></category><category><![CDATA[code]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Wed, 16 Dec 2020 02:33:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649113996342/K62As1zl0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When building a web app without a dedicated front-end framework like ReactJS, Templating engines (e.g. Blade, Nunjucks) are incredibly useful.</p>
<p>Though they aren’t entirely necessary, they definitely help create more dynamic pages with cleaner HTML code.</p>
<p>Before getting into JavaScript, Flask and Django were my preferred choices for building web applications. Coming from that background, I got very used to the Jinja2 engine.</p>
<p>When I switched to using Express for web app development, I wanted a solution that would have similar syntax and features to Jinja2. Fortunately, Nunjucks is exactly that. This is a templating engine that is heavily inspired by Jinja2.</p>
<p>In this article, I will walk you through the Nunjucks setup for ExpressJS. This is a fairly simple and straightforward process.</p>
<h2 id="heading-setup">Setup</h2>
<p>First, create an empty folder. Navigate into the folder and run the following command to initialise npm:</p>
<p><code>npm init</code></p>
<p>Follow all the prompts to setup your project.</p>
<p>Once the setup process has completed, you should have a package.json file in the root of your project.</p>
<h3 id="heading-installing-packages">Installing packages</h3>
<p>Next, run the following command to install express and nunjucks.</p>
<p><code>npm install express nunjucks</code></p>
<h3 id="heading-defining-the-entry-point">Defining the entry point</h3>
<p>Now create the file that will be the entry point of our application. I name this file index.js and place it at the root of my project.</p>
<p>The contents of <code>index.js</code> are as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)
<span class="hljs-keyword">const</span> nunjucks = <span class="hljs-built_in">require</span>(<span class="hljs-string">'nunjucks'</span>)

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

nunjucks.configure(<span class="hljs-string">'views'</span>, {
  <span class="hljs-attr">autoescape</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">express</span>: app
})

app.set(<span class="hljs-string">'view engine'</span>, <span class="hljs-string">'html'</span>)

<span class="hljs-keyword">const</span> PORT = <span class="hljs-string">'8000'</span>

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.render(<span class="hljs-string">'home.html'</span>)
})

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Listening on port <span class="hljs-subst">${PORT}</span>...`</span>)
})
</code></pre>
<p>Let’s take a moment to go through what’s happening in this file:</p>
<ul>
<li>Require the express and nunjucks packages.</li>
<li>Create an instance of express and assign it to a variable called ‘app’.</li>
<li>Configuring nunjucks: The first parameter is the path to the template folder. The second parameter is an object containing configuration options. <a target="_blank" href="https://mozilla.github.io/nunjucks/templating.html#autoescaping">Autoescape</a> makes sure all output to templates are escaped before display (recommended). You can manually mark the output as safe. The express property requires an instance of an express app.</li>
<li>Set the port number. We’ll use this when starting the application later.</li>
<li>Create a ‘get’ route at ‘/’ and return a response that simply renders the template home.html.</li>
<li>Listen for connections on the specified port.</li>
</ul>
<h3 id="heading-creating-the-templates">Creating the templates</h3>
<p>At the moment if you try to load the application, you’ll get an error because we haven’t created the template that we’re trying to render yet.</p>
<p>Remember that we set the path to templates as ‘views’. Nunjucks will look for the ‘views’ folder in the same directory as the script that runs the configuration.</p>
<p>If you have your template folder in another directory or have named it something different like ‘templates’, make sure you configure the path correctly.</p>
<p>In this case, we have to create a folder called ‘views’ in the root of our project (because this is where index.js resides).</p>
<p>Inside the views folder, create a base.html template. This is the template that will be inherited by other templates. It allows us to define certain UI elements, styles and scripts only once and have them displayed/imported on every template.</p>
<p>This is where we’d define navigation bars and page footers.</p>
<p>The contents of base.html are as follows:</p>
<pre><code><span class="hljs-operator">&lt;</span><span class="hljs-operator">!</span>DOCTYPE html<span class="hljs-operator">&gt;</span>
<span class="hljs-operator">&lt;</span>html<span class="hljs-operator">&gt;</span>
  <span class="hljs-operator">&lt;</span>head<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>meta charset<span class="hljs-operator">=</span><span class="hljs-string">"utf-8"</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>meta http<span class="hljs-operator">-</span>equiv<span class="hljs-operator">=</span><span class="hljs-string">"X-UA-Compatible"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"IE=edge"</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>title<span class="hljs-operator">&gt;</span>{{ title }}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>title<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>meta name<span class="hljs-operator">=</span><span class="hljs-string">"description"</span> content<span class="hljs-operator">=</span><span class="hljs-string">""</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>meta name<span class="hljs-operator">=</span><span class="hljs-string">"viewport"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"width=device-width, initial-scale=1"</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>link rel<span class="hljs-operator">=</span><span class="hljs-string">"stylesheet"</span> href<span class="hljs-operator">=</span><span class="hljs-string">""</span><span class="hljs-operator">&gt;</span>
  <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>head<span class="hljs-operator">&gt;</span>
  <span class="hljs-operator">&lt;</span>body<span class="hljs-operator">&gt;</span>
    {<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> content <span class="hljs-operator">%</span>}{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}
    <span class="hljs-operator">&lt;</span>script src<span class="hljs-operator">=</span><span class="hljs-string">""</span> async defer<span class="hljs-operator">&gt;</span><span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>script<span class="hljs-operator">&gt;</span>
  <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>body<span class="hljs-operator">&gt;</span>
<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>html<span class="hljs-operator">&gt;</span>
</code></pre><p>We’ve defined a content block that will be overridden by the child templates. This is where the child templates will place their respective content.</p>
<p>Next, create a home.html template that extends base.html and displays a simple header in the content block.</p>
<pre><code>{<span class="hljs-operator">%</span> extends <span class="hljs-string">'base.html'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> set title <span class="hljs-operator">=</span> <span class="hljs-string">'Home'</span> <span class="hljs-operator">%</span>}

{<span class="hljs-operator">%</span> <span class="hljs-built_in">block</span> content <span class="hljs-operator">%</span>}
  <span class="hljs-operator">&lt;</span>h1<span class="hljs-operator">&gt;</span>Welcome home<span class="hljs-operator">!</span><span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">&gt;</span>
{<span class="hljs-operator">%</span> endblock <span class="hljs-operator">%</span>}
</code></pre><p>Now that we’ve created the templates, we’re able to load the home page. Visit localhost at the specified port and you should see that your app is up and running!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we’ve covered setting up the nunjucks templating engine with an express web application. In the next article, I will write about <a target="_blank" href="https://kelvinmwinuka.com/how-to-set-up-mongoose-with-expressjs/">connecting an express application to MongoDB using mongoose</a> so we can persist data.</p>
<p>You can track the progress of this project on <a target="_blank" href="https://github.com/kelvinmwinuka/express-tutorial">Github</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Periodically Pull Financial Data With Python and Cron]]></title><description><![CDATA[I got the idea for this article while experimenting with python automation. I decided to create a simple tutorial on automating tasks periodically using python and cronjobs.
Keep in mind that this demonstration is by no means exhaustive. However, the...]]></description><link>https://kelvinmwinuka.com/periodically-pull-financial-data-with-python-and-cron</link><guid isPermaLink="true">https://kelvinmwinuka.com/periodically-pull-financial-data-with-python-and-cron</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Python]]></category><category><![CDATA[cron]]></category><category><![CDATA[cronjob]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Sun, 11 Oct 2020 19:11:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649192832610/M4f07SqeQ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I got the idea for this article while experimenting with python automation. I decided to create a simple tutorial on automating tasks periodically using python and cronjobs.</p>
<p>Keep in mind that this demonstration is by no means exhaustive. However, the core concepts conveyed will be applicable in other use cases.</p>
<p>First, here’s an overview of the python script that will be running periodically on my machine.</p>
<p>I will explain each section of this script in more depth. If you understand this script sufficiently, feel free to skip ahead to the scheduling section of this article.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> yagmail
<span class="hljs-keyword">import</span> datetime
<span class="hljs-keyword">import</span> yfinance <span class="hljs-keyword">as</span> yf
<span class="hljs-keyword">from</span> dotenv <span class="hljs-keyword">import</span> load_dotenv

load_dotenv()

FILE_PATH = os.getenv(<span class="hljs-string">'FILE_PATH'</span>)
DEV_EMAIL = os.getenv(<span class="hljs-string">'DEV_EMAIL'</span>)
DEV_PASSWORD = os.getenv(<span class="hljs-string">'DEV_PASSWORD'</span>)
NOTIFICATION_EMAIL = os.getenv(<span class="hljs-string">'NOTIFICATION_EMAIL'</span>)

yesterday = datetime.date.today() - datetime.timedelta(days=<span class="hljs-number">1</span>)

data = yf.download(
    tickers=<span class="hljs-string">"AAPL MSFT"</span>,
    group_by=<span class="hljs-string">"ticker"</span>,
    start=yesterday,
    end=yesterday
)[:<span class="hljs-number">1</span>]

records = {}

<span class="hljs-keyword">try</span>:
    <span class="hljs-keyword">with</span> open(FILE_PATH, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> file:
        records = json.load(file)
<span class="hljs-keyword">except</span> (FileNotFoundError, json.JSONDecodeError) <span class="hljs-keyword">as</span> e:
    <span class="hljs-keyword">pass</span>

parsed = {}

<span class="hljs-keyword">for</span> ticker, column <span class="hljs-keyword">in</span> data:
    parsed[ticker] = {<span class="hljs-string">"Date"</span>: str(yesterday)} <span class="hljs-keyword">if</span> ticker <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> parsed <span class="hljs-keyword">else</span> parsed[ticker]
    parsed[ticker][column] = int(data[ticker][column]) <span class="hljs-keyword">if</span> ticker == <span class="hljs-string">'Volume'</span> <span class="hljs-keyword">else</span> float(data[ticker][column])

<span class="hljs-keyword">for</span> ticker <span class="hljs-keyword">in</span> parsed:
    <span class="hljs-keyword">if</span> ticker <span class="hljs-keyword">in</span> records:
        records[ticker].append(parsed[ticker])
    <span class="hljs-keyword">else</span>:
        records[ticker] = [parsed[ticker]]

<span class="hljs-keyword">with</span> open(FILE_PATH, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> file:
    json.dump(records, file, indent=<span class="hljs-number">2</span>)

yagmail.SMTP(
    DEV_EMAIL,
    DEV_PASSWORD
).send(
    to=NOTIFICATION\_EMAIL,
    subject=<span class="hljs-string">'Daily Financial Data'</span>,
    contents=<span class="hljs-string">'Your daily financial record update is complete!'</span>
)
</code></pre>
<h2 id="heading-script-breakdown">Script breakdown</h2>
<p>Let’s talk about the standout packages that are employed in this script:</p>
<ol>
<li><a target="_blank" href="https://github.com/kootenpv/yagmail">yagmail</a> is a Gmail/SMTP client package that I use to send emails. Not a vital feature but I will explain my reasons for using it later in the article. There are other ways to send emails using python, this is my preferred way of doing it when I simply need to send an email with code that can fit in one line</li>
<li><a target="_blank" href="https://pypi.org/project/python-dotenv/">dotenv (python-dotenv)</a> allows us to load environment variables from a .env file in our project. This means we don’t have to fiddle with our system’s environment variables directly.</li>
<li><a target="_blank" href="https://pypi.org/project/yfinance/">yfinance</a> is the library of choice in accessing Yahoo financial data.</li>
</ol>
<pre><code class="lang-python">load_dotenv()

 <span class="hljs-comment"># Path to JSON file used for storage</span>
FILE_PATH = os.getenv(<span class="hljs-string">'FILE_PATH'</span>) 

DEV_EMAIL = os.getenv(<span class="hljs-string">'DEV_EMAIL'</span>)
DEV_PASSWORD = os.getenv(<span class="hljs-string">'DEV_PASSWORD'</span>)

<span class="hljs-comment"># Email to notify when the task is completed</span>
NOTIFICATION_EMAIL = os.getenv(<span class="hljs-string">'NOTIFICATION_EMAIL'</span>)
</code></pre>
<p>Our first action is loading the environment variables from the .env file using the load_dotenv() function. This function looks for a .env file in the current and parent directories.</p>
<p>Once the file is found, the variables are loaded and can be accessed like any system environment variable using the os package.</p>
<pre><code class="lang-python">yesterday = datetime.date.today() - datetime.timedelta(days=<span class="hljs-number">1</span>)

data = yf.download(
    tickers=<span class="hljs-string">"AAPL MSFT"</span>,
    group_by=<span class="hljs-string">"ticker"</span>,
    start=yesterday,
    end=yesterday
)[:<span class="hljs-number">1</span>]
</code></pre>
<p>Now for the exciting part. Here, I’m using yfinance to download Microsoft and Apple data from the previous day. You can read more about this package <a target="_blank" href="https://pypi.org/project/yfinance/">here</a>.</p>
<p>The object returned by the download method is a pandas DataFrame. I make sure to truncate it to only retrieve the first row of the results. This is only a safety measure, as Only one row is expected anyway.</p>
<pre><code class="lang-python">records = {}

<span class="hljs-keyword">try</span>:
    <span class="hljs-keyword">with</span> open(FILE_PATH, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> file:
        records = json.load(file)
<span class="hljs-keyword">except</span> (FileNotFoundError, json.JSONDecodeError) <span class="hljs-keyword">as</span> e:
    <span class="hljs-keyword">pass</span>
</code></pre>
<p>This section of the code loads the records that we already have. The records are currently stored in a JSON file specified by <code>FILE_PATH</code>.</p>
<p>If you’re downloading a lot of data, I would advise you to use a database such as MongoDB or MySQL.</p>
<pre><code class="lang-python">parsed = {}

<span class="hljs-keyword">for</span> ticker, column <span class="hljs-keyword">in</span> data:
    parsed[ticker] = {<span class="hljs-string">"Date"</span>: str(yesterday)} <span class="hljs-keyword">if</span> ticker <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> parsed <span class="hljs-keyword">else</span> parsed[ticker]
    parsed[ticker][column] = int(data[ticker][column]) <span class="hljs-keyword">if</span> ticker == <span class="hljs-string">'Volume'</span> <span class="hljs-keyword">else</span> float(data[ticker][column])

<span class="hljs-keyword">for</span> ticker <span class="hljs-keyword">in</span> parsed:
    <span class="hljs-keyword">if</span> ticker <span class="hljs-keyword">in</span> records:
        records[ticker].append(parsed[ticker])
    <span class="hljs-keyword">else</span>:
        records[ticker] = [parsed[ticker]]

<span class="hljs-keyword">with</span> open(FILE_PATH, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> file:
    json.dump(records, file, indent=<span class="hljs-number">2</span>)
</code></pre>
<p>In this section, I parse the data manually into a Python dictionary. I chose to do this because I’m more comfortable with basic Python dictionaries than pandas DataFrames.</p>
<p>If you’re more comfortable dealing with DataFrames, it’s possible to export the data to a JSON file directly.</p>
<p>After parsing the data, we append it to the records dictionary and then overwrite the JSON file with the new records data.</p>
<pre><code class="lang-python">yagmail.SMTP(
    DEV_EMAIL,
    DEV_PASSWORD
).send(
    to=NOTIFICATION_EMAIL,
    subject=<span class="hljs-string">'Daily Financial Data'</span>,
    contents=<span class="hljs-string">'Your daily financial record update is complete!'</span>
)

Finally, we use yagmail to send an email notification at the end of the script to notify us that the script has been executed.

<span class="hljs-comment">## Scheduling execution</span>

<span class="hljs-comment">### Using loops</span>

The next challenge <span class="hljs-keyword">is</span> scheduling the execution of this script. One option would be to wrap everything <span class="hljs-keyword">in</span> an endless <span class="hljs-keyword">while</span> loop <span class="hljs-keyword">and</span> sleep at the end of the loop. This would look like this:

```python
<span class="hljs-keyword">import</span> time
....
<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
    <span class="hljs-comment"># Execute script here</span>
    time.sleep(<span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">24</span>)  <span class="hljs-comment"># Seconds to sleep</span>
</code></pre>
<p>The issue with this approach is that we have to make sure the script is always running. This means we have to run it manually and leave it running in the background. This defeats the purpose of automation as the script will not run if we ever forget to execute it.</p>
<p>Another problem with this script is that it’s not optimal. We’re sleeping for 24 hours! Unless you have a very specific scenario where this is necessary, if you ever find yourself sleeping for 24 hours, it’s time to consider cronjobs (or see a doctor!).</p>
<h3 id="heading-using-cronjobs">Using cronjobs</h3>
<p>Cronjobs are the more effective solution for scheduling the execution of this script. There are 2 ways to achieve this:</p>
<ol>
<li>Create a bash script that executes the python script</li>
<li>Execute the python script directly (recommended)</li>
</ol>
<p>Before implementing either of these approaches. We first have to find out the location of the python interpreter on our system. On macOS or Linux, you can find this out using the “which” command followed by the python command.</p>
<pre><code>$ which python3
<span class="hljs-operator">/</span>Library<span class="hljs-operator">/</span>Frameworks<span class="hljs-operator">/</span>Python.framework/Versions<span class="hljs-operator">/</span><span class="hljs-number">3.7</span><span class="hljs-operator">/</span>bin<span class="hljs-operator">/</span>python3
</code></pre><p>In this case, I’m specifically looking for the python3 interpreter as I want to execute this script with python 3. On my machine, the “python” command maps to python 2.7.</p>
<h4 id="heading-execute-through-a-bash-script">Execute through a bash script</h4>
<pre><code><span class="hljs-meta">#!/bin/bash</span>

/Library/Frameworks/Python.framework/Versions/3.7/bin/python3 <span class="hljs-variable">${HOME}</span>/&lt;path-to-python script&gt;
</code></pre><p>The code above is contained in a bash script that will execute the python script. The bash script basically contains the command we would input on the terminal but with some key differences.</p>
<p>On the terminal we would run this script from the project root as follows:</p>
<p><code>$ python3 script.py</code></p>
<p>On the bash script above we do something similar except instead of the python3 command, we specify the full path of the python3 interpreter. The second part of the command is the full path of the script we want to run.</p>
<p>Keep in mind that the paths to the interpreter and the script are relative from the system root and <strong><em>NOT</em></strong> the project root or the user’s home.</p>
<p>Make bash script executable with the following command:</p>
<p><code>chmod +x &lt;path-to-bash-script&gt;</code></p>
<p>Open crontab in edit mode and add a command to execute the bash script we created. I’ve used the @daily schedule here which executes the given command everyday at midnight.</p>
<p>If you’d like to fine-tune the exact hour of the day that you’d like to execute this command, you can <a target="_blank" href="https://www.tweaking4all.com/os-tips-and-tricks/macosx-tips-and-tricks/edit-crontab/">read this article</a> to learn how to achieve that.</p>
<pre><code>crontab <span class="hljs-operator">-</span>e

@daily .&lt;path<span class="hljs-operator">-</span>to<span class="hljs-operator">-</span>bash<span class="hljs-operator">-</span>script<span class="hljs-operator">&gt;</span>
</code></pre><h4 id="heading-execute-python-script-directly">Execute python script directly</h4>
<p>The second alternative is directly executing the python script from cron. In order to do this, we have to go through the same steps to prepare the python script as we did with the bash script.</p>
<p>We have to make the python script executable first. Navigate to the script’s directory in the terminal and then run the following command:</p>
<p><code>chmod +x script.py</code></p>
<p>Once you’ve done that, open the script itself and add a similar line to this at the very top of the file:</p>
<p><code>_#!/Library/Frameworks/Python.framework/Versions/3.7/bin/python3_</code></p>
<p>This is called a hashbang or shebang. It is made up of 2 parts: “#!” followed by the location of the interpreter you want to use. This is the result you get when you run the “which python3” command.</p>
<p>A hashbang tells the system how to execute the file. You will notice we have a hashbang at the beginning of the bash script as well. This points to the bash interpreter.</p>
<p>The benefit of using a hashbang is that we don’t have to preface the script name with the interpreter command when executing it in the terminal.</p>
<p>So instead of:</p>
<p><code>$ python3 script.py</code></p>
<p>We can do:</p>
<p><code>$ ./script.py</code></p>
<p>Once we’ve done that, we can edit the crontab entry to execute the file directly using the following code:</p>
<pre><code>@daily <span class="hljs-operator">/</span>Library<span class="hljs-operator">/</span>Frameworks<span class="hljs-operator">/</span>Python.framework/Versions<span class="hljs-operator">/</span><span class="hljs-number">3.7</span><span class="hljs-operator">/</span>bin<span class="hljs-operator">/</span>python3 ${HOME}<span class="hljs-operator">/</span><span class="hljs-operator">&lt;</span>path<span class="hljs-operator">-</span>to<span class="hljs-operator">-</span>python script<span class="hljs-operator">&gt;</span>
</code></pre><p>Before you save this, remember that we have the hashbang at the top of the script, so we don’t have to specify the interpreter in the crontab line. Let’s update this entry to the following:</p>
<p><code>@daily .${HOME}/&lt;path-to-python script&gt;</code></p>
<p>Hashbangs help us keep our crontab entries much cleaner.</p>
<p>Now the script will run at the scheduled times and specified intervals.</p>
]]></content:encoded></item><item><title><![CDATA[Optimise React with useMemo and React.memo]]></title><description><![CDATA[There comes a time when we have to worry about more than just making sure our applications work, but that they work optimally. When using react, we have certain tools at our disposal to make sure our applications are optimised. In this article, I wil...]]></description><link>https://kelvinmwinuka.com/optimise-react-with-usememo-and-reactmemo</link><guid isPermaLink="true">https://kelvinmwinuka.com/optimise-react-with-usememo-and-reactmemo</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[React]]></category><category><![CDATA[optimisation]]></category><category><![CDATA[create-react-app]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Wed, 07 Oct 2020 18:45:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649191573938/gLdjK8btc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There comes a time when we have to worry about more than just making sure our applications work, but that they work optimally. When using react, we have certain tools at our disposal to make sure our applications are optimised. In this article, I will demonstrate how to achieve this using React.memo and the useMemo hook.</p>
<h2 id="heading-rendering">Rendering</h2>
<p>Before we dive into the use of these methods, let’s first establish a basic understanding of how react components are re-rendered.</p>
<p>Components in react will re-render when there is a change in their state and/or their props.</p>
<p>Child components will also re-render whenever their parent component is re-rendered. Even when the child’s state/props haven’t changed.</p>
<h2 id="heading-memoization">Memoization</h2>
<p>The second concept we need to understand is memoization as it is central to how React.memo and useMemo work.</p>
<p>Memoization is the practice of caching the results/outputs of expensive functions or operations and returning these cached results the next time identical input is provided.</p>
<p>This optimises our program by allowing us to skip costly computations entirely if the provided inputs have already been used before.</p>
<p>React.memo and useMemo make use of this concept to determine whether components should be re-rendered or values should be re-computed respectively.</p>
<h2 id="heading-usememo">useMemo</h2>
<p>Let’s start with useMemo. This is a react hook that we use within functional components in order to memoize values (especially from expensive functions).</p>
<p>useMemo takes 2 parameters: a function that returns a value to be memoized, and an array of dependencies. Dependencies are the variables that determine whether the memoized value should be recomputed.</p>
<p>In other words, as long as the dependencies haven’t changed, do not re-run the function to update the memoized value. Since the dependencies are contained in an array, you can have multiple dependencies for useMemo.</p>
<p>Do note only ONE of the dependencies in the dependency array needs to change in order to trigger the execution of the function/operation.</p>
<p>Now let’s look at an example of useMemo in action.</p>
<p>First, let’s write some simple application code that does not make use of useMemo.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> User = <span class="hljs-function">(<span class="hljs-params">{ greeting }</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(greeting)
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{greeting}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>Here we have a User component that simply renders a string contained in the greeting prop. This string is also logged to the console. You will see in just a moment why this is important.</p>
<p>Next, let’s define the App component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">'Michael'</span>)

  <span class="hljs-keyword">const</span> greet = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`Hello, <span class="hljs-subst">${name}</span>`</span>
  }

  <span class="hljs-keyword">const</span> greeting = greet()

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{(event)</span> =&gt;</span> {
          event.preventDefault()
          const data = new FormData(event.target)
          setName(data.get('name'))
        }}&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'name'</span>/&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'submit'</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'Change name'</span>/&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">User</span> <span class="hljs-attr">greeting</span>=<span class="hljs-string">{greeting}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>The app component contains a function called greet that performs the unfathomably slow operation of returning a greeting based on the current name in the state (which is defaulted to ‘Michael’).</p>
<p>We have a greeting constant that is computed by calling the greet function. This is the string that is passed to the User component.</p>
<p>We also have a form that when submitted, updates the name in the App component’s state.</p>
<p>When we run this application, nothing out of the ordinary happens. Submitting the form updates the name, which causes App components to re-render. This causes the greeting to be updated and finally the User component re-renders with the updated prop.</p>
<p>For the sake of this example, let’s imagine that the greet function is a very expensive function that eventually returns our greeting. How can we make use of useMemo to prevent it from being executed on every re-render?</p>
<p>We can memoize the greeting by updating it to the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> greeting = useMemo( <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> greet()
  }, [])
</code></pre>
<p>Now we only compute the value of <code>greeting</code> when the dependencies update.</p>
<p>But hold on a minute, the dependency array is empty. What happens in this case?</p>
<p>If you’re familiar with the useEffect hook, you’ll know that to mimic the functionality of componentDidMount, we pass an empty dependency array so that it executes once upon the first render.</p>
<p>This is exactly what happens here. This value will be computed once on the first render and will be the same for all subsequent renders. No matter how many times the name changes, the value of greeting will not change.</p>
<p>Now let’s use it a little more practically. We want to re-compute the greeting every time name changes. But because doing this basically renders useMemo useless, let’s add a condition to the name update:</p>
<p>We will only update the name in the state if the submitted name contains the string ‘Kelvin’ in it. So let’s update the form’s onSubmit function to the following:</p>
<pre><code><span class="hljs-operator">&lt;</span>form onSubmit<span class="hljs-operator">=</span>{(<span class="hljs-function"><span class="hljs-keyword">event</span>) =&gt; </span>{
          <span class="hljs-keyword">event</span>.preventDefault()
          const data <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> FormData(<span class="hljs-keyword">event</span>.target)

          let name <span class="hljs-operator">=</span> data.get(<span class="hljs-string">'name'</span>)
          <span class="hljs-keyword">if</span> (name.toLowerCase().includes(<span class="hljs-string">'kelvin'</span>)) setName(name)

          setCount(count <span class="hljs-operator">+</span> <span class="hljs-number">1</span>)
        }}<span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span>input <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">'text'</span> name<span class="hljs-operator">=</span><span class="hljs-string">'name'</span><span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span>input <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">'submit'</span> value<span class="hljs-operator">=</span><span class="hljs-string">'Change name'</span><span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>form<span class="hljs-operator">&gt;</span>
</code></pre><p>Now we’re conditionally updating the name so it makes sense to memoize the greeting depending on the name, since it’s not updating on every submit. I’ve also added a count variable in state that increments every time the form is submitted just to force the App component to re-render regardless of wether name is updated.</p>
<p>Now we can update the useMemo hook to the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> greeting = useMemo( <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> greet()
  }, [name])
</code></pre>
<p>The only difference here, is that we’ve added the dependency of name to it. Every time name changes, only then will the greeting be recomputed.</p>
<p>When we run this app, we can see that on the User component, the greeting doesn’t change when the input doesn’t contain ‘Kelvin’ in it. On those instances, the memoized greeting is still being used.</p>
<p>Remember that console.log statement we had in our User component? If you look at your console, you’ll notice that the greeting gets printed whether the memoized value is being used, or a new value is calculated.</p>
<p>It appears we are preventing the greeting from being re-computed on certain instances, but the component is always being re-rendered. Why is this?</p>
<p>The answer is simple: Even though the prop doesn’t change in those instances, the component still gets re-rendered simply because the parent has been re-rendered thanks to the count increment.</p>
<p>So what if the rendering of a child component is in itself expensive and we want to make sure we prevent re-rendering when props haven’t changed even if the parent has re-rendered?</p>
<p>This is where React.memo comes in!</p>
<h2 id="heading-reactmemo">React.memo</h2>
<p>As mentioned before, React.memo prevents a component from re-rendering unless the props passed to it have changed.</p>
<p>To put this into practice, let’s update the User component to the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> User = React.memo(<span class="hljs-function">(<span class="hljs-params">{ greeting }</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'User component rendered'</span>)
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{greeting}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
})
</code></pre>
<p>We have wrapped the component with React.memo. We’ve also updated the log statement to let us know when the User component has rendered, just for extra clarity.</p>
<p>Add the following statement in the App components body before the return statement in order to indicate whenever the App component has been re-rendered:</p>
<p>console.log('App component rendered')</p>
<p>Run the application and you will notice that ‘Hello, Michael’ is displayed on the page. When you enter any name besides Kelvin, the name is not updated in state. Count is always updated in state just as before.</p>
<p>The difference this time is that the User component will not be re-rendered as you can see from the console logs.</p>
<p>Why is this? Well, when the name is updated to any value other than ‘Kelvin’ the value of greeting is not updated. The App component still re-renders because the value of count is updated.</p>
<p>This re-rendering of the App component does not affect the child component User as React.memo prevents it from re-rendering due to the fact that the value of the props (in this case, greeting) hasn’t changed.</p>
<p>Change the name to ‘Kelvin’ and you’ll notice that this time, the name is updated in App state, which causes the value of greeting to be updated, which in turn allows the User component to be re-rendered.</p>
<h2 id="heading-manual-render">Manual render</h2>
<p>As we’ve seen, React.memo prevents a component from re-rendering when the props haven’t changed.</p>
<p>React.memo uses shallow comparison to compare the previous set of props to the next incoming set of props in order to determine whether the component should be re-rendered.</p>
<p>If shallow comparison is not sufficient for your needs, as props tend to contain very complex objects in larger applications, you can pass a second optional argument to React.memo: A function that takes previous props and next props as parameters which allows you to manually determine whether the component should be re-rendered.</p>
<p>To implement this, let’s update the User component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> User = React.memo(<span class="hljs-function">(<span class="hljs-params">{ greeting }</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'User component rendered'</span>)
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{greeting}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}, <span class="hljs-function">(<span class="hljs-params">prevProps, nextProps</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (prevProps === nextProps) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
})
</code></pre>
<p>Note that this function should return false if you <strong><em>DO</em></strong> want the component to re-render and true if you want to skip the re-render.</p>
]]></content:encoded></item><item><title><![CDATA[Manage React State with useReducer]]></title><description><![CDATA[React offers many ways to manage state. I have previously written about one such method, using redux. Another way to manage react state is through the use of the useReducer hook. In this article, I am going to demonstrate the usage of this hook along...]]></description><link>https://kelvinmwinuka.com/manage-react-state-with-usereducer</link><guid isPermaLink="true">https://kelvinmwinuka.com/manage-react-state-with-usereducer</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[code]]></category><category><![CDATA[webdevelopment]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[Redux]]></category><category><![CDATA[useReducer]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Fri, 21 Aug 2020 00:48:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649190867255/oNdLRehRo.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>React offers many ways to manage state. I have previously written about one such method, <a target="_blank" href="https://kelvinmwinuka.com/setting-up-redux-in-react/">using redux</a>. Another way to manage react state is through the use of the useReducer hook. In this article, I am going to demonstrate the usage of this hook along with some of its benefits.</p>
<h2 id="heading-the-problem-with-redux">The problem with redux</h2>
<p>If you haven’t read my article about <a target="_blank" href="https://kelvinmwinuka.com/setting-up-redux-in-react/">setting up redux in react,</a> I urge you to read it in order to get some context about what will be discussed in this article.</p>
<p>One of the main complaints against redux is that it requires a lot of boilerplate code to set up some fairly simple functionality. Having to include redux and react-redux increases the project’s bundle size. While the setup increases the complexity of the code.</p>
<p>This is through no fault of the redux developers. Redux is designed to be a general state management tool not exclusive to react. As a result, adapting it to any particular framework will always take a little more setup than something designed specifically for that framework.</p>
<p>Redux also has quite a steep learning curve for some beginners as it introduces paradigms that are hard to grasp. I’m not ashamed to say that it took me at least a couple of weeks of tinkering with redux before I felt comfortable with it.</p>
<p>The complexity of redux is justified for large projects. As the state becomes large and complex enough, the elaborate redux setup eventually pays for itself in such scenarios.</p>
<p>However, there are some projects that are not quite large enough to justify using redux but contain state too complex to manage using the much simpler useState hook. This is where useReducer comes in.</p>
<h2 id="heading-how-usereducer-solves-this-problem">How useReducer solves this problem</h2>
<p><code>useReducer</code> is a react hook that offers the basic functionality of state management that comes with redux, without all the boilerplate code in the setup.</p>
<p>For projects that have a need for a more sophisticated state management system but do not need the extra bells and whistles that come with redux, this is the (almost) perfect alternative.</p>
<p>Because <code>useReducer</code> is designed specifically for react, it is extremely easy to integrate into react components.</p>
<p>There are more issues that are addressed by the <code>useReducer</code> hook. I will discuss these later on in the advantages section of this article.</p>
<h2 id="heading-using-usereducer">Using useReducer</h2>
<p>Alright, enough talk, time to code! Here’s a demonstration of useReducer in action. For the sake of simplifying this tutorial, I have all the code written inside the App component.</p>
<p>Feel free to break the code down into separate components wherever you see fit. This will work regardless.</p>
<p>We are going to be using a functional component as react does not allow us to use hooks in class components. Make sure to import the useReducer hook:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useReducer } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

Now, <span class="hljs-keyword">let</span>’s make use <span class="hljs-keyword">of</span> the hook:

<span class="hljs-keyword">const</span> reducer = <span class="hljs-function">(<span class="hljs-params">state, action</span>) =&gt;</span> {
    <span class="hljs-keyword">switch</span> (action.type) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_LANGUAGE'</span>:
        <span class="hljs-keyword">return</span> { ...state, <span class="hljs-attr">languages</span>: [...state.languages, action.payload] }
      <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_FRAMEWORK'</span>:
        <span class="hljs-keyword">return</span> { ...state, <span class="hljs-attr">frameworks</span>: [...state.frameworks, action.payload] }
      <span class="hljs-keyword">case</span> <span class="hljs-string">'REMOVE_LANGUAGE'</span>:
        <span class="hljs-keyword">return</span> { ...state, <span class="hljs-attr">languages</span>: state.languages.filter( <span class="hljs-function">(<span class="hljs-params">language, index</span>) =&gt;</span> index !== action.payload ) }
      <span class="hljs-keyword">case</span> <span class="hljs-string">'REMOVE_FRAMEWORK'</span>:
        <span class="hljs-keyword">return</span> { ...state, <span class="hljs-attr">frameworks</span>: state.frameworks.filter( <span class="hljs-function">(<span class="hljs-params">framework, index</span>) =&gt;</span> index !== action.payload ) }
      <span class="hljs-attr">default</span>:
        <span class="hljs-keyword">return</span> state
    }
  }

  <span class="hljs-keyword">const</span> initialState = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Kelvin Mwinuka'</span>,
    <span class="hljs-attr">occupation</span>: <span class="hljs-string">'Software Developer'</span>,
    <span class="hljs-attr">languages</span>: [<span class="hljs-string">'JavaScript'</span>, <span class="hljs-string">'Python'</span>],
    <span class="hljs-attr">frameworks</span>: [<span class="hljs-string">'React'</span>, <span class="hljs-string">'Flask'</span>, <span class="hljs-string">'Express'</span>]
  }

  <span class="hljs-keyword">const</span> [state, dispatch] = useReducer(reducer, initialState)
</code></pre>
<p>If you’ve used redux before, a lot of this looks very familiar. In fact, the <code>useReducer</code> hook is basically redux lite.</p>
<p>First, we set up our reducer. This takes the current state and the dispatched action as parameters. Depending on the action type, we return the current state with the relevant data (payload) added to it.</p>
<p>Next, we set up our initial state. This can be an empty object. I’ve put some data in the initial state here because I’d like something to be displayed on the first render. If you do not need this behaviour, feel free to leave this empty.</p>
<p>Finally, we initialise state and dispatch using the <code>useReducer</code> hook. The 2 primary arguments are the reducer and initial state.</p>
<p>We will access state when displaying information while rendering but use dispatch in order to update the state.</p>
<p>Now let’s render the visual elements that will allow us to interact with our state:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>{state.name} <span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>({state.occupation})<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Languages<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
          {state.languages.map((language, index) =&gt; {
            return (
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>{language}<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> { dispatch({type: 'REMOVE_LANGUAGE', payload: index})} }&gt;
                  Remove
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            )
          })}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'language'</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'submit'</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'Add Language'</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Frameworks<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
          {state.frameworks.map((framework, index) =&gt; {
            return (
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>{framework}<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> { dispatch({type: 'REMOVE_FRAMEWORK', payload: index})} }&gt;
                  Remove
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            )
          })}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'framework'</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'submit'</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'Add Framework'</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
</code></pre>
<p>Here we create 2 lists that will display our languages and frameworks respectively. Each list has a corresponding form that allows us to add to it. Additionally, each list entry has a delete button that allows us to remove that particular item from its list.</p>
<p>Let’s start with the delete buttons as they have the simplest logic. Each delete button rendered is aware of its index in the list. When clicked, the button dispatches an action that has a type and payload (just like redux).</p>
<p>The payload is the index of the button/item. So how does the reducer know which list to remove from?</p>
<p>Well, the delete buttons in the languages list dispatch an action with type <code>REMOVE_LANGUAGE</code>. As you can see, the reducer listens for this specific action and then deletes the given index in the payload from the languages list.</p>
<p>The delete buttons in the frameworks list dispatch a similar action except they pass a type of <code>REMOVE_FRAMEWORK</code>. The reducer also listens for this type of action and responds by filtering out the item at the index passed in the payload.</p>
<p>Now let’s handle adding to the lists.</p>
<p>Both forms have the same submit handler. Let’s define this within our app component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault()
    <span class="hljs-keyword">const</span> formData = <span class="hljs-keyword">new</span> FormData(event.target)

    <span class="hljs-keyword">const</span> language = formData.get(<span class="hljs-string">'language'</span>)  <span class="hljs-comment">// Returns null if 'language' is not defined</span>
    <span class="hljs-keyword">const</span> framework = formData.get(<span class="hljs-string">'framework'</span>)  <span class="hljs-comment">// Returns null if 'framework' is not defined</span>

    <span class="hljs-keyword">const</span> action = language ? {<span class="hljs-attr">type</span>: <span class="hljs-string">'ADD_LANGUAGE'</span>, <span class="hljs-attr">payload</span>: language} : 
                  framework ? {<span class="hljs-attr">type</span>: <span class="hljs-string">'ADD_FRAMEWORK'</span>, <span class="hljs-attr">payload</span>: framework} : <span class="hljs-literal">null</span>

    dispatch(action)
    event.target.reset()
  }
</code></pre>
<p>Here we capture the form submit event (for both forms). We then create a <code>FormData</code> object from the form. Next, we capture the language and framework value from the FormData.</p>
<p>The language key will return null for the framework form and vice versa.</p>
<p>We then use nested ternary operators to determine what the action object should look like. The payload is the same for both forms, a string.</p>
<p>However, in order for the reducer to know which list to append the string to, we need a type of <code>ADD_LANGUAGE</code> in the case language is not null, and a type of <code>ADD_FRAMEWORK</code> when framework is not null.</p>
<p>Finally we dispatch the action we’ve just created and reset the target form.</p>
<h2 id="heading-working-with-child-components">Working with child components</h2>
<p>So the next question is: how do we work with child components?</p>
<p>In redux, we can pass in the relevant portion of the state down to child components along with actions. We can also directly connect each component to a relevant section of the state using mapStateToProps. Action creators can be mapped to props using mapDispatchToProps.</p>
<p>With <code>useReducer</code>, we need not pass anything other than the relevant portion of state and the dispatch function itself for action dispatching.</p>
<p>Let’s look at an example of this.</p>
<p>First, we will separate the languages and frameworks sections into their own components:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Languages = <span class="hljs-function">(<span class="hljs-params">{ languages, handleSubmit, dispatch }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Languages<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {languages.map((language, index) =&gt; {
          return (
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>{language}<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> { dispatch({ type: 'REMOVE_LANGUAGE', payload: index }) }}&gt;
                Remove
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          )
        })}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'language'</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'submit'</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'Add Language'</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">const</span> Frameworks = <span class="hljs-function">(<span class="hljs-params">{ frameworks, handleSubmit, dispatch }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Frameworks<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
          {frameworks.map((framework, index) =&gt; {
            return (
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>{framework}<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> { dispatch({ type: 'REMOVE_FRAMEWORK', payload: index }) }}&gt;
                  Remove
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            )
          })}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'framework'</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'submit'</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'Add Framework'</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>Now that we’ve extracted this code into separate components, we can update the App component’s JSX:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>{state.name} <span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>({state.occupation})<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Languages</span> <span class="hljs-attr">languages</span>=<span class="hljs-string">{state.languages}</span> <span class="hljs-attr">handleSubmit</span>=<span class="hljs-string">{handleSubmit}</span> <span class="hljs-attr">dispatch</span> /&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Frameworks</span> <span class="hljs-attr">frameworks</span>=<span class="hljs-string">{state.frameworks}</span> <span class="hljs-attr">handleSubmit</span>=<span class="hljs-string">{handleSubmit}</span> <span class="hljs-attr">dispatch</span>/&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
</code></pre>
<p>If we want to update the state from our child components, all we need to pass down is the dispatch function. The chid component will be responsible for dispatching the appropriate action in its logic.</p>
<p>This prevents having to pass multiple functions and callbacks, which can quickly become overwhelming.</p>
<h2 id="heading-advantages-of-usereducer">Advantages of useReducer</h2>
<p>Now that we’ve seen <strong>how</strong> to implement useReducer, let’s discuss <strong>why</strong> you should use this hook:</p>
<h3 id="heading-1-simplicity">1. Simplicity</h3>
<p>The first reason is one we’ve already discussed before, it is simple. This hook removes all the boilerplate associated with redux. This is invaluable for projects that aren’t large enough to justify the use of redux.</p>
<h3 id="heading-2-handle-more-complex-state-than-usestate">2. Handle more complex state than useState</h3>
<p>If your application’s state has multiple levels, using the useState hook can become very tedious. To combat this and achieve a clean state management solution, the useReducer hook is more suitable for the task.</p>
<h3 id="heading-3-reduces-obnoxious-prop-drilling">3. Reduces obnoxious prop-drilling</h3>
<p>One of the ways in which we update state from child components is using a technique called prop drilling.</p>
<p>This is a technique whereby a callback function is passed down multiple levels until it reaches the relevant component that uses it.</p>
<p>Technically, we’re still prop-drilling the dispatch function through all our components.</p>
<p>However, the dispatch function is potentially relevant to all the components it passes through as it is component agnostic.</p>
<h3 id="heading-4-removes-external-library-dependencies">4. Removes external library dependencies</h3>
<p>Redux is an external library, and therefore adds to the external dependencies of your react project.</p>
<p>If you are conscious about this due to concerns about bundle size or any other reason, then useReducer is a perfect way to manage some fairly complex state without having to rely on an external package.</p>
]]></content:encoded></item><item><title><![CDATA[Easy Workbox Integration with create-react-app]]></title><description><![CDATA[Recently, I was in a situation that required workbox integration for background sync in an application. After some trial, error and success, I decided to write this article to demonstrate the easiest way I’ve found to integrate workbox with create-re...]]></description><link>https://kelvinmwinuka.com/easy-workbox-integration-with-create-react-app</link><guid isPermaLink="true">https://kelvinmwinuka.com/easy-workbox-integration-with-create-react-app</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[code]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[create-react-app]]></category><category><![CDATA[workbox]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Wed, 05 Aug 2020 05:25:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649190160512/Ao6oYk_wo.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I was in a situation that required workbox integration for background sync in an application. After some trial, error and success, I decided to write this article to demonstrate the easiest way I’ve found to integrate workbox with create-react-app.</p>
<p>This article assumes basic knowledge of create-react-app, workbox and the react framework, as we will be using some terminology associated with these technologies. There’s no need to be a pro, beginner-level knowledge should suffice.</p>
<h2 id="heading-1-update-serviceworkerjs">1. Update serviceWorker.js</h2>
<p>The first step is updating the <code>serviceWorker.js</code> file within the src folder. We will be updating the register function. At the moment, it looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params">config</span>) </span>{
  <span class="hljs-keyword">if</span> (process.env.NODE_ENV === <span class="hljs-string">'production'</span> &amp;&amp; <span class="hljs-string">'serviceWorker'</span> <span class="hljs-keyword">in</span> navigator) {
    <span class="hljs-comment">// The URL constructor is available in all browsers that support SW.</span>
    <span class="hljs-keyword">const</span> publicUrl = <span class="hljs-keyword">new</span> URL(process.env.PUBLIC_URL, <span class="hljs-built_in">window</span>.location.href);
    <span class="hljs-keyword">if</span> (publicUrl.origin !== <span class="hljs-built_in">window</span>.location.origin) {
      <span class="hljs-comment">// Our service worker won't work if PUBLIC_URL is on a different origin</span>
      <span class="hljs-comment">// from what our page is served on. This might happen if a CDN is used to</span>
      <span class="hljs-comment">// serve assets; see https://github.com/facebook/create-react-app/issues/2374</span>
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'load'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> swUrl = <span class="hljs-string">`<span class="hljs-subst">${process.env.PUBLIC\_URL}</span>/service-worker.js`</span>;

      <span class="hljs-keyword">if</span> (isLocalhost) {
        <span class="hljs-comment">// This is running on localhost. Let's check if a service worker still exists or not.</span>
        checkValidServiceWorker(swUrl, config);

        <span class="hljs-comment">// Add some additional logging to localhost, pointing developers to the</span>
        <span class="hljs-comment">// service worker/PWA documentation.</span>
        navigator.serviceWorker.ready.then(<span class="hljs-function">() =&gt;</span> {
          <span class="hljs-built_in">console</span>.log(
            <span class="hljs-string">'This web app is being served cache-first by a service '</span> +
              <span class="hljs-string">'worker. To learn more, visit https://bit.ly/CRA-PWA'</span>
          );
        });
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// Is not localhost. Just register service worker</span>
        registerValidSW(swUrl, config);
      }
    });
  }
}
</code></pre>
<p>We’re going to update the following line:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> swUrl = <span class="hljs-string">`<span class="hljs-subst">${process.env.PUBLIC_URL}</span>/service-worker.js`</span>;
</code></pre>
<p>To:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> swUrl = <span class="hljs-string">`<span class="hljs-subst">${process.env.PUBLIC_URL}</span>/custom-service-worker.js`</span>;
</code></pre>
<p>This will allow us to create and register our own custom service worker file named <code>custom-service-worker.js</code>. You can name this whatever you like.</p>
<p>If you’d like to be able to test this in development, disable the production environment check in the following line:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (process.env.NODE\_ENV === <span class="hljs-string">'production'</span> &amp;&amp; <span class="hljs-string">'serviceWorker'</span> <span class="hljs-keyword">in</span> navigator)
</code></pre>
<h2 id="heading-2-create-a-custom-service-worker-file">2. Create a custom service worker file</h2>
<p>The next step is creating the custom service worker file in the public folder of our application. This should match the name we used in step 1. In our case, ‘custom-service-worker.js’</p>
<p>We can import and use workbox from here:</p>
<pre><code class="lang-javascript">importScripts(<span class="hljs-string">'https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js'</span>)

<span class="hljs-keyword">if</span> (workbox) {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Yay! Workbox is loaded ![🎉](https://cdn.hashnode.com/res/hashnode/image/upload/v1649114039486/kFdciRh2-.png)`</span>);
} <span class="hljs-keyword">else</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Boo! Workbox didn't load ![😬](https://cdn.hashnode.com/res/hashnode/image/upload/v1649114040812/CRViTXRw3.png)`</span>);
}
</code></pre>
<p>Once Workbox is loaded from the CDN, a workbox object is created allowing us to make use of the workbox API.</p>
<p>We can self-host workbox by downloading the files into a folder in our public folder in one of 2 ways:</p>
<ol>
<li><a target="_blank" href="https://developers.google.com/web/tools/workbox/modules/workbox-cli#copylibraries">Using workbox cli’s copyLibraries command</a></li>
<li><a target="_blank" href="https://github.com/GoogleChrome/workbox/releases">Downloading the files from a Github release</a></li>
</ol>
<p>Note that workbox will cache all modules referenced when loaded through the CDN. These modules will then be available for offline use after the first time they are referenced.</p>
<p>Therefore, you do not need to host workbox yourself if this is your concern.</p>
<p>In order to load workbox if we’re self hosting, we will need to do the following:</p>
<pre><code class="lang-javascript">importScripts(<span class="hljs-string">'/third_party/workbox/workbox-sw.js'</span>);

workbox.setConfig({
  <span class="hljs-attr">modulePathPrefix</span>: <span class="hljs-string">'/third_party/workbox/'</span>
});
</code></pre>
<p>In this instance, the workbox folder is contained within the third_party folder inside our application’s public folder.</p>
<p>Now we can finally use workbox. We can use destructuring in order to access the different workbox modules:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { backgroundSync, routing, strategies } = workbox
</code></pre>
<h2 id="heading-3-register-service-worker">3. Register service worker</h2>
<p>The final step is registering the service worker in our application. Navigate to the index.js file in the src folder and change the following line:</p>
<p><code>serviceWorker.unregister();</code></p>
<p>To:</p>
<p><code>serviceWorker.register();</code></p>
]]></content:encoded></item><item><title><![CDATA[Setting Up Redux in React]]></title><description><![CDATA[Setting up redux in your react application can be confusing, but it doesn’t have to be. In this article, I walk you through the entire process of setting up and connecting redux to your react application along with a practical application example.
1....]]></description><link>https://kelvinmwinuka.com/setting-up-redux-in-react</link><guid isPermaLink="true">https://kelvinmwinuka.com/setting-up-redux-in-react</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[code]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[Redux]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Sat, 11 Jul 2020 12:06:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649189322072/9-wkPqapQ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Setting up redux in your react application can be confusing, but it doesn’t have to be. In this article, I walk you through the entire process of setting up and connecting redux to your react application along with a practical application example.</p>
<h2 id="heading-1-creating-the-application">1. Creating the application</h2>
<p>In this example, we will create a simple application that displays a user’s profile containing a name, bio and 2 lists: one for programming languages and one for frameworks.</p>
<p>Let’s create the app using create-react-app: <code>npx create-react-app &lt;app_name&gt;</code></p>
<p>Let’s add an image in the public folder to be used as the profile picture(optional) and create a component file in <code>/src</code> named <code>TechList.js</code>.</p>
<p>Our folder structure should look like this:</p>
<pre><code>.
├── README.md
├── package<span class="hljs-operator">-</span>lock.json
├── package.json
├── <span class="hljs-keyword">public</span>
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   ├── pro.jpg
│   └── robots.txt
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── TechList.js
    ├── index.js
    ├── logo.svg
    ├── serviceWorker.js
    └── setupTests.js
</code></pre><p>Let’s define the App component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> TechList <span class="hljs-keyword">from</span> <span class="hljs-string">'./TechList'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"media"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"align-self-start mr-3 profile-pic"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"pro.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Profile"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"media-body"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-0"</span>&gt;</span>{/** Bio will go here */}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{/** Bio will go here */}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container tech-container"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"row"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-sm"</span>&gt;</span>
                {/** Programming lanugages list */}
                <span class="hljs-tag">&lt;<span class="hljs-name">TechList</span> 
                  <span class="hljs-attr">items</span>=<span class="hljs-string">{[]}</span>
                /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-sm"</span>&gt;</span>
                {/** Programming lanugages list */}
                <span class="hljs-tag">&lt;<span class="hljs-name">TechList</span> 
                  <span class="hljs-attr">items</span>=<span class="hljs-string">{[]}</span>
                /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now let’s define the <code>TechList</code> component, a reusable component that will display both the languages and frameworks lists:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">const</span> TechList = <span class="hljs-function">(<span class="hljs-params">{
    items,
}</span>) =&gt;</span> {

    <span class="hljs-keyword">const</span> handleFormubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        event.preventDefault()
        event.target.reset()
    }
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"list-group"</span>&gt;</span>
            {
                items.map( (item, index) =&gt; {
                    return <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"list-group-item"</span>&gt;</span>{item}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                })
            }
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"list-group-item"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleFormubmit}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-row"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-control add-tech-text"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Type new"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"entry"</span> <span class="hljs-attr">required</span>/&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>Add to list<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TechList
</code></pre>
<p>This component receives an items prop which is an array containing the languages/frameworks that will be displayed in the list. At the moment, we’re passing an empty array from the App component so this will not display anything.</p>
<p>It also contains a form appended at the end of the list that allows us to enter some text to be appended to the list dynamically. We will add functionality to this later.</p>
<p>So far, the app should look something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649114051894/XWT85sRmJ.png" alt /></p>
<p>No information is displayed but this will change once we set up and connect redux.</p>
<p>Next, let’s set up a redux folder inside /src that will contain our action creators and reducer. Inside the folder, we’ll have actions.js and reducer.js. The folder structure should now look like this:</p>
<pre><code>.
├── README.md
├── package<span class="hljs-operator">-</span>lock.json
├── package.json
├── <span class="hljs-keyword">public</span>
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   ├── pro.jpg
│   └── robots.txt
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── TechList.js
    ├── index.js
    ├── logo.svg
    ├── redux
    │   ├── actions.js
    │   └── reducer.js
    ├── serviceWorker.js
    └── setupTests.js
</code></pre><h2 id="heading-2-installing-the-packages">2. Installing the packages</h2>
<p>We will need to install the necessary packages with the following command: <code>npm install redux react-redux redux-thunk axios</code></p>
<h2 id="heading-3-action-creators">3. Action creators</h2>
<p>Our action creators will be located inside the actions.js file. We will have 2 action creators for now: one that creates an action that sends data to add a programming language to the store, and one that sends data to add a framework.</p>
<p>Our code in actions.js will look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addLanguange = <span class="hljs-function">(<span class="hljs-params">language</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">type</span>: <span class="hljs-string">'ADD_LANGUAGE'</span>,
        <span class="hljs-attr">payload</span>: language
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addFramework = <span class="hljs-function">(<span class="hljs-params">framework</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">type</span>: <span class="hljs-string">'ADD_FRAMEWORK'</span>,
        <span class="hljs-attr">payload</span>: framework
    }
}
</code></pre>
<h2 id="heading-4-reducer">4. Reducer</h2>
<p>Our <code>reducer.js</code> file will contain our reducer:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> initial_state = {
    <span class="hljs-attr">profile</span>: {
        <span class="hljs-attr">name</span>: <span class="hljs-string">'Kelvin Clement Mwinuka'</span>,
        <span class="hljs-attr">bio</span>: <span class="hljs-string">'I am a software developer with a BS in Computer Science from The University of Nottingham. I’m passionate about web technologies. In my free time, I like blogging and challenging myself physically.'</span>,
        <span class="hljs-attr">languages</span>: [
            <span class="hljs-string">'JavaScript'</span>, <span class="hljs-string">'Python'</span>, <span class="hljs-string">'HTML'</span>, <span class="hljs-string">'CSS'</span>
        ],
        <span class="hljs-attr">frameworks</span>: [
            <span class="hljs-string">'React'</span>, <span class="hljs-string">'Express'</span>, <span class="hljs-string">'Flask'</span>, <span class="hljs-string">'Django'</span>
        ]
    },
}

<span class="hljs-keyword">const</span> rootReducer = <span class="hljs-function">(<span class="hljs-params">state = initial_state, action</span>) =&gt;</span> {
    <span class="hljs-keyword">switch</span> (action.type) {
        <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_LANGUAGE'</span>:
            <span class="hljs-keyword">return</span> {
                ...state, 
                <span class="hljs-attr">profile</span>: {
                    ...state.profile,
                    <span class="hljs-attr">languages</span>: [...state.profile.languages, action.payload]
                }
            }
        <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_FRAMEWORK'</span>:
            <span class="hljs-keyword">return</span> {
                ...state, 
                <span class="hljs-attr">profile</span>: {
                    ...state.profile,
                    <span class="hljs-attr">frameworks</span>: [...state.profile.frameworks, action.payload]
                }
            }
        <span class="hljs-attr">default</span>:
            <span class="hljs-keyword">return</span> state
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> rootReducer
</code></pre>
<p>In this example, I’ve set up an initial state with some pre-loaded values. When an action is dispatched, the reducer will figure out which part of the state to append data.</p>
<p>Keep the reducer pure by not having any other logic besides returning the new state. We also should not directly mutate the state.</p>
<h2 id="heading-5-connecting-the-app">5. Connecting the app</h2>
<p>Now that we have our action creators and reducer, it’s time to connect our application to redux so we can actually use them.</p>
<p>Let’s open the index.js file and make the following changes:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>;
<span class="hljs-keyword">import</span> \* <span class="hljs-keyword">as</span> serviceWorker <span class="hljs-keyword">from</span> <span class="hljs-string">'./serviceWorker'</span>;
<span class="hljs-keyword">import</span> { createStore, applyMiddleware } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>
<span class="hljs-keyword">import</span> thunk <span class="hljs-keyword">from</span> <span class="hljs-string">'redux-thunk'</span>
<span class="hljs-keyword">import</span> rootReducer <span class="hljs-keyword">from</span> <span class="hljs-string">'./redux/reducer'</span>

<span class="hljs-keyword">const</span> store = createStore(
  rootReducer,
  applyMiddleware(thunk)
)

ReactDOM.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">store</span>=<span class="hljs-string">{store}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Provider</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>,
  <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)
);

<span class="hljs-comment">// If you want your app to work offline and load faster, you can change</span>
<span class="hljs-comment">// unregister() to register() below. Note this comes with some pitfalls.</span>
<span class="hljs-comment">// Learn more about service workers: https://bit.ly/CRA-PWA</span>
serviceWorker.unregister();
</code></pre>
<p>First, we import createStore and applyMiddleware. createStore is exactly what it sounds like: it allows us to create the store that will hold our data. applyMiddleware allows us to extend the functionality of redux by adding packages called middleware.</p>
<p>Next, we import the Provider component from react-redux that will wrap our App component.</p>
<p>Our third import is a middleware package called redux-thunk, I will get into more detail about this in <a class="post-section-overview" href="#enhancement">section 7 (Enhancement with redux-thunk)</a>.</p>
<p>The final import is our reducer. We only have one to import here. However, if you have multiple reducers, you could merge them into one giant reducer using combineReducer from the redux package.</p>
<p>Now we can create our store using createStore and pass in our reducer, and then apply the middleware.</p>
<p>If you wish to stop here or if this simple setup is sufficient, you do not have to use applyMiddleware at all. You could just pass the reducer and call it a day. I’ve added the middleware here in order to set up for the redux-thunk section.</p>
<p>Now lets go into our App component in App.js and make the following changes:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> TechList <span class="hljs-keyword">from</span> <span class="hljs-string">'./TechList'</span>
<span class="hljs-keyword">import</span> { bindActionCreators } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>
<span class="hljs-keyword">import</span> { addLanguange, addFramework } <span class="hljs-keyword">from</span> <span class="hljs-string">'./redux/actions'</span>
<span class="hljs-keyword">import</span> { connect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">(<span class="hljs-params">{
  profile,
  action
}</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"media"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"align-self-start mr-3 profile-pic"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"pro.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Profile"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"media-body"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-0"</span>&gt;</span>{profile.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{profile.bio}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container tech-container"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"row"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-sm"</span>&gt;</span>
                {/** Programming lanugages list */}
                <span class="hljs-tag">&lt;<span class="hljs-name">TechList</span> 
                  <span class="hljs-attr">items</span>=<span class="hljs-string">{profile.languages}</span>
                  <span class="hljs-attr">action</span>=<span class="hljs-string">{actions.addLanguange}</span>
                /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-sm"</span>&gt;</span>
                {/** Programming lanugages list */}
                <span class="hljs-tag">&lt;<span class="hljs-name">TechList</span> 
                 <span class="hljs-attr">items</span>=<span class="hljs-string">{profile.languages}</span>
                  <span class="hljs-attr">action</span>=<span class="hljs-string">{actions.addFrameworks}</span>
                /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mapStateToProps</span> (<span class="hljs-params">state</span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">profile</span>: state.profile
  }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mapDispatchToProps</span> (<span class="hljs-params">dispatch</span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">actions</span>: bindActionCreators({ 
      addLanguange,
      addFramework 
    }, dispatch)
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> connect(mapStateToProps, mapDispatchToProps)(App);
</code></pre>
<p>First, we import <code>bindActionCreators</code> from redux which allows us to combine all our action creators into one object with corresponding keys.</p>
<p>This is not necessary but I find this to be a clean way of dealing with action creators especially as the project grows and necessitates the usage of more of action creators.</p>
<p>Next we import our action creators themselves from actions.js.</p>
<p>Finally, we import connect from <code>react-redux</code>. This allows us to connect a particular component to our store. We will have this only on the App component and pass down any action creators or data as props.</p>
<p>If you have a large project, you could use this method on multiple components especially if you want to make sure you’re only subscribing to certain parts of the state rather than the entire store.</p>
<p>We’ve added a mapStateToProps function:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mapStateToProps</span> (<span class="hljs-params">state</span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">profile</span>: state.profile
  }
}
</code></pre>
<p>This takes the state contained in our redux store as a parameter and returns an object that can be considered a subset of the state. The object in question will be passed to the current component via its props.</p>
<p>Right now, we are subscribing to the ‘profile’ object in the state. Meaning the component will only re-render if this section of the state changes.</p>
<p>This is one of the strengths of redux. The component does not have to re-render if the portion of the state it subscribes to has not changed. Even if the state has changed elsewhere.</p>
<p>If we end up expanding our state in reducer.js and add another section other than ‘profile’, the App component and subsequently, its children, will not re-render if the new portion of the state changes.</p>
<p>We’ve also added another function:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mapDispatchToProps</span> (<span class="hljs-params">dispatch</span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">actions</span>: bindActionCreators({ 
      addLanguange,
      addFramework 
    }, dispatch)
  }
}
</code></pre>
<p>This function enables us to fire our action creators within the app component and its children provided they are passed down.</p>
<p>We make the following update on both instances of the TechList component:</p>
<pre><code class="lang-javascript">              ...
               {<span class="hljs-comment">/** Programming lanugages list */</span>}
               &lt;TechList 
                  items={profile.languages}
                  action={actions.addLanguange}
                /&gt;
              ...
                {<span class="hljs-comment">/** Programming lanugages list */</span>}
                &lt;TechList 
                 items={profile.languages}
                  action={actions.addFrameworks}
                /&gt;
</code></pre>
<p>We pass the relevant items list and action creator to each of the instances.</p>
<h2 id="heading-6-dispatching-actions">6. Dispatching actions</h2>
<p>Now that we’ve connected the application to the redux store, let’s dispatch the actions.</p>
<p>The actions in question add a programming language and a framework to the state’s languages and framework lists respectively. In order to make this possible, we’ll update the TechList component to the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">const</span> TechList = <span class="hljs-function">(<span class="hljs-params">{
    items,
    action
}</span>) =&gt;</span> {

    <span class="hljs-keyword">const</span> handleFormubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        event.preventDefault()
        action(event.target.entry.value)
        event.target.reset()
    }
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"list-group"</span>&gt;</span>
            {
                items.map( (item, index) =&gt; {
                    return <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"list-group-item"</span>&gt;</span>{item}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                })
            }
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"list-group-item"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleFormubmit}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-row"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-control add-tech-text"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Type new"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"entry"</span> <span class="hljs-attr">required</span>/&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>Add to list<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TechList
</code></pre>
<p>This component takes an items props which it loops through and displays in a list as described before. The second prop is an actions prop. This will contain an action creator that will be invoked and passed the data grabbed from the form submission.</p>
<p>This component is action creator agnostic, even though it is the one invoking the action creator. So it’s important to pass the correct action creator down from the parent component.</p>
<p>Congratulations! you’ve connected your app to redux. Now you can add new items to each of the lists.</p>
<p>Next, we’ll take a look at how to enhance this app. At the moment, action creators can only return an action object. This is great if we already have the data we want to return.</p>
<p>What about a situation where we need to retrieve data from a server through an API call? We can’t do this in the reducer as it needs to be pure. The action creator is the place to do this. We need a way to add this logic here. This is where redux-thunk comes in.</p>
<h2 id="heading-7-enhancement-with-redux-thunk">7. Enhancement with redux-thunk</h2>
<p>To understand redux-thunk, we first need to understand what a thunk is. A thunk is a function that delays the execution of some code until the exact moment the result of that execution is needed. In our case, that code is dispatching an action.</p>
<p>Why is this important? At the moment, we have to dispatch an action that consists of the type and the payload. This requires that we already have the payload data beforehand.</p>
<p>What if we don’t have that data? What if we need to retrieve that data from a server before we display it? This is what a thunk is useful for. In this case, instead of dispatching an action directly, we want to make a request to the server and then dispatch an action with the data from the response.</p>
<p>Our action creators need to return a function that has this logic and then returns an action at the end of its execution. This is the thunk.</p>
<p>In order to enable thunks in redux, we need to apply the redux-thunk middleware, which we have already done.</p>
<p>First, let’s write. a simple Node server that listens on port 8000 for requests. This server has a ‘/profile’ GET endpoint that returns the user’s profile details, a ‘/languages’ POST endpoint that adds to the user’s list of languages, and a ‘/frameworks’ POST endpoint that adds to the user’s list of frameworks.</p>
<p>Each endpoint returns the latest user object as a JSON response.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> bodyParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">'body-parser'</span>)
<span class="hljs-keyword">var</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cors'</span>)
<span class="hljs-keyword">var</span> app = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)()

<span class="hljs-keyword">const</span> port = <span class="hljs-number">8000</span>

<span class="hljs-keyword">var</span> profile = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Kelvin Mwinuka'</span>,
    <span class="hljs-attr">bio</span>: <span class="hljs-string">'I am a software developer with a BS in Computer Science from The University of Nottingham. I’m passionate about web technologies. In my free time, I like blogging and challenging myself physically.'</span>,
    <span class="hljs-attr">languages</span>: [],
    <span class="hljs-attr">frameworks</span>: []
}

app.use(cors())
app.use(bodyParser.json())

app.post(<span class="hljs-string">'/languages'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> language = req.body.language
    <span class="hljs-keyword">if</span> (!profile.languages.map( <span class="hljs-function"><span class="hljs-params">l</span> =&gt;</span> l.toLowerCase()).includes(language.toLowerCase())) {
        profile.languages.push(language)
    }
    res.json(profile)
});

app.post(<span class="hljs-string">'/frameworks'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> framework = req.body.framework
    <span class="hljs-keyword">if</span> (!profile.frameworks.map( <span class="hljs-function"><span class="hljs-params">f</span> =&gt;</span> f.toLowerCase()).includes(framework.toLowerCase())) {
        profile.frameworks.push(framework)
    }
    res.json(profile)
});

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

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

Let’s make the necessary changes <span class="hljs-keyword">in</span> actions.js to enable the desired behaviour:

<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> setProfileData = <span class="hljs-function">(<span class="hljs-params">profile</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">type</span>: <span class="hljs-string">'SET_PROFILE_DATA'</span>,
        <span class="hljs-attr">payload</span>: profile
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> loadProfile = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">async</span> (dispatch) =&gt; {
        <span class="hljs-keyword">let</span> res = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'http://localhost:8000/profile'</span>)
        <span class="hljs-keyword">let</span> profile = res.data
        dispatch(setProfileData(profile))
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addLanguange = <span class="hljs-function">(<span class="hljs-params">language</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">async</span> (dispatch) =&gt; {
        <span class="hljs-keyword">let</span> res = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">'http://localhost:8000/languages'</span>, { 
            <span class="hljs-attr">language</span>: language 
        })
        <span class="hljs-keyword">let</span> profile = res.data
        dispatch(setProfileData(profile))
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addFramework = <span class="hljs-function">(<span class="hljs-params">framework</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">async</span> (dispatch) =&gt; {
        <span class="hljs-keyword">let</span> res = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">'http://localhost:8000/frameworks'</span>, { 
            <span class="hljs-attr">framework</span>: framework 
        })
        <span class="hljs-keyword">let</span> profile = res.data
        dispatch(setProfileData(profile))
    }
}
</code></pre>
<p>The first change we’ve made is the addition of a ‘setProfileData’ action creator that behaves like a regular action creator (no thunk) to set the profile data if we already have it.</p>
<p>Notice what we’ve done with the <code>addLanguage</code> and <code>addFramework</code> action creators? Instead of returning a raw action object, we instead return an async function that takes dispatch as a parameter.</p>
<p>This function executes whatever logic is needed first, and only then will it dispatch an action. This is what a thunk is. A thunk can also be used for conditional dispatches but that is outside the scope of this article.</p>
<p>We’ve also added another action creator called <code>loadProfile</code> that is explicitly responsible for retrieving the user profile from the server. It behaves similar to the ‘addLanguage’ and <code>addFramework</code> action creators.</p>
<p>Another important thing to note is that these 3 action creators now pass the ‘setProfileData’ action creator to the dispatch function. We can do this because that action creator returns a raw action. Therefore, it’s equivalent to passing the action object directly to dispatch. I take this approach in order to avoid typing the same action object multiple times.</p>
<p>In the reducer, let’s add one more case for setting the user profile. The data is no longer hardcoded in the initial state and will instead be set by dispatching an action after retrieving it from the server.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> initial_state = {
    <span class="hljs-attr">profile</span>: {
        <span class="hljs-attr">name</span>: <span class="hljs-string">''</span>,
        <span class="hljs-attr">bio</span>: <span class="hljs-string">''</span>,
        <span class="hljs-attr">languages</span>: [],
        <span class="hljs-attr">frameworks</span>: []
    },
}

<span class="hljs-keyword">const</span> rootReducer = <span class="hljs-function">(<span class="hljs-params">state = initial_state, action</span>) =&gt;</span> {
    <span class="hljs-keyword">switch</span> (action.type) {

        <span class="hljs-keyword">case</span> <span class="hljs-string">'SET_PROFILE_DATA'</span>:
            <span class="hljs-keyword">return</span> {...state, <span class="hljs-attr">profile</span>: action.payload}

        <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_LANGUAGE'</span>:
            <span class="hljs-keyword">return</span> {
                ...state, 
                <span class="hljs-attr">profile</span>: {
                    ...state.profile,
                    <span class="hljs-attr">languages</span>: [...state.profile.languages, action.payload]
                }
            }
        <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_FRAMEWORK'</span>:
            <span class="hljs-keyword">return</span> {
                ...state, 
                <span class="hljs-attr">profile</span>: {
                    ...state.profile,
                    <span class="hljs-attr">frameworks</span>: [...state.profile.frameworks, action.payload]
                }
            }
        <span class="hljs-attr">default</span>:
            <span class="hljs-keyword">return</span> state
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> rootReducer
</code></pre>
<p>In the app section, let’s import our new <code>loadProfile</code> action creator and then invoke it right at the top of our app component in order to trigger the user profile retrieval from the server.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> TechList <span class="hljs-keyword">from</span> <span class="hljs-string">'./TechList'</span>
<span class="hljs-keyword">import</span> { bindActionCreators } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>
<span class="hljs-keyword">import</span> { addLanguange, addFramework, loadProfile } <span class="hljs-keyword">from</span> <span class="hljs-string">'./redux/actions'</span>
<span class="hljs-keyword">import</span> { connect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">(<span class="hljs-params">{
  profile,
  actions
}</span>) =&gt;</span> {

  actions.loadProfile()

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"media"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"align-self-start mr-3 profile-pic"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"pro.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Profile"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"media-body"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-0"</span>&gt;</span>{profile.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{profile.bio}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container tech-container"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"row"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-sm"</span>&gt;</span>
                {/** Programming lanugages list */}
                <span class="hljs-tag">&lt;<span class="hljs-name">TechList</span> 
                  <span class="hljs-attr">items</span>=<span class="hljs-string">{profile.languages}</span>
                  <span class="hljs-attr">action</span>=<span class="hljs-string">{actions.addLanguange}</span>
                /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-sm"</span>&gt;</span>
                {/** Programming lanugages list */}
                <span class="hljs-tag">&lt;<span class="hljs-name">TechList</span> 
                  <span class="hljs-attr">items</span>=<span class="hljs-string">{profile.frameworks}</span>
                  <span class="hljs-attr">action</span>=<span class="hljs-string">{actions.addFramework}</span>
                /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mapStateToProps</span> (<span class="hljs-params">state</span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">profile</span>: state.profile
  }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mapDispatchToProps</span> (<span class="hljs-params">dispatch</span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">actions</span>: bindActionCreators({ 
      loadProfile,
      addLanguange,
      addFramework
    }, dispatch)
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> connect(mapStateToProps, mapDispatchToProps)(App);
</code></pre>
<p>That’s it! run the app and you’ll notice that we’ve retained all the functionality we had before from the user’s perspective, but we can now create smarter action creators that allow us to accomplish more with redux.</p>
]]></content:encoded></item><item><title><![CDATA[Testing React App With Jest & Puppeteer]]></title><description><![CDATA[So you’ve created your react application and now you have to write end-to-end tests in order to make sure your application works as expected from the end user’s perspective. In this article, I will provide a simple step-by-step guide on how to achiev...]]></description><link>https://kelvinmwinuka.com/testing-react-app-with-jest-and-puppeteer</link><guid isPermaLink="true">https://kelvinmwinuka.com/testing-react-app-with-jest-and-puppeteer</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[React]]></category><category><![CDATA[Testing]]></category><category><![CDATA[puppeteer]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Thu, 02 Jul 2020 05:47:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649114070504/t3fpZYjue.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649114061643/HHefYIVgj.png" alt="Puppeteer logo. Testing React App With Puppeteer" /></p>
<p>So you’ve created your react application and now you have to write end-to-end tests in order to make sure your application works as expected from the end user’s perspective. In this article, I will provide a simple step-by-step guide on how to achieve this using the Jest testing framework and the Puppeteer library.</p>
<p>Before we continue, it’s important to note that a react application created using create-react-app will come pre-packaged with Testing Library, which more or less allows us to achieve the same thing this article addresses. Here is a brilliant article that explains <a target="_blank" href="https://jkettmann.com/beginners-guide-to-testing-react/">how to run tests using Jest and Testing Library</a>.</p>
<p>So why puppeteer? Well, there are many reasons you might choose to go with puppeteer instead. Maybe there is some functionality that is unique to puppeteer that satisfies a very specific use case. For me, it’s a matter of personal preference, I prefer the way Puppeteer handles interaction with the DOM.</p>
<h2 id="heading-1-creating-the-app">1. Creating the app</h2>
<p>First, let’s create an application that will be our test subject. I’ve created a simple single-page application that contains a form and a table. The form will allow us to input some data that immediately gets displayed in the table upon submission. Here’s how it looks:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649114063373/uB1ySDlLK.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649114065025/vqKhSWVXp.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649114066632/KMpLh7sAn.png" alt /></p>
<p>This application is created using create-react-app. The application folder will be structured as shown below.</p>
<pre><code>
├── e2e
│   ├── custom<span class="hljs-operator">-</span>environment.js
│   ├── jest.config.js
│   └── tests
│       └── App.test.js
├── package<span class="hljs-operator">-</span>lock.json
├── package.json
├── <span class="hljs-keyword">public</span>
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
└── src
    ├── App.css
    ├── App.js
    ├── DevsTable.js
    ├── Form.js
    ├── index.js
    ├── serviceWorker.js
    └── setupTests.js
</code></pre><p>I’ve placed the e2e folder in the project root. This is where our puppeteer tests and Jest configurations will live. Other additional files are the DevsTable, and Form components.</p>
<p>In the form component, we accept the user input and pass it to the App component to update its state.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">const</span> Form = <span class="hljs-function">(<span class="hljs-params">{ add }</span>) =&gt;</span> {

    <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        event.preventDefault();
        <span class="hljs-keyword">let</span> dev = <span class="hljs-keyword">new</span> FormData(event.target)
        add({<span class="hljs-attr">name</span>: dev.get(<span class="hljs-string">'name'</span>), <span class="hljs-attr">role</span>: dev.get(<span class="hljs-string">'role'</span>)})
        event.target.reset()
    }

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"devForm"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Name: <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">required</span>/&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Role: <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"role"</span>/&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Add Developer"</span> <span class="hljs-attr">required</span>/&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Form
</code></pre>
<p>The DevsTable component displays a table and maps each object in the devs prop to a row in the table.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> DevsTable = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">table</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Role<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
                {
                    props.devs.map((dev, index) =&gt; {
                        return (
                            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">name</span>${<span class="hljs-attr">index</span>}`}&gt;</span>{dev.name}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">role</span>${<span class="hljs-attr">index</span>}`}&gt;</span>{dev.role}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
                        )
                    })
                }
            <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span></span>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DevsTable
</code></pre>
<p>Here’s the App component’s code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useCallback } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> Form <span class="hljs-keyword">from</span> <span class="hljs-string">'./Form'</span>;
<span class="hljs-keyword">import</span> DevsTable <span class="hljs-keyword">from</span> <span class="hljs-string">'./DevsTable'</span>

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

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

  <span class="hljs-keyword">const</span> addDeveloper = useCallback(<span class="hljs-function">(<span class="hljs-params">dev</span>) =&gt;</span> {
    setDevs(<span class="hljs-function"><span class="hljs-params">devs</span> =&gt;</span> [...devs, dev])
  }, [setDevs])

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">DevsTable</span> <span class="hljs-attr">devs</span>=<span class="hljs-string">{devs}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">add</span>=<span class="hljs-string">{addDeveloper}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Finally, the styling in App.css:</p>
<pre><code><span class="hljs-selector-class">.App</span> {
  <span class="hljs-attribute">text-align</span>: left;
  <span class="hljs-attribute">font-family</span>: Arial, Helvetica, sans-serif;
}

<span class="hljs-selector-tag">table</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid black;
  <span class="hljs-attribute">border-collapse</span>: collapse;
}

<span class="hljs-selector-tag">th</span>, <span class="hljs-selector-tag">td</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid black;
}

<span class="hljs-selector-tag">th</span> {
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">background-color</span>: teal;
}

<span class="hljs-selector-tag">form</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">50px</span>;
}

<span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.submit</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">background-color</span>: teal;
  <span class="hljs-attribute">border-width</span>: <span class="hljs-number">0px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">0px</span>;
}
</code></pre><p>I usually delete the index.css file and its import statement in index.js. I prefer to have the top-level CSS in App.css.</p>
<h2 id="heading-2-installing-the-packages">2. Installing the packages</h2>
<p>Before we can start writing the tests, we need to make sure we have the right packages. The first will be the <a target="_blank" href="https://jestjs.io/en/">Jest testing framework</a>. When using create-react-app, Jest comes pre-packaged in order to run the default test script. However, we will not be able to use this in the terminal when running our own custom test scripts.</p>
<p>To solve this, we need to add Jest to our devDependencies. If you don’t already have devDependencies in your package.json, add it at the top level. Next, navigate to your node_modules folder and look for the Jest module. Open that module’s package.json and check the version of Jest that’s been pre-packaged by create-react-app.</p>
<p>We want to use the same version of jest in our devDependencies to avoid clashes. Inside devDependencies, add Jest and set the version to the same version installed with create-react-app.</p>
<p>Your devDependencies section should look something like this:</p>
<pre><code><span class="hljs-string">"devDependencies"</span>: {
    <span class="hljs-string">"jest"</span>: <span class="hljs-string">"24.9.0"</span>
  }
</code></pre><p>Now run npm install.</p>
<p>We are going to need 2 more packages for our testing: jest-environment-node and <a target="_blank" href="https://pptr.dev/">Puppeteer</a>.</p>
<p>jest-environment-node allows us to create a custom environment in which to run our tests(I will explain this in more detail later in the article). Puppeteer is the testing library that provides a high-level API for controlling chromium. At the time of writing, puppeteer only offers chromium support.</p>
<p>We only need these in our dev environment so we will install them with the following command:</p>
<p>npm install jest-environment-node puppeteer --save-dev</p>
<p>Once the installation is done, our devDependencies section should look like this:</p>
<pre><code><span class="hljs-string">"devDependencies"</span>: {
    <span class="hljs-string">"jest"</span>: <span class="hljs-string">"24.9.0"</span>,
    <span class="hljs-string">"jest-environment-node"</span>: <span class="hljs-string">"^26.0.1"</span>,
    <span class="hljs-string">"puppeteer"</span>: <span class="hljs-string">"^4.0.0"</span>
  }
</code></pre><h2 id="heading-3-creating-the-custom-test-environment">3. Creating the custom test environment</h2>
<p>Jest runs tests in environments. The default environment used by Jest is a browser-like environment through jsdom. The environment is created for each test suite. We want to create a custom environment so we can control the test suites’ setup and teardown.</p>
<p>Why is this important? We could just create the browser and page objects in beforeAll and then close them in afterAll, right?</p>
<p>While this would work, it’s not the most efficient solution if we have multiple test suites that use puppeteer. This would lead to typing the same setup and teardown logic multiple times.</p>
<p>Instead, we will create one custom environment, set up and tear down the tests here and then use that custom environment for all our tests.</p>
<p>Here’s how we set up the custom environment:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> NodeEnvironemnt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'jest-environment-node'</span>)
<span class="hljs-keyword">var</span> puppeteer = <span class="hljs-built_in">require</span>(<span class="hljs-string">'puppeteer'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomEnvironment</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NodeEnvironemnt</span> </span>{
    <span class="hljs-keyword">constructor</span>(config, context){
        <span class="hljs-built_in">super</span>(config, context)
    }

    <span class="hljs-keyword">async</span> setup(){
        <span class="hljs-keyword">await</span> <span class="hljs-built_in">super</span>.setup()
        <span class="hljs-built_in">this</span>.global.browser = <span class="hljs-keyword">await</span> puppeteer.launch({
            <span class="hljs-attr">headless</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">slowMo</span>: <span class="hljs-number">100</span>
        })
        <span class="hljs-built_in">this</span>.global.page = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.global.browser.newPage()
        <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.global.page.goto(<span class="hljs-string">'http://localhost:3000/'</span>, {<span class="hljs-attr">waitUntil</span>: <span class="hljs-string">'load'</span>})
    }

    <span class="hljs-keyword">async</span> teardown(){
        <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.global.browser.close()
        <span class="hljs-keyword">await</span> <span class="hljs-built_in">super</span>.teardown()
    }
}

<span class="hljs-built_in">module</span>.exports = CustomEnvironment
</code></pre>
<p>In the custom environment, we have access to <code>this.global</code>. This is where you put data that needs to be accessible in the tests.</p>
<p>We set up our browser and page objects in the setup method. This method runs before the test suite is executed. The teardown method runs after all the tests in a suite are complete so its where we close the browser.</p>
<h2 id="heading-4-configuring-jest">4. Configuring Jest</h2>
<p>Next, we have to configure Jest. We can do this directly in the project’s package.json with a “jest” object, but I prefer using a config file. Let’s navigate to the jest.config.js inside the e2e folder and add the following code:</p>
<pre><code>module.exports <span class="hljs-operator">=</span> {
    testEnvironment: <span class="hljs-string">'./custom-environment.js'</span>,
    testTimeout: <span class="hljs-number">60000</span>
}
</code></pre><p>The <code>testEnvironment</code> option allows us to set a custom environment to be used instead of the default environment. Let’s point it to the custom environment we defined earlier.</p>
<p>The <code>testTimeout</code> option allows us to set the amount of time a test has to run before Jest times out and aborts it. The default is 5 seconds. This is quite short for end-to-end tests as launching the browser and loading pages alone can take a few seconds. I’ve set it to 1 minute here but feel free to adjust this according to your needs.</p>
<p>However, it’s important to set a timeout that’s not too long either. One of the criteria to test for is performance. It’s not beneficial to simply adjust your tests to tolerate extremely slow loading times as that’s a sign that your application can be optimised.</p>
<p>Next, we have to create a command to run our tests. In the scripts section inside the package.json, let’s add the following line:</p>
<pre><code><span class="hljs-string">"test:e2e"</span>: <span class="hljs-string">"jest -c e2e/jest.config.js"</span>
</code></pre><p>This sets the Jest terminal command that will be run. We also set the configuration file here. Now, all we have to do to run the tests is use the <code>npm run test:e2e</code> command in the terminal.</p>
<h2 id="heading-5-writing-the-tests">5. Writing the tests</h2>
<p>Finally, we can write the tests! Let’s navigate to <code>e2e/tests/App.test.js</code> and define the test suite. Inside the test suite, we’re exposed to the global object which contains the browser and page objects we created in the custom environment.</p>
<p>Here, I’ve written a simple test that fills the form 3 times with 3 sets of data, and then iterates through the table rows to check if the data is being displayed as expected.</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">'App tests'</span>,<span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">let</span> page = <span class="hljs-built_in">global</span>.page

  test(<span class="hljs-string">'Loads all elements'</span>, <span class="hljs-keyword">async</span> () =&gt; {

    <span class="hljs-keyword">const</span> testData = [
      { <span class="hljs-attr">name</span>: <span class="hljs-string">'Kelvin Mwinuka'</span>, <span class="hljs-attr">role</span>: <span class="hljs-string">'Front-end developer'</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">'James Mitchel'</span>, <span class="hljs-attr">role</span>: <span class="hljs-string">'Back-end developer'</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">'Michael Scott'</span>, <span class="hljs-attr">role</span>: <span class="hljs-string">'DevOps'</span> }
    ]

    <span class="hljs-keyword">await</span> page.waitForFunction(<span class="hljs-string">'document.getElementById("devForm")'</span>)

    <span class="hljs-comment">// Input all the data</span>
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; testData.length; i++){
      <span class="hljs-keyword">await</span> page.type(<span class="hljs-string">"input[name='name']"</span>, testData[i].name)
      <span class="hljs-keyword">await</span> page.type(<span class="hljs-string">"input[name='role']"</span>, testData[i],role)
      <span class="hljs-keyword">await</span> page.click(<span class="hljs-string">"input[type='submit']"</span>)
    }

    <span class="hljs-comment">// Check if all the data is represented in the table</span>
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; testData.length; i++){
      expect(<span class="hljs-keyword">await</span> page.$eval(<span class="hljs-string">`#name<span class="hljs-subst">${i}</span>`</span>, <span class="hljs-function"><span class="hljs-params">element</span> =&gt;</span> element.innerText))
      .toEqual(testData[i].name)
      expect(<span class="hljs-keyword">await</span> page.$eval(<span class="hljs-string">`#role<span class="hljs-subst">${i}</span>`</span>, <span class="hljs-function"><span class="hljs-params">element</span> =&gt;</span> element.innerText))
      .toEqual(testData[i].role)
    }
  });
})
</code></pre>
<h2 id="heading-6-considerations">6. Considerations</h2>
<p>There are several improvements we can make for a better testing experience.</p>
<h3 id="heading-1-dev-server">1. Dev server</h3>
<p>At the moment, we need the application to already be running before we can run our tests. We can improve this by employing the help of jest-dev-server. First let’s install it in our devDependencies <code>npm install jest-dev-server --save-dev</code></p>
<p>Now let’s create a global-setup.js file in our e2e folder with the following contents:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { <span class="hljs-attr">setup</span>: setupDevServer } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"jest-dev-server"</span>)

<span class="hljs-built_in">module</span>.exports = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">await</span> setupDevServer({
        <span class="hljs-attr">command</span>: <span class="hljs-string">'npm run start --port 3000'</span>,
        <span class="hljs-attr">launchTimeout</span>: <span class="hljs-number">30000</span>,
        <span class="hljs-attr">debug</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-number">3000</span>
    })
}
</code></pre>
<p>This file starts the server upon setting up our test. Next, let’s create a global-teardown.js file in the same directory with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { <span class="hljs-attr">teardown</span>: teardownDevServer } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"jest-dev-server"</span>)

<span class="hljs-built_in">module</span>.exports = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">await</span> teardownDevServer()
}
</code></pre>
<p>This will shutdown the dev server once the tests have finished executing. In order for jest to run these setup and teardown functions, we must update the jest.config.js file to this:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {
    <span class="hljs-attr">testEnvironment</span>: <span class="hljs-string">'./custom-environment.js'</span>,
    <span class="hljs-attr">testTimeout</span>: <span class="hljs-number">60000</span>,
    <span class="hljs-attr">globalSetup</span>: <span class="hljs-string">'./global-setup.js'</span>,
    <span class="hljs-attr">globalTeardown</span>: <span class="hljs-string">'./global-teardown.js'</span>
}
</code></pre>
<p>It’s important to note that the setup and teardown methods in custom environment run once before and after EACH test suite respectively. The globalSetup and globalTeardown function run before and after ALL tests suites respectively.</p>
<p>Also, note that the global variables set in globalSetup can only be accessed in globalTeardown and cannot be accessed inside the test suites unlike the global variables set in the custom environment.</p>
<h3 id="heading-2-tests-with-login">2. Tests with login</h3>
<p>If you have multiple test suites which create user sessions, you’ll want to make sure they are queued to run consecutively. By default, Jest will run test suites concurrently.</p>
<p>The issue arises when one suite logs in and essentially kicks another suite out of its session. To prevent this, limit the max workers to 1 in the jest command by updating the script in package.json to the following:</p>
<pre><code><span class="hljs-string">"test:e2e"</span>: <span class="hljs-string">"jest -c e2e/jest.config.js --maxWorkers=1"</span>
</code></pre><p>This will make sure only one test suite is run at a time. Do note that this will increase the total execution time.</p>
<h3 id="heading-3-mocking-requests">3. Mocking requests</h3>
<p>If you want to avoid the above problem entirely, it’s advisable to mock requests in your tests. This has multiple advantages including but not limited to:</p>
<ol>
<li>Reducing test execution time as no real network calls are made</li>
<li>Having full control over responses when testing for various response scenarios</li>
<li>Not being at the mercy of the back-end server when running tests</li>
</ol>
<p>Here’s a library that provides <a target="_blank" href="https://github.com/Diokuz/puppeteer-request-mocker">puppeteer request mocking</a> functionality along with concise documentation.</p>
]]></content:encoded></item><item><title><![CDATA[Python Higher-Order Functions]]></title><description><![CDATA[A higher-order function is one that either takes a function as an argument or returns a function (or both!). These functions help us achieve more complex tasks in our business logic that would be much more tedious with first-class functions.
Python a...]]></description><link>https://kelvinmwinuka.com/python-higher-order-functions</link><guid isPermaLink="true">https://kelvinmwinuka.com/python-higher-order-functions</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[code]]></category><category><![CDATA[functions]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Python]]></category><category><![CDATA[higher-order functions]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Sun, 29 Dec 2019 23:39:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649188133230/hphA2WgdM.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A <a target="_blank" href="https://en.wikipedia.org/wiki/Higher-order_function">higher-order function</a> is one that either takes a function as an argument or returns a function (or both!). These functions help us achieve more complex tasks in our business logic that would be much more tedious with first-class functions.</p>
<p>Python allows us to define our own custom higher-order functions. In fact, I demonstrate this feature in my previous article on <a target="_blank" href="https://kelvinmwinuka.com/python-lambda-functions-example/">lambda functions</a> in Python. I won’t be covering that particular feature in this article. However, I will be covering 3 of the most useful higher-order functions that are built into Python:</p>
<ol>
<li>Map</li>
<li>Reduce</li>
<li>Filter</li>
</ol>
<p>These functions make dealing with iterable objects much simpler than using first-class functions or regular loops. For each function, I will explain what the function does, demonstrate how it works with a code example, and suggest possible applications for the function.</p>
<h2 id="heading-map">Map</h2>
<p>The map function in Python allows us to produce a new iterable object from an original iterable object. It takes 2 arguments: a function and an iterable object. The map function applies the function passed to every member of the iterable and then produces a map object. This object can be cast to an iterable type of our choosing. The function passed to the map object does not have to return a value (I will demonstrate this later).</p>
<h3 id="heading-implementation">Implementation</h3>
<p>For our example, let’s generate a new list (L2) from an initial list (L1) such that each element of L2 is a double of its corresponding element in L1. Here is how we can achieve this with the map function:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">double</span>(<span class="hljs-params">x</span>):</span>
    <span class="hljs-keyword">return</span> x * <span class="hljs-number">2</span>

L1 = [<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">22</span>, <span class="hljs-number">45</span>, <span class="hljs-number">1</span>, <span class="hljs-number">245</span>, <span class="hljs-number">6</span>, <span class="hljs-number">34</span>, <span class="hljs-number">4</span>, <span class="hljs-number">8</span>, <span class="hljs-number">14</span>]

L2 = list(map(double, L1))

print(<span class="hljs-string">"Doubled Numbers: {}"</span>.format(L2)) 
<span class="hljs-comment"># [6, 2, 8, 44, 90, 2, 490, 12, 68, 8, 16, 28]</span>
</code></pre>
<p>The code above passes the double function(notice we leave out the parenthesis) and the original list (L1). A map object is returned and then cast to a list. <em>Note, we can cast this map object to any type of iterable we want (list, tuple, set, …).</em></p>
<p>The map function also works with lambda functions. To make the code above a little more compact, we can rewrite it as follows:</p>
<pre><code class="lang-python">L1 = [<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">22</span>, <span class="hljs-number">45</span>, <span class="hljs-number">1</span>, <span class="hljs-number">245</span>, <span class="hljs-number">6</span>, <span class="hljs-number">34</span>, <span class="hljs-number">4</span>, <span class="hljs-number">8</span>, <span class="hljs-number">14</span>]
L2 = list(map( (<span class="hljs-keyword">lambda</span> x : x \* <span class="hljs-number">2</span>) , L1))
print(L2)
</code></pre>
<p>This would be a more desirable solution if your map function is rather simple and will not be needed elsewhere in the program. However, if you’re running a complex operation on an iterable and/or plan to reuse the function outside of this context, it’s best to stick to regular functions.</p>
<p>Remember I mentioned that the function does not actually have to return anything. If you want to map certain functionality to every member of an iterable but don’t care for the resulting map object, the map function will simply return None for every corresponding member of the original iterable.</p>
<p>In fact, we don’t even have to store the returned map object at all. If we have a list of people and we simply want to print out a greeting for each person on the list, we can use a map function:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">greet</span>(<span class="hljs-params">person</span>):</span>
    print(<span class="hljs-string">"Hello, {}!"</span>.format(person[<span class="hljs-string">'name'</span>]))
people = [
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'John Doe'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">20</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Mike Will'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">10</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Jane Hill'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">18</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Alan Smith'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">16</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Chimuka Chinene'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">18</span>},
]
list(map(greet, people ))
<span class="hljs-string">""" Prints :
Hello, John Doe!
...
Hello, Chimuka Chinene!
"""</span>
</code></pre>
<p>We have to cast the map object returned in order to actually get the function to execute on all the members. The list produced is just a list of None type objects as the mapper function did not return anything. If you assign that list to a variable and print it, the output would be: [None, None, None, None, None]</p>
<h3 id="heading-uses">Uses</h3>
<p>The most obvious use of a map function is in creating a hash table. A hash table is a data structure that associates a key with a hash that’s generated using the key. The map function could be used to apply the hash function to a list of keys without the need for iteration.</p>
<p>The map function could also be used to replace loops. Instead of looping through every member of an iterable and executing some logic, we could map a function with that logic to the iterable. Remember, we don’t have to return anything from the mapper function nor do we have to care for the resulting map object.</p>
<h2 id="heading-reduce">Reduce</h2>
<p>A reduce function works similar to a map function in the sense that it accepts an iterable and a function to apply to all the members of an iterable. However, it differs from map as it returns ONE value instead of an iterable mapping to the original. It <em>reduces</em> an iterable down to one value. The reduce function also takes a third argument, the initial value that it starts the iteration with. If this value is not provided, the first element of the iterable will be used as the initial value. With every iteration, the function takes its current value, and the next member in the iterable and returns a value to be used for the next element.</p>
<h3 id="heading-implementation">Implementation</h3>
<p>Let’s calculate the sum of the doubles of all numbers in an array of integers L1. We could use a loop for this. However, a cleaner solution would be to use a reduce function as follows: <em>Note in Python 3, reduce has been moved to functools so you will have to import it.</em></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> reduce
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">addDoubles</span>(<span class="hljs-params">a, b</span>):</span>
    <span class="hljs-keyword">return</span> a + (b * <span class="hljs-number">2</span>)
L1 = [<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">22</span>, <span class="hljs-number">45</span>, <span class="hljs-number">1</span>, <span class="hljs-number">245</span>, <span class="hljs-number">6</span>, <span class="hljs-number">34</span>, <span class="hljs-number">4</span>, <span class="hljs-number">8</span>, <span class="hljs-number">14</span>]
doubleSum = reduce(addDoubles, L1, <span class="hljs-number">0</span>)
print(doubleSum) <span class="hljs-comment"># 774</span>
</code></pre>
<p>In the code above, the add function takes 2 parameters: the current sum(a) and the current element in the iterable(b) which is doubled. The total of the double and current sum is returned and carried forward into the next iteration until the end of the iterable. The reduce function also accepts lambda functions. We can simplify the code above as follows:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> reduce
L1 = [<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">22</span>, <span class="hljs-number">45</span>, <span class="hljs-number">1</span>, <span class="hljs-number">245</span>, <span class="hljs-number">6</span>, <span class="hljs-number">34</span>, <span class="hljs-number">4</span>, <span class="hljs-number">8</span>, <span class="hljs-number">14</span>]
doubleSum = reduce( (<span class="hljs-keyword">lambda</span> a,b : a + b * <span class="hljs-number">2</span>) , L1, <span class="hljs-number">0</span>)
print(doubleSum) <span class="hljs-comment"># 774</span>
</code></pre>
<p>This is a simple example, we can define a much more complex reducer function. We can also pick another initial value. For example, if I wanted my starting point to be 1000, I would write the code differently:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> reduce
L1 = [<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">22</span>, <span class="hljs-number">45</span>, <span class="hljs-number">1</span>, <span class="hljs-number">245</span>, <span class="hljs-number">6</span>, <span class="hljs-number">34</span>, <span class="hljs-number">4</span>, <span class="hljs-number">8</span>, <span class="hljs-number">14</span>]
sum = reduce( (<span class="hljs-keyword">lambda</span> a,b : a + b * <span class="hljs-number">2</span>) , L1, <span class="hljs-number">1000</span>) <span class="hljs-comment"># 1000 as initial value</span>
print(sum) <span class="hljs-comment"># 1774</span>
</code></pre>
<h3 id="heading-uses">Uses</h3>
<p>The reduce function can be used anywhere that an iterable needs to be aggregated to one value. We can define the reducer function any way we like.</p>
<h2 id="heading-filter">Filter</h2>
<p>The filter function is also similar to the map function. It accepts an iterable, and a function to execute on all the members of the iterable. However, it does come with some different rules:</p>
<ol>
<li>A filter does not have to produce a 1 to 1 mapping between the new iterable and the original one like a map function does.</li>
<li>A filter creates a new list based on the elements that return True when the filter function is executed on them</li>
</ol>
<h3 id="heading-implementation">Implementation</h3>
<p>Given a list of 5 people, let’s <em>filter out</em> all the people that are younger than 18.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">legal</span>(<span class="hljs-params">person</span>):</span>
    <span class="hljs-keyword">return</span> person[<span class="hljs-string">'age'</span>] &gt;= <span class="hljs-number">18</span>
people = [
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'John Doe'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">20</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Mike Will'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">10</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Jane Hill'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">18</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Alan Smith'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">16</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Chimuka Chinene'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">18</span>},
]
legal_people = list(filter(legal, people))
print(legal_people)
<span class="hljs-string">""" Prints [{'name': 'John Doe', 'age': 20}, {'name': 'Jane Hill', 'age': 18}, #{'name': 'Chimuka Chinene', 'age': 18}] """</span>
</code></pre>
<p>In the code above, we run the <code>legal</code> function on each person. The function returns either <code>True</code> or <code>False</code> depending on the person’s age. Only the people whose age returns True from the legal function make it into the new list. A filter object is returned. We can cast this to any iterable type we desire.</p>
<p>The filter function can also take a lambda function as an argument. We can write the code above as follows:</p>
<pre><code class="lang-python">people = [
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'John Doe'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">20</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Mike Will'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">10</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Jane Hill'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">18</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Alan Smith'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">16</span>},
    { <span class="hljs-string">'name'</span> : <span class="hljs-string">'Chimuka Chinene'</span>, <span class="hljs-string">'age'</span> : <span class="hljs-number">18</span>},
]
legal_people = list(filter( (<span class="hljs-keyword">lambda</span> person : person[<span class="hljs-string">'age'</span>] &gt;= <span class="hljs-number">18</span>) , people))
print(legal_people)
<span class="hljs-string">""" Prints [{'name': 'John Doe', 'age': 20}, {'name': 'Jane Hill', 'age': 18}, #{'name': 'Chimuka Chinene', 'age': 18}] """</span>
</code></pre>
<h3 id="heading-uses">Uses</h3>
<p>This one is pretty straightforward. We use the filter function in all instances where we want to filter out undesirable members of the original list. We can run this on very complex elements in an iterable and define complex filter functions to achieve whatever desired outcome we want. Just remember, the filter function has to return True or False.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Higher-order functions are an invaluable tool when writing programs, especially ones working on iterable objects. They are not necessary as their functionality can be achieved by regular for/while loops. However, they help a great deal in keeping our code neat and concise compared to regular loops. I hope I’ve provided a sufficient explanation of the functions above that will allow you to implement them in your projects. Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Python Lambda Functions]]></title><description><![CDATA[Python lambda functions are an invaluable feature. One of the benefits of using Python is that it facilitates relatively compact code compared to other programming languages. This means getting so much more done with fewer lines of code.
This isn’t a...]]></description><link>https://kelvinmwinuka.com/python-lambda-functions</link><guid isPermaLink="true">https://kelvinmwinuka.com/python-lambda-functions</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Python]]></category><category><![CDATA[clean code]]></category><dc:creator><![CDATA[Kelvin Mwinuka]]></dc:creator><pubDate>Mon, 23 Dec 2019 16:56:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649188236641/tieIbAAPX.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Python lambda functions are an invaluable feature. One of the benefits of using Python is that it facilitates relatively compact code compared to other programming languages. This means getting so much more done with fewer lines of code.</p>
<p>This isn’t always the case, however. If you’re not aware of the tools python provided in order to achieve this, it is very easy to write verbose code that defeats the point of picking Python for its “compactness”.</p>
<p>One such tool is the lambda function. These allow us to create anonymous functions in python. If you’ve read good python programmers’ code before, you might have come across something that looks like this:</p>
<pre><code class="lang-python">add = <span class="hljs-keyword">lambda</span> a,b : a + b
</code></pre>
<p>The code above might look a bit confusing, let me clarify the syntax of a lambda function by breaking it down into its components. Lambda functions have 3 components: the ‘lambda’ keyword (of course), the set of arguments, and an expression.</p>
<pre><code class="lang-python"><span class="hljs-keyword">lambda</span> [(optional) arguments] : [expression]
</code></pre>
<h2 id="heading-the-rules">The Rules</h2>
<p>Before we go into detail about the implementation of lambda functions, let’s first discuss their rules:</p>
<ol>
<li><p>Lambda functions are nameless (unless assigned to a variable). You cannot assign a function name after the ‘lambda’ keyword’ as you would with the ‘def’ keyword.</p>
</li>
<li><p>Arguments are optional. Lambda functions can be defined without passing any arguments, just like a regular function.</p>
</li>
<li><p>Lambda functions can only have one expression.</p>
</li>
<li><p>Just like a regular function, you can return anything from a lambda function. It is also possible to return nothing.</p>
</li>
<li><p>Lambda functions can be assigned to variables for repeated use. This is the only way to name a lambda function.</p>
</li>
<li><p>Lambda functions can be returned from regular functions.</p>
</li>
<li><p>Lambda functions can return other lambda functions.</p>
</li>
</ol>
<h2 id="heading-why-use-lambda-functions">Why Use Lambda Functions?</h2>
<p>If you have never used lambda functions before, you probably think that you would do just fine without them, and you’d be right. However, as I’ve stated before, they play an important role in making sure we maintain clean, compact and pythonic code.</p>
<p>Lambda functions are most useful in situations where an anonymous function is required for single-use or repeated use.</p>
<h3 id="heading-implementation">Implementation</h3>
<p>As stated before, we can use lambda functions alongside regular functions to generate functions. Let’s create an example where we want to create 3 functions. One that doubles a given number, one that triples a given number, and one that quadruples a given number. We could achieve this by creating 3 different functions:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">doubler</span>(<span class="hljs-params">n</span>):</span>
    <span class="hljs-keyword">return</span> n * <span class="hljs-number">2</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">tripler</span>(<span class="hljs-params">n</span>):</span>
    <span class="hljs-keyword">return</span> n * <span class="hljs-number">3</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">quadroupler</span>(<span class="hljs-params">n</span>):</span>
    <span class="hljs-keyword">return</span> n * <span class="hljs-number">4</span>
</code></pre>
<p>Instead of writing the code above, we could create a function that returns a lambda function with the functionality that we want:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">function_generator</span>(<span class="hljs-params">n</span>):</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">lambda</span> a : a * n
</code></pre>
<p>Now we create our desired functions:</p>
<pre><code class="lang-python">doubler = function_generator(<span class="hljs-number">2</span>)
tripler = function_generator(<span class="hljs-number">3</span>)
quadroupler = function_generator(<span class="hljs-number">4</span>)
</code></pre>
<p>The <code>function_generator</code> function returns a function that will multiply its argument to whatever argument was passed to <code>function_generator</code>. We can test this with the following statement:</p>
<pre><code class="lang-python">print(doubler(<span class="hljs-number">4</span>), tripler(<span class="hljs-number">4</span>), quadroupler(<span class="hljs-number">4</span>)) <span class="hljs-comment"># Output 8 12 16</span>
</code></pre>
<p>The function generator can be simplified even further by nesting 2 lambda functions in one line:</p>
<pre><code class="lang-python">function_generator = <span class="hljs-keyword">lambda</span> n : <span class="hljs-keyword">lambda</span> a : a * n
</code></pre>
<p>The previous test line should produce the same output as before.</p>
<p>Remember that a lambda function assigned to a variable makes the variable callable as a function. When introducing the topic, I gave the following example:</p>
<pre><code class="lang-python">add = <span class="hljs-keyword">lambda</span> a,b : a + b
</code></pre>
<p>This makes ‘add’ callable. So to add 2 numbers, we would use the following statement:</p>
<pre><code class="lang-python">add(<span class="hljs-number">4</span>, <span class="hljs-number">6</span>) <span class="hljs-comment"># Returns 10</span>
</code></pre>
<p>This also applies to functions returning lambdas. As long as a lambda function is returned, it is callable, no matter how deep the nesting goes. The function returned also has no name (hence ‘anonymous’) unless it is assigned to a variable.</p>
<p>We can also call a lambda function immediately after its definition:</p>
<pre><code class="lang-python">(<span class="hljs-keyword">lambda</span> x : x * <span class="hljs-number">2</span>)(<span class="hljs-number">4</span>) <span class="hljs-comment"># Returns 8</span>
</code></pre>
<p>Make sure to store/print the value returned as it will not be accessible again later on in your module code. This format is very useful for list comprehensions. </p>
<p>Suppose we have a list of numbers (nums) and we want to generate a new list of numbers such that for each number n in nums, <code>n * 2 &gt; 50</code> should return <code>True</code>. How can we achieve this?</p>
<p>Using a regular function and list comprehension:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">validate</span>(<span class="hljs-params">n</span>):</span>
    <span class="hljs-keyword">return</span> n * <span class="hljs-number">2</span> &gt; <span class="hljs-number">50</span>

nums = [<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">22</span>, <span class="hljs-number">45</span>, <span class="hljs-number">1</span>, <span class="hljs-number">245</span>, <span class="hljs-number">6</span>, <span class="hljs-number">34</span>, <span class="hljs-number">4</span>, <span class="hljs-number">8</span>, <span class="hljs-number">14</span>]
nums2 = [n <span class="hljs-keyword">for</span> n <span class="hljs-keyword">in</span> nums <span class="hljs-keyword">if</span> validate(n)] <span class="hljs-comment"># Returns [45, 245, 34]</span>
</code></pre>
<p>However, we could eliminate the function definition altogether and include the validation expression within the list comprehension:</p>
<p>``python
nums = [3, 1, 4, 22, 45, 1, 245, 6, 34, 4, 8, 14]
nums2 = [n for n in nums if (lambda x : x * 2 &gt; 50)(n)] # Returns [45, 245, 34]
```</p>
<p>Using Python lambda functions makes our code much more compact than in the previous example.</p>
]]></content:encoded></item></channel></rss>