<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohammad Faisal</title>
    <description>The latest articles on DEV Community by Mohammad Faisal (@mohammadfaisal).</description>
    <link>https://dev.to/mohammadfaisal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F580949%2Fee64f98c-f816-4153-adb2-dc4f537b22f2.jpeg</url>
      <title>DEV Community: Mohammad Faisal</title>
      <link>https://dev.to/mohammadfaisal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mohammadfaisal"/>
    <language>en</language>
    <item>
      <title>Setup Mixpanel Analytics in a NextJS Application</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Sun, 01 Dec 2024 10:49:54 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/setup-mixpanel-analytics-in-a-nextjs-application-49ae</link>
      <guid>https://dev.to/mohammadfaisal/setup-mixpanel-analytics-in-a-nextjs-application-49ae</guid>
      <description>&lt;p&gt;Analytics is crucial for any profitable application, whether it’s a small application with 100 users or a large application with 10,000 users.&lt;/p&gt;

&lt;p&gt;Understanding your users is one of the most critical things. And mixpanel is one of the best tools to do that.&lt;/p&gt;

&lt;p&gt;Today, we will learn how to integrate and start mixpanel tracking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup the project
&lt;/h2&gt;

&lt;p&gt;I assume you already have a NextJS project setup. Also, create a new Mixpanel account from &lt;a href="https://mixpanel.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt; (If you haven’t already).&lt;/p&gt;

&lt;p&gt;Keep in mind that I am showing for NextJS but it’s applicable for any ReactJS app too.&lt;/p&gt;

&lt;p&gt;Then, install the dependency&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Get a token
&lt;/h2&gt;

&lt;p&gt;First, add the following environment variable&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXT_PUBLIC_MIXPANEL_TOKEN="YOUR_TOKEN_HERE"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can get the mixpanel token from your project’s dashboard.&lt;/p&gt;

&lt;p&gt;Then go to &lt;strong&gt;Settings&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Project Settings&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Then grab the &lt;strong&gt;Project Token&lt;/strong&gt; and add it in the environment file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Configuration File
&lt;/h2&gt;

&lt;p&gt;Create a file named mixpanel.ts and add the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mixpanel&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mixpanel-browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Define event names as constants to prevent typos&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ANALYTICS_EVENTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;PAGE_VIEW&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Page View&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;BUTTON_CLICK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button Click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;FORM_SUBMIT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Form Submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;USER_SIGNED_IN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User Signed In&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;USER_SIGNED_UP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User Signed Up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;USER_SIGNED_OUT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User Signed Out&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// ... other events&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize mixpanel&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MIXPANEL_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_MIXPANEL_TOKEN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MIXPANEL_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MIXPANEL_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;track_pageview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;persistence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localStorage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ignore_dnt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, initialize the mixpanel as high as possible in your component tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Add Analytics Functions&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now, after you add the configuration, it’s time to add some reusable functions to track mixpanel events. &lt;/p&gt;

&lt;p&gt;So add the following code in the same file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MixpanelAnalytics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;track&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="na"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;CommonEventProperties&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MIXPANEL_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error tracking event:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;pageView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;pageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MIXPANEL_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;MixpanelAnalytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ANALYTICS_EVENTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PAGE_VIEW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pageName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error tracking page view:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you analyze these 2 functions above&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;track&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This function is used to track any kind of event. &lt;/p&gt;

&lt;p&gt;For example, if you want to track a user, click a button to visit an external website. Maybe for affiliate calculation&lt;/p&gt;

&lt;p&gt;You can do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;MixpanelAnalytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;VISIT_WEBSITE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;website_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;website_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;website&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;visit_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;total_website_visits&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  pageView
&lt;/h3&gt;

&lt;p&gt;This is a pretty straightforward method to track every page view inside your application. &lt;/p&gt;

&lt;p&gt;Now remember — when we initialized mixpanel, we already told it to track page views:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MIXPANEL_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;track_pageview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;HERE&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So this custom tracking is only for more detailed analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Know your users
&lt;/h2&gt;

&lt;p&gt;Now, tracking clicks is cool and all, but many times, it’s not enough. &lt;/p&gt;

&lt;p&gt;Maybe you want to track specific users. Maybe you want to know who is doing what. Maybe you are creating a funnel to analyze user behavior. &lt;/p&gt;

&lt;p&gt;For these scenarios,&lt;a href="https://docs.mixpanel.com/docs/tracking-methods/sdks/javascript#managing-user-identity" rel="noopener noreferrer"&gt;mixpanel provides 2 functions&lt;/a&gt;. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;identify &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;reset&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, on a high level, after a user logs in, you can call&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;identify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;whatever identified you want (usually email or userid)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on logout, you can reset it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can also add additional context or details about your users using the &lt;strong&gt;people.set()&lt;/strong&gt; method&lt;/p&gt;

&lt;p&gt;For example,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;people&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enterprise&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// Update "plan" from "Premium" to "Enterprise"&lt;/span&gt;
    &lt;span class="na"&gt;company&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mixpanel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;  &lt;span class="c1"&gt;// Create new "company" profile prop&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are some additional methods like append, union, increment etc., to handle more scenarios, but skip them as they are not the focus of this article. You can read more &lt;a href="https://docs.mixpanel.com/docs/tracking-methods/sdks/javascript#other-types-of-profile-updates" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  But what about anonymous users?
&lt;/h2&gt;

&lt;p&gt;Now, in many applications (especially public sites) — it’s not mandatory to log in to see the contents. &lt;/p&gt;

&lt;p&gt;But how do we track those people if they don’t log in? &lt;/p&gt;

&lt;p&gt;To handle all these scenarios, let’s create two more utility functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MixpanelAnalytics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... other methods ...&lt;/span&gt;

  &lt;span class="na"&gt;identifyKnownUsers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userProperties&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;identify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userProperties&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;people&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userProperties&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error identifying user:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;identifyUnknownUsers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;anonymousId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_distinct_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="s2"&gt;`anon-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nx"&gt;MixpanelAnalytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;identify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;anonymousId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;MixpanelAnalytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPeople&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;$first_seen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;user_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;anonymous&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platform&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error initializing user:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you can track your known and unknown users with this. &lt;/p&gt;

&lt;p&gt;An example usage can look like the following: In one of the root files — (layout.tsx file in app router, _app.tsx in pages router)&lt;/p&gt;

&lt;p&gt;Add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;functionToGetUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;MixpanelAnalytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;identifyKnownUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;MixpanelAnalytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeUnknownUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So this will initialize the user appropriately when they visit the site. &lt;/p&gt;

&lt;p&gt;You can gather data and assign it to this particular user going forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example usage
&lt;/h2&gt;

&lt;p&gt;Now comes the fun part. Notice the following code and update it according to your needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handleClick = () =&amp;gt; {
  MixpanelAnalytics.setPeople({
    $last_visited: websiteName,
    last_visit_date: new Date().toISOString(),
    total_visits: (mixpanel.get_property('total_visits') ?? 0) + 1,
  });

  MixpanelAnalytics.track(ANALYTICS_EVENTS.VISIT_WEBSITE, {
    website_name: websiteName,
    website_url: website,
    visit_count: (mixpanel.get_property('total_visits') ?? 0) + 1,
  });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above function we are tracking the particular user’s profile with the tracking data and also making sure that we are counting their visits to the particular website as well.&lt;/p&gt;

&lt;p&gt;Cool right? &lt;/p&gt;

&lt;h2&gt;
  
  
  Best practices
&lt;/h2&gt;

&lt;p&gt;When working with analytics — it’s very important to keep the data consistent. &lt;/p&gt;

&lt;p&gt;So, make sure to add proper types for analytics events. &lt;/p&gt;

&lt;p&gt;For example &lt;/p&gt;

&lt;h3&gt;
  
  
  Define constants for the events.
&lt;/h3&gt;

&lt;p&gt;Never use plain strings for event names.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ANALYTICS_EVENTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;PAGE_VIEW&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Page View&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;BUTTON_CLICK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button Click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// ... other events&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Type safety
&lt;/h3&gt;

&lt;p&gt;For events payload, make sure to use consistent structure by using types&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CommonEventProperties&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;referrer&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  User Properties
&lt;/h3&gt;

&lt;p&gt;Always maintain consistent user properties across sessions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MixpanelAnalytics.setPeople({
  $email: user.email,
  $name: user.user_metadata?.full_name,
  $created: user.created_at,
  last_sign_in: new Date().toISOString(),
  user_type: 'registered',
  auth_provider: user.app_metadata?.provider || 'email',
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otherwise, down the road, the data will be useless.&lt;/p&gt;

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

&lt;p&gt;Remember to handle analytics initialization properly in your client-side components.&lt;/p&gt;

&lt;p&gt;Also, ensure that sensitive user data is handled appropriately according to your privacy policy and data protection regulations.&lt;/p&gt;

&lt;p&gt;Hope you learned something new today.&lt;/p&gt;

&lt;p&gt;Have a great day!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>NextJS Internationalization using Google Translator</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Mon, 26 Aug 2024 18:00:00 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/nextjs-internationalization-using-google-translator-4pgk</link>
      <guid>https://dev.to/mohammadfaisal/nextjs-internationalization-using-google-translator-4pgk</guid>
      <description>&lt;p&gt;How to internationalize a NextJS website?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup a CMS or use i18n&lt;/li&gt;
&lt;li&gt;Connect each piece of text with a key in the translation file.&lt;/li&gt;
&lt;li&gt;Translate each piece of text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But all of these take a huge amount of time.&lt;/p&gt;

&lt;p&gt;Today I will show you the fastest way to add internationalization in a NextJS website. &lt;/p&gt;

&lt;p&gt;In 10 minutes you are going to have a fully translated website using the power of Google Translate.&lt;/p&gt;

&lt;p&gt;** Here is the &lt;a href="https://nextjs-internationalization-with-google-translate.vercel.app/" rel="noopener noreferrer"&gt;demo&lt;/a&gt; and here is the &lt;a href="https://github.com/Mohammad-Faisal/nextjs-internationalization-with-google-translate" rel="noopener noreferrer"&gt;github project&lt;/a&gt; **&lt;/p&gt;

&lt;p&gt;Let’s begin!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create a new project
&lt;/h2&gt;

&lt;p&gt;Creating a new NextJS project is simple. Just run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On your local machine create a basic NextJS project.&lt;/p&gt;

&lt;p&gt;Also, we need to install a dependency named nookies . This will be used for cookie management.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add nookies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are done with dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Configure the public folder
&lt;/h2&gt;

&lt;p&gt;Create 2 files under the public/assets directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  a. lang-config.js
&lt;/h3&gt;

&lt;p&gt;Create the following file in &lt;strong&gt;public/assets/lang-config.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__GOOGLE_TRANSLATION_CONFIG__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;English&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Deutsch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Español&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Français&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;defaultLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file defines the available languages and the default language. &lt;/p&gt;

&lt;p&gt;You can add whatever language is supported by Google Translate here.&lt;/p&gt;

&lt;h3&gt;
  
  
  b. translation.js
&lt;/h3&gt;

&lt;p&gt;Create another file in &lt;strong&gt;public/assets/translation.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TranslateInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__GOOGLE_TRANSLATION_CONFIG__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TranslateElement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;pageLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__GOOGLE_TRANSLATION_CONFIG__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultLanguage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file checks for the configuration and initializes the Google translator on the site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Import scripts
&lt;/h2&gt;

&lt;p&gt;Now it’s time to import these scripts into the project. &lt;/p&gt;

&lt;p&gt;Head over to the &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;root &lt;code&gt;layout.tsx&lt;/code&gt; file (if you are using app router)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;or &lt;code&gt;_document.tsx&lt;/code&gt; file (if you are using pages router)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And use NextJS’s Script tag to include these scripts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/assets/lang-config.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;beforeInteractive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/assets/translation.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;beforeInteractive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;//translate.google.com/translate_a/element.js?cb=TranslateInit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;afterInteractive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;google_translate_element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s understand what’s going on here.&lt;/p&gt;

&lt;p&gt;The first 2 &lt;strong&gt;Script&lt;/strong&gt; tags are loading the config and initialization. We used strategy &lt;strong&gt;beforeInteractive&lt;/strong&gt; to ensure that they are available from the get-go of the site.&lt;/p&gt;

&lt;p&gt;The third &lt;strong&gt;script&lt;/strong&gt; is the script that does the actual translation for us. This can be loaded after the hydration so we used strategy &lt;strong&gt;afterInteractive&lt;/strong&gt; here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Create the language switcher
&lt;/h2&gt;

&lt;p&gt;Now comes the most important component. &lt;/p&gt;

&lt;p&gt;Create a new component named language-switcher.tsx and add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parseCookies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCookie&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nookies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// The following cookie name is important because it's Google-predefined for the translation engine purpose&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;COOKIE_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;googtrans&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// We should know a predefined nickname of a language and provide its title (the name for displaying)&lt;/span&gt;
    &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;LanguageDescriptor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Types for JS-based declarations in public/assets/scripts/lang-config.js&lt;/span&gt;
    &lt;span class="nx"&gt;declare&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;globalThis&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;__GOOGLE_TRANSLATION_CONFIG__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nl"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LanguageDescriptor&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
                &lt;span class="nl"&gt;defaultLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LanguageSwitcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currentLanguage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCurrentLanguage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;languageConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLanguageConfig&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Initialize translation engine&lt;/span&gt;
        &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// 1. Read the cookie&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseCookies&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;existingLanguageCookieValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;COOKIE_NAME&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;languageValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingLanguageCookieValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// 2. If the cookie is defined, extract a language nickname from there.&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;existingLanguageCookieValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;languageValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// 3. If __GOOGLE_TRANSLATION_CONFIG__ is defined and we still not decided about languageValue - use default one&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__GOOGLE_TRANSLATION_CONFIG__&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;languageValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;languageValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__GOOGLE_TRANSLATION_CONFIG__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultLanguage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;languageValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// 4. Set the current language if we have a related decision.&lt;/span&gt;
                &lt;span class="nf"&gt;setCurrentLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;languageValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// 5. Set the language config.&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__GOOGLE_TRANSLATION_CONFIG__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;setLanguageConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__GOOGLE_TRANSLATION_CONFIG__&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

        &lt;span class="c1"&gt;// Don't display anything if current language information is unavailable.&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;currentLanguage&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;languageConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// The following function switches the current language&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;switchLanguage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// We just need to set the related cookie and reload the page&lt;/span&gt;
            &lt;span class="c1"&gt;// "/auto/" prefix is Google's definition as far as a cookie name&lt;/span&gt;
            &lt;span class="nf"&gt;setCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;COOKIE_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/auto/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-center notranslate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;languageConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LanguageDescriptor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentLanguage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentLanguage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;languageConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultLanguage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`l_s_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mx-3 text-orange-300&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
                                &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`l_s_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                                &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;switchLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
                                &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mx-3 text-blue-300 cursor-pointer hover:underline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                            &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                        &lt;span class="p"&gt;)}&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="p"&gt;))}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LanguageSwitcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;COOKIE_NAME&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is pretty self-explanatory. But let me give you an overview.&lt;/p&gt;

&lt;p&gt;This has to be a client component as we are using useEffect and useState .&lt;/p&gt;

&lt;p&gt;First, we read the cookies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const COOKIE_NAME = 'googtrans';

const cookies = parseCookies();
const existingLanguageCookieValue = cookies[COOKIE_NAME];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cookies tell us which language is selected. If nothing is found we take the default language.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (global.__GOOGLE_TRANSLATION_CONFIG__ &amp;amp;&amp;amp; !languageValue) {
    languageValue = global.__GOOGLE_TRANSLATION_CONFIG__.defaultLanguage;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otherwise&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (languageValue) {
   setCurrentLanguage(languageValue);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we set the current global config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (global.__GOOGLE_TRANSLATION_CONFIG__) {
   setLanguageConfig(global.__GOOGLE_TRANSLATION_CONFIG__);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we have a function to switch the language. This is again as simple as setting the cookie name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const switchLanguage = (lang: string) =&amp;gt; () =&amp;gt; {
    setCookie(null, COOKIE_NAME, '/auto/' + lang);
    window.location.reload();
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s basically it. You have freedom about the language you want to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Use it
&lt;/h2&gt;

&lt;p&gt;Now the only thing to do is add this component somewhere. I am adding it to the page.tsx file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { LanguageSwitcher } from '@/components/language-switcher';

export default function Home() {
  return (
      &amp;lt;main className="flex"&amp;gt;
          &amp;lt;LanguageSwitcher /&amp;gt;
          &amp;lt;div&amp;gt;
              {`Add some text here to test`}
          &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;
  );
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then if you run the application&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the following.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2fpjkwjbumk9p0rau52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2fpjkwjbumk9p0rau52.png" alt="translator with google translation tab" width="450" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beautiful! You can switch between the buttons to see how the translations work! &lt;/p&gt;

&lt;p&gt;But there is a bar at the top. Which is not beautiful. We can easily remove it using a little CSS trick.&lt;/p&gt;

&lt;p&gt;Add the following to your globals.css file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;    &lt;span class="nc"&gt;.skiptranslate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voila! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1b0m4de0oylef4336dmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1b0m4de0oylef4336dmz.png" alt="translator without google translation tab" width="450" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now you have a working language switcher that can support over 200 languages. &lt;/p&gt;

&lt;p&gt;All you have to do is add a new language to the lang-config.js file under the public/assets folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;This is by far the fastest way to translate a website. &lt;/p&gt;

&lt;p&gt;But…&lt;/p&gt;

&lt;p&gt;You have less control over the content as Google Translate will do all the work.&lt;/p&gt;

&lt;p&gt;Also probably not good for SEO optimization.&lt;/p&gt;

&lt;p&gt;But completely fine for informational websites or landing pages.&lt;/p&gt;

&lt;p&gt;Hope you have a wonderful day ahead! &lt;/p&gt;

&lt;p&gt;Github Repo: &lt;a href="https://github.com/Mohammad-Faisal/nextjs-internationalization-with-google-translate" rel="noopener noreferrer"&gt;https://github.com/Mohammad-Faisal/nextjs-internationalization-with-google-translate&lt;/a&gt;&lt;br&gt;
Live demo: &lt;a href="https://nextjs-internationalization-with-google-translate.vercel.app/" rel="noopener noreferrer"&gt;https://nextjs-internationalization-with-google-translate.vercel.app/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I improved score from 21 to 61 for a Production Nextjs site.</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Fri, 23 Aug 2024 17:01:22 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/techniques-to-optimize-a-nextjs-website-4668</link>
      <guid>https://dev.to/mohammadfaisal/techniques-to-optimize-a-nextjs-website-4668</guid>
      <description>&lt;p&gt;Recently, I had to improve the performance of a Production NextJS website.&lt;/p&gt;

&lt;p&gt;You can visit the website here (the changes are not live yet)&lt;br&gt;
&lt;a href="https://www.invygo.com/en-ae" rel="noopener noreferrer"&gt;Invygo Rent-A-Car&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, I will explain how we did it and the thought process.&lt;/p&gt;
&lt;h3&gt;
  
  
  Let’s start with the score
&lt;/h3&gt;

&lt;p&gt;Here is where we started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4232%2F1%2AXs3qh2MxAVYCci0lGCBDLA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4232%2F1%2AXs3qh2MxAVYCci0lGCBDLA.png" alt="start"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a fair comparison, I deployed it to a test account using Vercel, and I will use this one for all benchmarks.&lt;/p&gt;

&lt;p&gt;My focus is not only on technical improvement — but also on improving the user experience.&lt;/p&gt;

&lt;p&gt;Let’s go…&lt;/p&gt;
&lt;h2&gt;
  
  
  Optimization 1: Parallel request.
&lt;/h2&gt;

&lt;p&gt;Our filter page makes 4 API calls to get the appropriate filters for that region.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4636%2F1%2Ab0ejejQGsPquMylY7zN8qQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4636%2F1%2Ab0ejejQGsPquMylY7zN8qQ.png" alt="Parallel request"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But as you can assume, nothing is stopping us from making these requests parallel.&lt;/p&gt;

&lt;p&gt;It was simply wrapping everything into a Promise.all() .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A41pdAIhVH3JdNfSgmffVww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A41pdAIhVH3JdNfSgmffVww.png" alt="parallel request"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This optimization improved the experience, but I didn’t benchmark the improvement.&lt;/p&gt;
&lt;h2&gt;
  
  
  Optimization 2: Static generation of the pages.
&lt;/h2&gt;

&lt;p&gt;Our pages were server-side rendered using getServerSideProps . However, as we can already predict the initial pages, the second thing I did was generate those pages statically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4216%2F1%2AGgwVG1OebvM8LMKLj9OWGQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4216%2F1%2AGgwVG1OebvM8LMKLj9OWGQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main benefit is that we already have the pages generated during the build time, so when a user clicks on a button to view the page, we don’t have to make the 4 API calls we discussed above on the first load.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4904%2F1%2AXMyKdmkl61zBrxippIRYOQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4904%2F1%2AXMyKdmkl61zBrxippIRYOQ.png" alt="Score after the second optimization"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It improves the score and enhances the user experience.&lt;/p&gt;
&lt;h2&gt;
  
  
  Optimization 3: Prefetch the static pages
&lt;/h2&gt;

&lt;p&gt;I wanted to take this one step further to improve the user experience even more.&lt;/p&gt;

&lt;p&gt;We can use the Next Link component to prefetch URLs.&lt;/p&gt;

&lt;p&gt;However, the pages we are discussing are referenced from many places on the website, as we want users to visit these pages frequently.&lt;/p&gt;

&lt;p&gt;That’s why I decided to prefetch these 5–6 URLs whenever any user lands on any page of our website.&lt;/p&gt;

&lt;p&gt;The way to do that is to create a custom component named. PrefetchStaticPaths&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const PrefetchStaticPaths: React.FC = () =&amp;gt; {
  const router = useRouter();

  useEffect(() =&amp;gt; {
    const prefetchPaths = async () =&amp;gt; {
      const paths = [...] // list of paths that you want to prefetch

      for (const path of paths) {
        await router.prefetch(path);
      }
    };

    prefetchPaths();
  }, [router]);

  return null;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I included this component in the _app.tsx file.&lt;/p&gt;

&lt;p&gt;This means that the pages will be ready to view whenever a user visits the website. And when you try to visit, it will be almost instant.&lt;/p&gt;

&lt;p&gt;I also improved the above code to make those requests parallel.&lt;/p&gt;

&lt;p&gt;So, the modified version looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const prefetchPromises = paths.map((path) =&amp;gt; {
  const startTime = performance.now();
  console.log('Start prefetching path:', path);

  return router
    .prefetch(path)
    .then(() =&amp;gt; {
      const endTime = performance.now();
      const duration = endTime - startTime;
      console.log(`Finished prefetching path: ${path}. Time taken: ${duration.toFixed(2)}ms`);
    })
    .catch((error) =&amp;gt; {
      console.error(`Error prefetching path: ${path}`, error);
    });
});

await Promise.all(prefetchPromises);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This surely improved the user experience but didn’t have much impact on the page speed score.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2178%2F1%2ANTtjHo9KYbqmSfPTJ1pt8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2178%2F1%2ANTtjHo9KYbqmSfPTJ1pt8g.png" alt="Score 29"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimization 4: Optimize large images.
&lt;/h2&gt;

&lt;p&gt;Images are often among the heaviest parts of any page. On our filter page, several banners increased the page size.&lt;/p&gt;

&lt;p&gt;There is a nice free tool called &lt;a href="https://tinypng.com/" rel="noopener noreferrer"&gt;TinyPng&lt;/a&gt;. You can drop the images there and get similar-looking images of much smaller sizes.&lt;/p&gt;

&lt;p&gt;Here is what it looked like in the conversion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2502%2F1%2AhmSXj5nRRu36qPbvTc0dMQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2502%2F1%2AhmSXj5nRRu36qPbvTc0dMQ.png" alt="65% improvement"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tool alone reduced the image size by 65%, which is pretty significant. We are talking about 300kb savings for each image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want to Take it even further?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are other tools you can use even further. Like &lt;a href="https://imagecompressor.com/" rel="noopener noreferrer"&gt;Image compressor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tool allows you to specify the number of colours, which can reduce the image sizes by an additional 50%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2314%2F1%2A0Uag0ktb11LOYTBVJ73kFA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2314%2F1%2A0Uag0ktb11LOYTBVJ73kFA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Usually, the PNG images use 256 colors. But if you use 8, you can get another 50% optimized image.&lt;/p&gt;

&lt;p&gt;But don’t overuse it because it can reduce the quality visually.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2202%2F1%2AWrq181ZcuZW14Jv7U8KQpQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2202%2F1%2AWrq181ZcuZW14Jv7U8KQpQ.png" alt="Score 35"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimization 5: Optimize Script Loading
&lt;/h2&gt;

&lt;p&gt;Any serious production application will have many tracking tools. Our app is no different. We are using Google Tag Manager and some other tools.&lt;/p&gt;

&lt;p&gt;No NextJS offers a nice way to load these scripts lazily.&lt;/p&gt;

&lt;p&gt;We have to add the strategy to the script tag.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2As6FMSnZRiZ2YbwWJPrNwRg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2As6FMSnZRiZ2YbwWJPrNwRg.png" alt="Lazy loading of scripts."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This reduces the time for the initial load.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2234%2F1%2A37ylrnk2Bc3js335y4AmJg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2234%2F1%2A37ylrnk2Bc3js335y4AmJg.png" alt="Score 46"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimization 6: Code splitting and lazy loading.
&lt;/h2&gt;

&lt;p&gt;Not everything needs to be loaded on the first build. You can identify which components are loading more stuff than required if you inspect the output when you run yarn build&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AYVxbz_w4tw4D_uXvZi7CMg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AYVxbz_w4tw4D_uXvZi7CMg.png" alt="Output of yarn build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see that we have a section called &lt;strong&gt;First Load JS shared by all.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These resources will be loaded no matter what.&lt;/p&gt;

&lt;p&gt;Let’s take a deeper look.&lt;/p&gt;

&lt;p&gt;If you check the name, you will see one is framework , and another one is main . We will check that later, but for now, focus on the one that starts with _app .&lt;/p&gt;

&lt;p&gt;This file is shared across the whole project, so whatever you load here will be loaded everywhere. So, it's very important to make sure that everything is correct here.&lt;/p&gt;

&lt;p&gt;One way to load things efficiently is by loading components dynamically. Including the scripts.&lt;/p&gt;

&lt;p&gt;So, I converted the imports from&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import BottomNavbar from '@/widgets/navigation/BottomNavBar';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;into&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const BottomNavbar = dynamic(() =&amp;gt; import('@/widgets/navigation/BottomNavBar'), { ssr: false });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And did this for all components.&lt;/p&gt;

&lt;p&gt;Now, look at the output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AR4n-9g2IrxxW9tWMn4CzJQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AR4n-9g2IrxxW9tWMn4CzJQ.png" alt="Chunks after optimization."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, using this simple trick, we slashed off 60kb. Not bad, huh?&lt;/p&gt;

&lt;h2&gt;
  
  
  The final result so far
&lt;/h2&gt;

&lt;p&gt;After doing all of these, our current score is following&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2308%2F1%2A6LBStRgNG3WxGI86CzRBKA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2308%2F1%2A6LBStRgNG3WxGI86CzRBKA.png" alt="Score so far"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s not great, but at least it’s usable now, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Can we go even further?
&lt;/h2&gt;

&lt;p&gt;Yes. How?&lt;/p&gt;

&lt;p&gt;Well… let me tell you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potential 1: Analyze the bundle
&lt;/h3&gt;

&lt;p&gt;There is a nice tool called &lt;a href="https://www.npmjs.com/package/webpack-bundle-analyzer" rel="noopener noreferrer"&gt;**webpack bundle analyzer&lt;/a&gt;. **You can hook this tool with your NextJS project to see which part of the output is casing the heaviest load.&lt;/p&gt;

&lt;p&gt;I ran it, and I saw the following.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6884%2F1%2ARnCinaQuwhofeWfxNjCFzQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6884%2F1%2ARnCinaQuwhofeWfxNjCFzQ.png" alt="Webpack bundle analyzer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we have used an icon library called lucide-react . And this is taking up the bulk of the space.&lt;/p&gt;

&lt;p&gt;We need custom icons to replace it, which will take some time to manage. So that’s for another day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potential 2: Analyze the packages
&lt;/h3&gt;

&lt;p&gt;When we are using the libraries on a project, we often do not consider their size.&lt;/p&gt;

&lt;p&gt;Another tool is &lt;a href="https://bundlephobia.com/" rel="noopener noreferrer"&gt;**BundlePhobia&lt;/a&gt;. **It allows you to check the size of any package, decide if it’s too heavy, and maybe use an alternative.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6768%2F1%2AvtQSrqJK3g7TLuBWgBYPAQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6768%2F1%2AvtQSrqJK3g7TLuBWgBYPAQ.png" alt="Bundlephobia"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, I will do this in the coming days to see how far we can take it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Remarks
&lt;/h2&gt;

&lt;p&gt;Optimizing any website is a constant process and battle. In this article, I tried to show some of the ways we can use it- there are, of course, many more.&lt;/p&gt;

&lt;p&gt;Let's talk about those some other day.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed it. Have a great day! :D&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using Digital Ocean Spaces as Strapi Storage</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Thu, 16 May 2024 11:50:03 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/using-digital-ocean-spaces-as-strapi-storage-4agk</link>
      <guid>https://dev.to/mohammadfaisal/using-digital-ocean-spaces-as-strapi-storage-4agk</guid>
      <description>&lt;p&gt;To read more articles like this, &lt;a href="https://www.mdfaisal.com/blog"&gt;visit my blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So recently, I migrated a website from WordPress to Strapi + NextJS.&lt;/p&gt;

&lt;p&gt;The client didn’t want Strapi’s own cloud service and wanted to stick to Digital Ocean as he already knows that well.&lt;/p&gt;

&lt;p&gt;So, I set up Strapi on Digital Ocean using their &lt;a href="https://docs.strapi.io/dev-docs/deployment/digitalocean-app-platform"&gt;app service&lt;/a&gt;, which is, I would say, not " beginner-friendly” but should be easy enough for someone technical.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;So after I uploaded a couple of content with images. They worked pretty well.&lt;/p&gt;

&lt;p&gt;But as soon as I added a new field to a new collection or do anything that triggers a new build the images were gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Issue
&lt;/h2&gt;

&lt;p&gt;The problem was that strapi, by default, uses a local upload provider. A local provider means the images are stored on the machine.&lt;/p&gt;

&lt;p&gt;Every time you build — the machine restarts, and the images are gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;The solution is to use persistent storage. In fact, Strapi provides several options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.strapi.io/dev-docs/plugins/upload#using-a-provider"&gt;&lt;strong&gt;Upload | Strapi Documentation&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, here is another problem. Strapi’s official documentation supports&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://market.strapi.io/providers/@strapi-provider-upload-aws-s3"&gt;Amazon S3&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://market.strapi.io/providers/@strapi-provider-upload-cloudinary"&gt;Cloudinary&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But my client wanted to stick to Digital Ocean. So what to do?&lt;/p&gt;

&lt;h2&gt;
  
  
  Comes the Digital ocean spaces
&lt;/h2&gt;

&lt;p&gt;Digital Ocean Spaces is actually an S3-compatible storage provider, which means it only provides a wrapper on top of the S3.&lt;/p&gt;

&lt;p&gt;To use this, First, create a digital ocean space using the following guide&lt;br&gt;
&lt;a href="https://docs.digitalocean.com/products/spaces/how-to/create/"&gt;&lt;strong&gt;How to Create a Spaces Bucket | DigitalOcean Documentation&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, get the access key and the secret access key using this guide.&lt;br&gt;
&lt;a href="https://docs.digitalocean.com/products/spaces/how-to/manage-access/#access-keys"&gt;&lt;strong&gt;How to Manage Administrative Access to Spaces | DigitalOcean Documentation&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Install AWS provider
&lt;/h2&gt;

&lt;p&gt;Now, go to the Strapi application and install &lt;a href="https://www.npmjs.com/package/@strapi/provider-upload-aws-s3"&gt;s3 provider&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @strapi/provider-upload-aws-s3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open up your plugins.ts file and add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default ({ env }) =&amp;gt; ({
  // ... other configs,
  upload: {
    config: {
  provider: "aws-s3",
      providerOptions: {
        credentials: {
          accessKeyId: env("DO_SPACE_ACCESS_KEY"),
          secretAccessKey: env("DO_SPACE_SECRET_KEY"),
        },
        region: env("DO_SPACE_REGION"),
        endpoint: env("DO_SPACE_ENDPOINT"),
        params: {
          Bucket: env("DO_SPACE_BUCKET"),
        },
      },
      actionOptions: {
        upload: {},
        uploadStream: {},
        delete: {},
      },
    },
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, add the following values to the &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DO_SPACE_ACCESS_KEY=___
DO_SPACE_SECRET_KEY=___
DO_SPACE_ENDPOINT=https://fra1.digitaloceanspaces.com
DO_SPACE_BUCKET=YOUR_BUCKET_NAME
DO_SPACE_REGION=REGION_NAME (in this case fra1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice several things.&lt;/p&gt;

&lt;p&gt;The space endpoint can’t have the bucket name at the beginning. This is a very common mistake that is not mentioned in the docs.&lt;/p&gt;

&lt;p&gt;So if your Origin Endpoint looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://any-bucket-name.fra1.digitaloceanspaces.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your &lt;code&gt;DO_SPACE_ENDPOINT value should be&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://fra1.digitaloceanspaces.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And obviously, the region will be &lt;code&gt;fra1&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Modify Middleware
&lt;/h2&gt;

&lt;p&gt;You are not done yet. Although this will work, when you visit the CMS, you will see that the previews are not loading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bSuZ4NvG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4948/1%2Az1oWI_fdEameTPi9Ihvoqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bSuZ4NvG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4948/1%2Az1oWI_fdEameTPi9Ihvoqg.png" alt="" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To fix this, we have to allow Strapi access to the S3 bucket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let’s do that…&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now open the &lt;code&gt;middlewares.ts&lt;/code&gt; file and add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default [  
// ...others 
{
    name: "strapi::security",
    config: {
      contentSecurityPolicy: {
        useDefaults: true,
        directives: {
          "connect-src": ["'self'", "https:"],
          "img-src": [
            "'self'",
            "data:",
            "blob:",
            "strapi.io",
            "{BUCKET_NAME}.s3.{REGION}.amazonaws.com",
            "https://{BUCKET_NAME}.s3.{REGION}.amazonaws.com"
          ],
          "media-src": [
            "'self'",
            "data:",
            "blob:",
            "strapi.io",
            "{BUCKET_NAME}.s3.{REGION}.amazonaws.com",
            "https://{BUCKET_NAME}.s3.{REGION}.amazonaws.com"
          ],
          upgradeInsecureRequests: null,
        },
      },
    },
  },
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Notice a few things
&lt;/h3&gt;

&lt;p&gt;Replace the BUCKET_NAME and the REGION values in the &lt;code&gt;middlewares.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then restart your Strapi server, and you should be able to upload images to the digital ocean spaces.&lt;/p&gt;

&lt;p&gt;This configuration should fix the issues, and you will see the previews.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--adqKITWn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4916/1%2AsRd3bzgZTcr0lTM5Su0rPA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--adqKITWn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4916/1%2AsRd3bzgZTcr0lTM5Su0rPA.png" alt="Previews." width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upload an image and check the spaces to verify that it’s working. Also, don’t forget to add the &lt;code&gt;.env&lt;/code&gt; variables to your digital ocean dashboard.&lt;/p&gt;

&lt;p&gt;Thank you for reading this far! Have a great day!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have something to say? Get in touch with me via &lt;a href="https://www.linkedin.com/in/56faisal/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://www.mdfaisal.com/"&gt;Personal Website&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Ditch Your Boring Terminal and Make it More Useful</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Sat, 11 May 2024 11:00:13 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/ditch-your-boring-terminal-and-make-it-more-useful-1hj8</link>
      <guid>https://dev.to/mohammadfaisal/ditch-your-boring-terminal-and-make-it-more-useful-1hj8</guid>
      <description>&lt;p&gt;To read more articles like this, &lt;a href="https://www.mohammadfaisal.dev/blog" rel="noopener noreferrer"&gt;visit my blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3560%2F1%2AYFmXV59l20C0HqxXgmmMiQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3560%2F1%2AYFmXV59l20C0HqxXgmmMiQ.png" alt="Expected design"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contrary to popular opinion, programmers are human. We like nice things. And the terminal is one of the most important things that we use on a day-to-day basis.&lt;/p&gt;

&lt;p&gt;So why live with a boring terminal when you can make it colourful and fun?&lt;/p&gt;

&lt;p&gt;Today, we will do precisely that. Let’s begin!&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Homebrew
&lt;/h2&gt;

&lt;p&gt;If you are using a mac, you are most probably already familiar with &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;homebrew&lt;/a&gt;. It helps with installing software on macOS.&lt;/p&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bin/bash -c "$(curl -fsSL [https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh](https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh))"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may need to install the CLI tools for XCode before that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xcode-select —-install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get an error, run the following command to reset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xcode-select -r
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Install Iterm2
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://iterm2.com/" rel="noopener noreferrer"&gt;Iterm2&lt;/a&gt; is a terminal emulator for macOS. It’s kind of a replacement for your original terminal. It comes with a bunch of cool features and customizations that we will go over later&lt;/p&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew cask install iterm2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Install ZSH
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/robbyrussell/oh-my-zsh/wiki/Installing-ZSH" rel="noopener noreferrer"&gt;ZSH&lt;/a&gt;, also called the Z shell, is an extended version of the Bourne Shell (sh). it has some advanced features like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Automatic cd: Just type the name of the directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plugin and theme support: ZSH has many plugin and theme frameworks to boost up your terminal even more.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To install it run the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;And you should be set up.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Install Oh My ZSH
&lt;/h2&gt;

&lt;p&gt;According to their &lt;a href="https://ohmyz.sh/" rel="noopener noreferrer"&gt;website&lt;/a&gt;…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Oh My Zsh is a delightful, open source, community-driven framework for managing your Zsh configuration&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In short, it will help you to manage the configuration and customizations for your Z Shell.&lt;/p&gt;

&lt;p&gt;To install, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, now, you have the basic setup complete.&lt;/p&gt;

&lt;p&gt;You should already have a nice-looking terminal than before.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Customize the Theme
&lt;/h2&gt;

&lt;p&gt;Now restart your iTerm2 and type the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;it will open the config file with a text editor. You can also use nano if you like.&lt;/p&gt;

&lt;p&gt;Now there will be a variable named &lt;code&gt;ZSH_THEME&lt;/code&gt; . And the value there is &lt;code&gt;robbyrussell&lt;/code&gt; . If we set it to random, then every time we open our terminal, a new theme will be loaded&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A5OtbygU3hHB-q8lqVQxKYA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A5OtbygU3hHB-q8lqVQxKYA.png" alt="ZSH THEME"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, you can choose from a wide variety of themes &lt;a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Themes" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s use a popular custom theme named &lt;a href="https://github.com/romkatv/powerlevel10k" rel="noopener noreferrer"&gt;powerlevel10k&lt;/a&gt;. First, install it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then set the theme name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZSH_THEME="powerlevel10k/powerlevel10k"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then save the file and run the following command from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exec zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open iterm2 again and configure the terminal by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p10k configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will take you through the configuration process and at the end of it, you will have a nice-looking terminal!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2612%2F1%2AwhrUnqpW-OMhs8utZzkPtQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2612%2F1%2AwhrUnqpW-OMhs8utZzkPtQ.png" alt="Colorful Terminal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Customize with Plugins
&lt;/h2&gt;

&lt;p&gt;Plugins are what make the zsh so powerful and fun to use. There are a lot of plugins that you can find &lt;a href="https://project-awesome.org/unixorn/awesome-zsh-plugins" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Let’s try one of them!&lt;/p&gt;

&lt;p&gt;Do you like typing? I guess not. We can have some autosuggestion inside our terminal by using a plugin named &lt;a href="https://github.com/zsh-users/zsh-autosuggestions" rel="noopener noreferrer"&gt;zsh-autosuggestions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/zsh-users/zsh-autosuggestions $ZSH_CUSTOM/plugins/zsh-autosuggestions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open up your &lt;code&gt;.zshrc&lt;/code&gt; file. And find the plugins section. You will see there is already a &lt;code&gt;plugin&lt;/code&gt; there (git). Add our new plugin.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AZqaX3OojsuOS0_z71Y_N-A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AZqaX3OojsuOS0_z71Y_N-A.png" alt="ADD A NEW PLUGIN"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it. Now when you want to type a command the terminal will give you suggestions!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2612%2F1%2ANJNZWQxnpJ8ZXHwkLH5uyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2612%2F1%2ANJNZWQxnpJ8ZXHwkLH5uyg.png" alt="Auto Suggestions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;There are a lot of things that you can do with oh my &lt;code&gt;zsh&lt;/code&gt; . I have shown the absolute basics here. I hope you enjoyed it.&lt;/p&gt;

&lt;p&gt;Have a great day!&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.freecodecamp.org/news/how-to-configure-your-macos-terminal-with-zsh-like-a-pro-c0ab3f3c1156/" rel="noopener noreferrer"&gt;https://www.freecodecamp.org/news/how-to-configure-your-macos-terminal-with-zsh-like-a-pro-c0ab3f3c1156/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/tech-explained/4-simple-steps-to-create-an-awesome-terminal-experience-on-your-mac-70bd7a0e1b59" rel="noopener noreferrer"&gt;https://medium.com/tech-explained/4-simple-steps-to-create-an-awesome-terminal-experience-on-your-mac-70bd7a0e1b59&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Have something to say? Get in touch with me via &lt;a href="https://www.linkedin.com/in/56faisal/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://www.mdfaisal.com/" rel="noopener noreferrer"&gt;Personal Website&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>javascript</category>
      <category>aws</category>
    </item>
    <item>
      <title>Why NVM is Tremendously Helpful for Web Developers</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Sat, 11 May 2024 10:31:49 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/why-nvm-is-tremendously-helpful-for-web-developers-17i9</link>
      <guid>https://dev.to/mohammadfaisal/why-nvm-is-tremendously-helpful-for-web-developers-17i9</guid>
      <description>&lt;p&gt;To read more articles like this, &lt;a href="https://www.mdfaisal.com/blog" rel="noopener noreferrer"&gt;visit my blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you work in the Node.js ecosystem, you’ve probably heard about the Node version manager (NVM).&lt;/p&gt;

&lt;p&gt;Today, we will see why this exists and why you should care about learning it.&lt;/p&gt;

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

&lt;p&gt;According to the &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;nvm&lt;/code&gt; allows you to quickly install and use different versions of Node.js via the command line.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Apart from that, it also keeps you away from many errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem at hand
&lt;/h3&gt;

&lt;p&gt;Have you ever encountered the &lt;code&gt;EACCESS&lt;/code&gt; error when installing a global npm package?&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;I bet you have! But what’s the solution? Some StackOverflow answers suggest you use &lt;code&gt;sudo&lt;/code&gt;, which is a very bad idea and can lead to more problems.&lt;/p&gt;

&lt;p&gt;The official &lt;a href="https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally" rel="noopener noreferrer"&gt;npm docs&lt;/a&gt; suggest that we use &lt;code&gt;node version manager (nvm)&lt;/code&gt; to resolve this issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install NVM
&lt;/h2&gt;

&lt;p&gt;If you are using Linux, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it’s successful you can check the version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;command -v nvm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may have to close your terminal and reopen it again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the Latest Version of Node.js
&lt;/h2&gt;

&lt;p&gt;If we want to install the latest version of the node we can run the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;At the time of writing this article, the latest version of the Node.js is &lt;code&gt;v17.3.0&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Specific Version of Node.js
&lt;/h2&gt;

&lt;p&gt;At the time of writing this article, the latest version of Node.js is &lt;code&gt;16.13.1&lt;/code&gt; . If we want to install this specific version:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Check the installed versions
&lt;/h2&gt;

&lt;p&gt;If you want to see the list of versions installed on your machine run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will show the versions on your machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ASZmHA3pveX8qLyCAfC7rNg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ASZmHA3pveX8qLyCAfC7rNg.png" alt="result of npm ls"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use a specific version of the node
&lt;/h2&gt;

&lt;p&gt;Now let’s say you have multiple versions of the node installed on your machine. And you want to switch between them. Maybe you want to work on a legacy app that uses Node.js 14.&lt;/p&gt;

&lt;p&gt;You can just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm use 14
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check the version of the node by running the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;And now you are using Node 14.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AUaAn2OOfywLTyWtrtIOshg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AUaAn2OOfywLTyWtrtIOshg.png" alt="version switch of node"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the Latest Version of npm
&lt;/h2&gt;

&lt;p&gt;You can install the latest version of npm for the version run the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;And check the version:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;So essentially you can have multiple versions of npm on your machine now!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AJCkmByxPs2UHaSwGx8yQ6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AJCkmByxPs2UHaSwGx8yQ6g.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How cool is that?&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;These tools are here to make our lives easier. Let’s take full advantage of them.&lt;/p&gt;

&lt;p&gt;Hope you learned something new today. Have a great day!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have something to say? Get in touch with me via &lt;a href="https://www.linkedin.com/in/56faisal/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://www.mdfaisal.com/" rel="noopener noreferrer"&gt;Personal Website&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>react</category>
      <category>javascript</category>
      <category>aws</category>
    </item>
    <item>
      <title>How do you Refactor a 2,700-Line React Component?</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Wed, 06 Mar 2024 09:55:16 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/how-do-you-refactor-a-2700-line-react-component-1c14</link>
      <guid>https://dev.to/mohammadfaisal/how-do-you-refactor-a-2700-line-react-component-1c14</guid>
      <description>&lt;p&gt;To read more articles like this, &lt;a href="https://www.mdfaisal.com/blog"&gt;visit my blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are always so excited about the new shiny things that come out every week in the programming world. New ways to structure components, new techniques to reduce those two lines of code, and so on.&lt;/p&gt;

&lt;p&gt;But in the real world, things are not so shiny. We often have to deal with codebases that have been evolving for many years, and many developers have left their mark on the components' different parts.&lt;/p&gt;

&lt;p&gt;Our story is about a component that has &lt;strong&gt;2700 lines of code&lt;/strong&gt;. Let’s try to explain how things went south and how we can do better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I worked in a company with a fleet management tool dashboard showing vehicles roaming around the city in real-time.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;dashboard&lt;/strong&gt; component is the hero of our story today. It has many functionalities. Nothing fancy, though.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A map that shows the vehicle markers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A way to search through the vehicles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A popup that shows vehicle details when clicked&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A list of vehicles at the bottom&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some filtering options.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sure, there are several features that this single component is responsible for displaying. But is it that much to contain &lt;strong&gt;2700 lines of code?&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Component
&lt;/h3&gt;

&lt;p&gt;Obviously, I will be stupid to paste 2700 lines of code into this article. (Also, it will be illegal :P ) But let me show you the general structure of the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// import statements -&amp;gt; 85 lines &lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styled-components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="o"&gt;--------------&lt;/span&gt;

&lt;span class="c1"&gt;//constant declaration -&amp;gt; 15 lines&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MAX_LOOP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FAILURE_MESSAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Something Brutal Happened!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="o"&gt;--------------&lt;/span&gt;

&lt;span class="c1"&gt;//styled component declaration -&amp;gt; 580 lines!!!!!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SomeStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
 display:flex;
 flex-direction: column;
`&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="o"&gt;---------------&lt;/span&gt;

&lt;span class="c1"&gt;//Helper components -&amp;gt; 200 lines&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MapPortal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// .. some placeholder component&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;


&lt;span class="o"&gt;---------------&lt;/span&gt;

&lt;span class="c1"&gt;// Props and State Type Declaration -&amp;gt; 70 lines&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;vin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;.....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;mapVisibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;---------------&lt;/span&gt;

&lt;span class="c1"&gt;// The actual component with all it's helper methods -&amp;gt; 1700 lines!!!!!!!!!!!!!!!!!!&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TheActualComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... And other lifecycle methods&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;randomHelperMethod&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="c1"&gt;// These functions extracts some logic into a separate function&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;onClickHandlers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Lots of them!&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="c1"&gt;// {Something worth of it?}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;// redux+type declarations -&amp;gt; 200 lines&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapStateToProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// .. lots of them!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapDisptachToProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// .. lots of them&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Okay Now Tell Me What’s Wrong Here
&lt;/h2&gt;

&lt;p&gt;To be 100% honest? Almost everything. Let me explain those.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Constant Declaration
&lt;/h3&gt;

&lt;p&gt;This is such an obvious one. Unfortunately, I have seen many examples of it throughout many companies and many components.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You should Keep the Constants in a Separate File&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It doesn’t matter if they are being re-used or not. It’s still better to store them in a separate File. Because down the line, someone else would create a separate constant with the same value, eventually creating confusion.&lt;/p&gt;

&lt;p&gt;I do it this way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// for related constants&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;DeclaredConstants&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;SOME_CONSTANT_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SomethingSpecial1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;SOME_CONSTANT_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SomethingSpecial2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// or for single constants&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SOME_CONSTANT_3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SomethingSpecial3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then import the inside my component and use them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DeclaredConstants&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ConstantDeclaration.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DeclaredConstants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SOME_CONSTANT_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This particular component isn’t a big deal, but best practices are best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Styles and Helper Methods
&lt;/h3&gt;

&lt;p&gt;I think it’s a very common mistake and (sometimes allowable) for smaller components to put the styles and helper methods in the same file.&lt;/p&gt;

&lt;p&gt;If your component is only 30–50 lines of code, then it can make sense to keep the styles and helper methods in the same file.&lt;/p&gt;

&lt;p&gt;But having 580 lines of style declaration doesn’t make sense in any scenario. Because not very often you would need to touch these styles.&lt;/p&gt;

&lt;p&gt;What I do is follow the following folder structure to keep things organized.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-component-name 
  |-- __tests__
  |-- styles.ts
  |-- helpers.ts
  |-- index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The responsibility of the files is clear from the name of the files themselves. It’s so simple to simply split our massive component to 1/3rd of its current size just by putting things where they should be!&lt;/p&gt;

&lt;p&gt;An Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SomeStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
  display: flex;
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using Raw CSS or SCSS, then you probably don’t make this mistake, but the projects using &lt;code&gt;styled-components&lt;/code&gt; or &lt;code&gt;material-ui&lt;/code&gt; mostly follow this bad practice.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Once someone started it. It became the standard practice.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So don’t fall into this trap. Create a separate file for styles ahead of time that can save your component in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Dumb Components
&lt;/h3&gt;

&lt;p&gt;There are two types of components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dumb components -&amp;gt; only act as a container or view&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Intelligent components -&amp;gt; Shows something based on some logic&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now there is no reason to put two components in the same file. It directly violates the Single Responsibility Principle.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every class or component should do one thing and one thing only&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes we get lazy (Myself included) and put simple container components into the actual component. But what do you think when the next developer comes?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Does he take out the smaller component into its own file?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Umm… Probably not. So after 4–5 years, you now have 200 lines of helper dumb components that can easily be extracted from separate files.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Class Component
&lt;/h3&gt;

&lt;p&gt;Not sure if you noticed, but this Massive component is using ClassComponent. I’m sure you know the reason. It was written at a time when functional components were not that common.&lt;/p&gt;

&lt;p&gt;But nowadays, using functional components make more sense because&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;They are easy to maintain&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Less code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More performant? (Arguably)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But even I wouldn’t try to convert it into a functional component at this stage. We need to refactor many things before converting this into a functional component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s see how much we could gain.
&lt;/h2&gt;

&lt;p&gt;Let me show you an estimation of how much we can improve without even understanding what this component is doing.&lt;/p&gt;

&lt;p&gt;We can just export the constants to constants.ts , Styles into the styles.ts and helper methods into the helpers.ts file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Styles                    =  600
Constants(Types+Others)   =  100
Helper Methods.           =  600 (roughly)
Dumb Components           =  200
---------------------------------
Total Gain                =  1400 lines!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a work of two hours maximum. All we need to do is.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Putting things into appropriate files and import them&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can reduce a component from 2700 to 1300 lines!&lt;/p&gt;

&lt;p&gt;Some might say that it’s still a lot. &lt;strong&gt;But hey!!!&lt;/strong&gt; One step at a time, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Can we do better?
&lt;/h2&gt;

&lt;p&gt;Yes, of course. When we look into the internal logic, we can do even better.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Break the actual components and re-usable parts into even smaller components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using Functional component&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Taking advantage of hooks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using functional redux&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And so on….. But that is a story for another day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the Good Parts.
&lt;/h2&gt;

&lt;p&gt;Obviously, This component has lots of problems but some good things.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typescript
&lt;/h3&gt;

&lt;p&gt;Although the Type declarations add up to around 200 lines in total, they are worth it. Especially without Typescript, it would be impossible to maintain this component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extracting logic
&lt;/h3&gt;

&lt;p&gt;Some of the dumb logic is extracted out of the view logic itself. For example, showing a message based on the vehicle status.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;showVehicleStatusMessage &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;VehicleStatus&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;SOME_STATUS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some Message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;SOME_OTHER_STATUS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some Other Message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s better to have them in a separate function like this instead of writing the logic into the view. Which can look something like this…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;vehicleStatus&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt;  &lt;span class="nx"&gt;SOME_STATUS&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some Message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So it’s not all bad; some developers tried to do things correctly. At the end of the day, software development is a team effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did I learn?
&lt;/h2&gt;

&lt;p&gt;The most important takeaway for me is to understand the importance of following the best practices.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Best practices are there for a reason&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The impact of &lt;strong&gt;following best practices&lt;/strong&gt; may not be evident on the first day, but if you don’t follow those, you will feel the pain someday!&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I hope you learned something new today. Have a great day!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have something to say? Get in touch with me via &lt;a href="https://www.linkedin.com/in/56faisal/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://www.mdfaisal.com/"&gt;Personal Website&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>aws</category>
      <category>programming</category>
    </item>
    <item>
      <title>You are Wrong. Frameworks Do Matter</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Wed, 28 Feb 2024 16:18:27 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/you-are-wrong-frameworks-do-matter-dfm</link>
      <guid>https://dev.to/mohammadfaisal/you-are-wrong-frameworks-do-matter-dfm</guid>
      <description>&lt;p&gt;To read more articles like this, &lt;a href="https://www.mdfaisal.com/blog"&gt;visit my blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am sure you have been asked this question at least once by someone, especially if you are a mid-level or senior engineer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which language/framework should I learn first?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the answer is always very straightforward.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Framework doesn’t matter…. Learn whatever you want.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And….. There is nothing wrong with this statement. Theoretically, frameworks don’t matter because everything changes so fast in the tech world.&lt;/p&gt;

&lt;p&gt;Right?&lt;/p&gt;

&lt;p&gt;Umm... I don’t think so. However, the statement is true, but in a real-life framework matters. They matter very much!&lt;/p&gt;

&lt;h2&gt;
  
  
  Let me explain why…
&lt;/h2&gt;

&lt;p&gt;If you go to any job search platform like LinkedIn, Toptal, or any other for that matter, you will see that,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Companies are looking for people with specific skill sets.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The only exception is FAANG (or MAANG… whatever) companies. Because they can’t find people with the specific skillset as they usually use custom technologies.&lt;/p&gt;

&lt;p&gt;But, in reality….&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Only 4% of people work for Big tech Companies. (give or take)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What about the rest of us?&lt;/p&gt;

&lt;h2&gt;
  
  
  The story is different on the other side.
&lt;/h2&gt;

&lt;p&gt;For all the other companies that are small startups or even mid-level, the tech stack really matters.&lt;/p&gt;

&lt;p&gt;They can’t afford to hire people, teach them specific frameworks, and invest 2–3 months to get up to speed.&lt;/p&gt;

&lt;p&gt;So what do they do?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They look for a specific skillset&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If a company uses &lt;strong&gt;React&lt;/strong&gt;, then it’s highly unlikely that they will search for front-end engineers having &lt;strong&gt;five years of Angular&lt;/strong&gt; experience.&lt;/p&gt;

&lt;p&gt;Most of the time, the framework's name is written in the Job description, and the resumes are sorted based on that.&lt;/p&gt;

&lt;p&gt;Sure… A senior engineer with this much experience in Angular can quickly pick up React.&lt;/p&gt;

&lt;p&gt;But let's say they find a React engineer, even slightly less qualified. Who do you think they will hire? I think you already know the answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t get me wrong
&lt;/h2&gt;

&lt;p&gt;I am not saying that the basics are not important. You should have a solid foundation for whatever you are learning.&lt;/p&gt;

&lt;p&gt;But when the time comes to dive deep into a framework, please don’t say that framework doesn’t matter.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Framework does matter, and you should learn the most popular one if possible, especially if you are starting out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Early in my career, I started with React. I imagine my career could be very different if I started with something else. And mostly for the worse.&lt;/p&gt;

&lt;p&gt;Let me explain why.&lt;/p&gt;

&lt;h2&gt;
  
  
  The popular framework is easier to learn.
&lt;/h2&gt;

&lt;p&gt;If you are starting out, then learning any new framework can be challenging.&lt;/p&gt;

&lt;p&gt;If the framework is the most popular one, then probably most of the problems are already solved by someone.&lt;/p&gt;

&lt;p&gt;You will get better resources and a clear path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Companies are using this.
&lt;/h2&gt;

&lt;p&gt;Startups and new companies usually pick up the most popular option regarding technology choice.&lt;/p&gt;

&lt;p&gt;There are a lot of reasons.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It’s easier to hire people.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better support.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better maintainability&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So unless you are creating your own start-up, it will be easier for you to get a job when you are already familiar with the tech stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  You are not preparing for FAANG.
&lt;/h2&gt;

&lt;p&gt;Yes, the huge tech companies don’t care much about which framework you know or which language you are proficient in. But that’s because&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;They use custom technologies that you can’t learn outside anyway.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They have a lot of projects, and almost every language is being used, so it really doesn’t matter which language you know.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, learning some random framework can be problematic for someone just starting in the industry.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rise of freelancing
&lt;/h2&gt;

&lt;p&gt;I have been involved with freelancing for a long time now, and the most important thing that employers ask for is specific skills.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most of the time, that skill means familiarity with the most popular frameworks like React&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Go to any freelance marketplace. I can assure you that getting a job in React is easier than in Angular. The number of jobs is much, much higher.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What to Do?
&lt;/h2&gt;

&lt;p&gt;I recommend learning the most popular language/framework if you are starting. You should look into the rising technologies even if you are already a mid-level engineer.&lt;/p&gt;

&lt;p&gt;If you want to start with the front end, start with HTML, CSS, and Javascript. And probably learn React after that.&lt;/p&gt;

&lt;p&gt;If you are starting with the backend, then learning NodeJS can give you the edge as you will learn the basics of backend development and the language Javascript, which is used everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;I just wanted to share my view on what a newcomer should learn. Obviously, once you get experienced, these things don’t matter anymore.&lt;/p&gt;

&lt;p&gt;But when it comes to guiding juniors, we should emphasize learning a specific framework very well, getting a job, and then going from there.&lt;/p&gt;

&lt;p&gt;Just a generic answer like **“It Depends” **doesn't help much.&lt;/p&gt;

&lt;p&gt;Thanks for reading this far. I hope you have a wonderful day!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can reach out to me via &lt;a href="https://www.linkedin.com/in/56faisal/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://www.mdfaisal.com/"&gt;Personal Website&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>programming</category>
      <category>aws</category>
    </item>
    <item>
      <title>How to Sanitize Data in React</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Mon, 26 Feb 2024 14:08:20 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/how-to-sanitize-data-in-react-2bme</link>
      <guid>https://dev.to/mohammadfaisal/how-to-sanitize-data-in-react-2bme</guid>
      <description>&lt;p&gt;To read more articles like this, &lt;a href="https://www.mdfaisal.com/blog"&gt;visit my blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every modern ReactJS application deals with data in some way. We are fetching data and letting people interact with it throughout the whole application.&lt;/p&gt;

&lt;p&gt;But if we are not careful about what data is coming into our website it can cause our application to fail.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One of the major reasons an application crashes on runtime is bad data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Today we will see one way to sanitize data in React applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;You should never trust anyone. Maybe you are expecting a remote API to return a piece of data that looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;userData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;basicInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you have a component that shows these two piece of data in the following manner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SomeComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basicInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now for some reason, the developer of the backend thought, okay, let’s change the structure of the data a bit to make it flatter and change it to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;userData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, as soon as they do that, your application will fail on runtime because it doesn’t know that the structure was changed.&lt;/p&gt;

&lt;p&gt;You will return to the desk and fix the issue, but your users will be greeted with a crashed application the whole time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: Cant't read name of undefined
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One way to avoid a crash like this is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt; {user?.basicInfo?.name} &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you have to put these &lt;code&gt;?&lt;/code&gt; sign everywhere which is not so clean, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Take advantage of Typescript.
&lt;/h2&gt;

&lt;p&gt;Now let’s define our User model like the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;initUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initPerson&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; {name: '', age: 0}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initPerson&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt;  {name: 'Tom', age: 0}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So this &lt;strong&gt;initUser&lt;/strong&gt; method can be used to create an instance of User, and the &lt;code&gt;options&lt;/code&gt; parameter makes it easy to pass parameters if we want.&lt;/p&gt;

&lt;p&gt;If we don’t pass anything, we will get back the object with default values.&lt;/p&gt;

&lt;p&gt;So before you push the data into the component, you will pass it via the &lt;code&gt;initUser&lt;/code&gt; method and stay chilled.&lt;/p&gt;

&lt;p&gt;Or you can use a hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useCleanUserData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;initUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;// inside component&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cleanUserData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCleanUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, we don’t need to worry about whether the API data is clean or not.&lt;/p&gt;

&lt;p&gt;You can use this same approach for redux as well. take advantage of the &lt;code&gt;selectors&lt;/code&gt; so that the data is cleaned before they enter into the component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have something to say? Get in touch with me via &lt;a href="https://www.linkedin.com/in/56faisal/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://www.mdfaisal.com/"&gt;Personal Website&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Well-Architected FastAPI Boilerplate</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Thu, 22 Feb 2024 10:01:52 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/a-well-architected-fastapi-boilerplate-17ao</link>
      <guid>https://dev.to/mohammadfaisal/a-well-architected-fastapi-boilerplate-17ao</guid>
      <description>&lt;p&gt;To read more articles like this, &lt;a href="https://www.mdfaisal.com/blog"&gt;visit my blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a project grows larger, the value of a well-architected and consistent project structure becomes more evident.&lt;/p&gt;

&lt;p&gt;Today, we will create a well-architected FastAPI project that should be easily scalable.&lt;/p&gt;

&lt;p&gt;We will also do it from scratch, so there will be no surprise for you!&lt;/p&gt;

&lt;p&gt;After we are done, our project will have -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A CRUD API ( &lt;strong&gt;Of course!&lt;/strong&gt; )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alembic for migrations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SQL Alchemy for Database Operations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Different environment handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docker-compose file for local development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dockerfile for production&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Linters.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the repository here if you are looking for that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mohammad-Faisal/fastapi-well-architected-boilerplate/tree/master"&gt;&lt;strong&gt;GitHub - Mohammad-Faisal/fastapi-well-architected-boilerplate: A Well arthitected FastAPI…&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to see how to build one from scratch — Let’s get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  First step.
&lt;/h2&gt;

&lt;p&gt;First, create the project directory and navigate to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir fastapi-well-architected-boilerplate
cd fastapi-well-architected-boilerplate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, create the following directories and files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p src/{api,core,db}
touch src/__init__.py
touch src/{main}.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project structure should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── src
│   ├── main.py
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;src&lt;/code&gt; directory contains the main application code.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;main.py&lt;/code&gt; file is the entry point of the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a virtual environment and install dependencies.
&lt;/h2&gt;

&lt;p&gt;Create a virtual environment and install the required dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m venv venv
source venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the two dependencies &lt;code&gt;fastapi&lt;/code&gt; and &lt;code&gt;uvicorn&lt;/code&gt; using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip3 install fastapi uvicorn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;fastapi&lt;/code&gt; package is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;unicorn&lt;/code&gt; package is a lightning-fast ASGI server implementation using uvloop and HTTP tools.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And create a &lt;code&gt;requirements.txt&lt;/code&gt; file to store the dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip3 freeze &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following code to the src/main.py file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;fastapi&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;FastAPI&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the application using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uvicorn src.main:app --reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open your browser and navigate to &lt;a href="http://localhost:8000/docs"&gt;http://localhost:8000/docs&lt;/a&gt; to see the API documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different environments and configuration settings
&lt;/h2&gt;

&lt;p&gt;The application will have different environments, such as &lt;code&gt;development&lt;/code&gt;, &lt;code&gt;testing&lt;/code&gt;, and &lt;code&gt;production&lt;/code&gt;. Each environment will have its configuration settings.&lt;/p&gt;

&lt;p&gt;The configuration settings will be stored in a &lt;code&gt;.env&lt;/code&gt; file in the project's root directory. The &lt;code&gt;.env&lt;/code&gt; file will contain the following settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env
ENV=development
DATABASE_URL=sqlite:///./test.db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ENV&lt;/code&gt; setting will be used to determine the current environment. The &lt;code&gt;DATABASE_URL&lt;/code&gt; setting will be used to connect to the database. The &lt;code&gt;DATABASE_URL&lt;/code&gt; setting will be different for each environment.&lt;/p&gt;

&lt;p&gt;Let’s install the &lt;code&gt;pydantic-settings&lt;/code&gt; package to load the configuration settings from the &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip3 install pydantic-settings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;src/config.py&lt;/code&gt; file contains the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;pydantic_settings&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;BaseSettings&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BaseSettings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sqlite:///./test.db&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;env_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Settings&lt;/code&gt; class contains the configuration settings. The &lt;code&gt;Config&lt;/code&gt; class is used to load the settings from the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Now, you can print the configuration settings using the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Format the code using Black
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;black&lt;/code&gt; package is a Python code formatter. It will format the code according to the Python PEP 8 style guide.&lt;/p&gt;

&lt;p&gt;Install the &lt;code&gt;black&lt;/code&gt; package using the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;And create a &lt;code&gt;pyproject.toml&lt;/code&gt; file in the root directory of the project with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;black&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;88&lt;/span&gt;
&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;py37&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;pyproject.toml&lt;/code&gt; file contains the configuration settings for the &lt;code&gt;black&lt;/code&gt; package. The &lt;code&gt;line-length&lt;/code&gt; setting is used to specify the maximum line length. The default is &lt;strong&gt;88&lt;/strong&gt;, but you can change it to any value.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;target-version&lt;/code&gt; setting is used to specify the Python version.&lt;/p&gt;

&lt;p&gt;Now, you can format the code using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;black src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will format the code in the &lt;code&gt;src&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Now black is great for formatting the code but it can be a bit too aggressive. If you want to see what changes it would make without actually making them, you can use the &lt;code&gt;--diff&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;black --diff src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to see what changes it would make without actually making them, you can use the &lt;code&gt;---check&lt;/code&gt; Option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;black --check src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, black focuses more on the code formatting. If you want to check the code for style and programming errors, you can use the &lt;code&gt;flake8&lt;/code&gt; package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database models and migrations
&lt;/h2&gt;

&lt;p&gt;The application will use the &lt;code&gt;SQLModel&lt;/code&gt; package to work with the database.&lt;/p&gt;

&lt;p&gt;This is built on top of SQLAlchemy and Pydantic. It will allow us to define the database models using Python-type hints.&lt;/p&gt;

&lt;p&gt;Install the &lt;code&gt;SQLAlchemy&lt;/code&gt; package using the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;src/database.py&lt;/code&gt; file contains the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;sqlmodel&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;create_engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Session&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;

&lt;span class="nx"&gt;SQLALCHEMY_DATABASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;

&lt;span class="nx"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SQLALCHEMY_DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_session&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code creates a database engine and a session. The &lt;code&gt;get_session&lt;/code&gt; function is used to get the session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create our first model
&lt;/h2&gt;

&lt;p&gt;Now, let’s create our first database model. We will create separate domains for each domain in the application.&lt;/p&gt;

&lt;p&gt;Let’s create our user domain&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch src/api/user/{__init__.py,models.py}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── src
│   ├── api
│       ├── user
│           ├── __init__.py
│           ├── models.py
# ... the other stuff
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, create the user model using the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;sqlmodel&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SQLModel&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SQLModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;
    &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;User&lt;/code&gt; class is a database model. It inherits from the &lt;code&gt;SQLModel&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;id&lt;/code&gt; field is the primary key. The &lt;code&gt;username&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;password&lt;/code&gt; fields are the columns in the database table.&lt;/p&gt;

&lt;p&gt;Now we have the models, but we need to create the database tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database migrations with Alembic
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Alembic&lt;/strong&gt; package is a database migration tool for SQLAlchemy. It will create the database and tables in the production environment.&lt;/p&gt;

&lt;p&gt;Install the Alembic package using the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Then, you can run the following command to initialize &lt;code&gt;alembic&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;migrations&lt;/code&gt; directory in the root directory of the project.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;migrations&lt;/code&gt; directory contains the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── migrations
│   ├── README
│   
│   ├── env.py
│   ├── script.py.mako
│   └── versions/
├── alembic.ini
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that it will also create a alembic.ini file in the root directory of the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[alembic]
# other configs
sqlalchemy.url = driver://user:pass@localhost/dbname
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to specify the &lt;code&gt;sqlalchemy.url&lt;/code&gt; setting in the &lt;code&gt;alembic.ini&lt;/code&gt; file. This setting is used to connect to the database.&lt;/p&gt;

&lt;p&gt;Then edit the &lt;code&gt;env.py&lt;/code&gt; file and add the following line to the section [target_metadata]:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from src.database import SQLModel
target_metadata = SQLModel.metadata
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the &lt;code&gt;script.py.mako&lt;/code&gt; file and add the following at the top&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sqlmodel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we are ready to run our first migration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic revision --autogenerate -m "Initial migration"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will create a new migration file in the &lt;code&gt;migrations/versions&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Now, you can run the migration using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic upgrade head
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will create the database and tables in the production environment.&lt;/p&gt;

&lt;p&gt;But wait, we are not in the production environment yet. We are still in the development environment. So, we need to create a separate configuration file for the development environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a separate configuration file for the development environment.
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;development.env&lt;/code&gt; file in the root directory of the project with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ENV=development
DATABASE_URL=sqlite:///./test.db
# development.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;development.env&lt;/code&gt; file contains the configuration settings for the development environment.&lt;/p&gt;

&lt;p&gt;Now you can run the application using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uvicorn src.main:app --reload --env-file .development.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will run the application in the development environment.&lt;/p&gt;

&lt;p&gt;For local development, we need a local database. And we can use docker to create a local database. It will greatly improve the local development experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a local database using Docker
&lt;/h2&gt;

&lt;p&gt;Let’s see how we can use docker-compose to create a local database and run the local server from the same file.&lt;/p&gt;

&lt;p&gt;This will allow us to run the application and the database using a single command.&lt;/p&gt;

&lt;p&gt;First, install Docker and Docker Compose on your machine.&lt;/p&gt;

&lt;p&gt;Then create the base &lt;code&gt;Dockerfile&lt;/code&gt; in the root directory of the project with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3.12.1-alpine3.18

WORKDIR /app

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can deploy your application anywhere with this docker file.&lt;/p&gt;

&lt;p&gt;Then create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file in the root directory of the project with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3.8'

services:
  db:
    image: postgres:13
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: test
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  app:
    build: .
    command: uvicorn src.main:app --reload --env-file .development.env --host 0.0.0.0 --port 8000
    volumes:
      - .:/app
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/test
    depends_on:
      - db

volumes:
    postgres_data:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;db&lt;/code&gt; service is used to create the database. It uses the &lt;code&gt;postgres:13&lt;/code&gt; image. The &lt;code&gt;POSTGRES_USER&lt;/code&gt;, &lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt;, and &lt;code&gt;POSTGRES_DB&lt;/code&gt; settings are used to create the database.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;app&lt;/code&gt; service is used to run the application. It uses the &lt;code&gt;uvicorn&lt;/code&gt; command to run the application. The &lt;code&gt;--env-file .development.env&lt;/code&gt; setting is used to load the configuration settings from the &lt;code&gt;development.env&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database credentials
&lt;/h2&gt;

&lt;p&gt;In this configuration, our local database URL will be &lt;code&gt;postgresql://user:password@localhost:5432/test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But in the docker file, we used &lt;code&gt;DATABASE_URL=postgresql://user:password@db:5432/test&lt;/code&gt; because in this context, the database is a service, and the host is &lt;code&gt;db&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can update the &lt;code&gt;.development.env&lt;/code&gt; file to use the new database URL in case we want to access it from the local machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .development.env
ENV=development
DATABASE_URL=postgresql://user:password@localhost:5432/test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, don’t forget to upgrade the &lt;code&gt;alembic.ini&lt;/code&gt; file to use the new database url.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[alembic]
# other configs
sqlalchemy.url = postgresql://user:password@localhost:5432/test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can run the application and the database using the following command:&lt;/p&gt;

&lt;p&gt;This command will create the database and run the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can run your first migration on the local database using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alemibc revision --autogenerate -m "Initial migration"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will create a new migration file in the &lt;code&gt;migrations/versions&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Now, you can run the migration using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic upgrade head
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if you visit your local database, you will see the &lt;code&gt;user&lt;/code&gt; table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the user API
&lt;/h2&gt;

&lt;p&gt;Now, let’s create the user API. We will create a router for the user domain.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;router.py&lt;/code&gt; file in the &lt;code&gt;src/api/user&lt;/code&gt; directory with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastapi import APIRouter

router = APIRouter()

@router.get("/")
async def read_users():
    return [{"username": "Rick"}, {"username": "Morty"}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;router&lt;/code&gt; object is an instance of the &lt;code&gt;APIRouter&lt;/code&gt; class. It is used to define the routes for the user domain.&lt;/p&gt;

&lt;p&gt;Now, you can add the user router to the main application using the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastapi import FastAPI

from src.api.user.router import router as user_router

app = FastAPI()

app.include_router(user_router, prefix="/users", tags=["users"])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we don’t want to deal with dummy data. Instead, we want to use the database to store and retrieve the users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the user service.
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;service.py&lt;/code&gt; file in the &lt;code&gt;src/api/user&lt;/code&gt; directory with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastapi import Depends
from src.database import get_session
from src.api.user.models import User
from sqlmodel import  select, Session


class UserService:
    def __init__(self, session: Session = Depends(get_session)) -&amp;gt; None:
        self.session = session

    def get_users(self):
        statement = select(User)
        users = self.session.exec(statement).all()
        return users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;get_users&lt;/code&gt; function is used to get the users from the database. Also, we are initializing the session in the constructor.&lt;/p&gt;

&lt;p&gt;Now, you can use the &lt;code&gt;get_users&lt;/code&gt; Function in the user router using the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastapi import APIRouter, Depends

from src.api.user.service import UserService

router = APIRouter()

@router.get("/")
async def read_users(user_service : UserService = Depends()):
    users = user_service.get_users()
    return users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we are using the &lt;code&gt;Depends&lt;/code&gt; function to inject the &lt;code&gt;UserService&lt;/code&gt; object into the &lt;code&gt;read_users&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Now you can run the application and navigate to &lt;strong&gt;&lt;a href="http://localhost:8000/users"&gt;http://localhost:8000/users&lt;/a&gt;&lt;/strong&gt; to see the users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a user.
&lt;/h2&gt;

&lt;p&gt;Now, let’s create another function to create a user. But before that, we need to create the request and response models.&lt;/p&gt;

&lt;p&gt;Create a new file named &lt;code&gt;schems.py&lt;/code&gt; in the &lt;code&gt;src/api/user&lt;/code&gt; directory with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from pydantic import BaseModel

class UserCreateInput(BaseModel):
    name: str
    email: str
    password: str
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then update the &lt;code&gt;service.py&lt;/code&gt; file to include the &lt;code&gt;create_user&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def create_user(self, user_create_input):
        user = User(**user_create_input.model_dump())
        self.session.add(user)
        self.session.commit()
        self.session.refresh(user)
        return user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, add the route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastapi import APIRouter, Depends

from src.api.user.service import UserService

router = APIRouter()

@router.get("/")

async def read_users(user_service : UserService = Depends()):
    users = user_service.get_users()
    return users

@router.post("/")
async def create_user(user_create_input: UserCreateInput, user_service :UserService = Depends()):
    user = user_service.create_user(user_create_input)
    return user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if you go to the terminal and send the following post request&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X 'POST' \
  'http://localhost:8000/users/' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "Mohammad Faisal",
  "email": "mohammadfaisal1011@gmail.com",
  "password": "faisal"
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will receive the following response with the success message!&lt;/p&gt;

&lt;h2&gt;
  
  
  Get the details of a user.
&lt;/h2&gt;

&lt;p&gt;Now, let’s create another function to get a user's details.&lt;/p&gt;

&lt;p&gt;For this, we don’t need any request schema, as we will be using the user id to get the details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@router.get("/{user_id}")
async def read_user(user_id: int, user_service : UserService = Depends()):
    user = user_service.get_user(user_id)
    return user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, remember to add the function to the service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def get_by_id(self, user_id: int):
    statement = select(User).where(User.id == user_id)
    user = self.session.exec(statement).one()
    return user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we need to handle the case when the user is not found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;sqlmodel&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;select&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SQLModel&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;one_or_none&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User not found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this check will raise an exception if the user is not found.&lt;/p&gt;

&lt;p&gt;But we need to handle this exception in the router.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;fastapi&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;APIRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HTTPException&lt;/span&gt;

&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;APIRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user_service&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
    &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user_create_input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserCreateInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user_service&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user_create_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/{user_id}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user_service&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;
    &lt;span class="nx"&gt;except&lt;/span&gt; &lt;span class="nx"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User not found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you will receive a 404 error if the user is not found.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update The User
&lt;/h3&gt;

&lt;p&gt;Now, let’s create another function to update the user.&lt;/p&gt;

&lt;p&gt;For this, we need to create a request schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserUpdateInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;
    &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then update the &lt;code&gt;service.py&lt;/code&gt; file to include the &lt;code&gt;update_user&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user_update_input&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;one&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;user_update_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, add the route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/{user_id}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user_update_input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserUpdateInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;user_service&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;
    &lt;span class="nx"&gt;except&lt;/span&gt; &lt;span class="nx"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User not found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can see that we have added the check for the user. If the user is not found, we will raise a 404 error.&lt;/p&gt;

&lt;p&gt;Now, this is a duplicate code. We can move this check to the service.&lt;/p&gt;

&lt;p&gt;We can use the concept of dependencies to create a dependency that will check if the user exists.&lt;/p&gt;

&lt;p&gt;Create a new file named &lt;code&gt;dependencies.py&lt;/code&gt; in the &lt;code&gt;src/api/user&lt;/code&gt; directory with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastapi import HTTPException, Depends

from src.api.user.service import UserService

def get_user(user_id: int, user_service: UserService = Depends()):
    user = user_service.get_by_id(user_id)
    if user is None:
        raise HTTPException(status_code=404, detail="User not found")
    return user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, update the &lt;code&gt;router.py&lt;/code&gt; file to include the &lt;code&gt;get_user&lt;/code&gt; dependency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@router.get("/{user_id}")
async def read_user(
    user_id: int,
    user_service: UserService = Depends(),
    user: Mapping = Depends(get_user),
):
    user = user_service.get_by_id(user_id)
    return user


@router.put("/{user_id}")
async def update_user(
    user_id: int,
    user_update_input: UserUpdateInput,
    user_service: UserService = Depends(),
    user: Mapping = Depends(),
):
    user = user_service.update(user_id, user_update_input)
    return user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can see that we are using the &lt;code&gt;get_user&lt;/code&gt; dependency to check if the user exists. And you can do the same. Now, you don't have any duplications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delete the user.
&lt;/h2&gt;

&lt;p&gt;Now, let’s create another function to delete the user.&lt;/p&gt;

&lt;p&gt;Then, update the &lt;code&gt;service.py&lt;/code&gt; file to include the &lt;code&gt;delete_user&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def delete_user(self, user_id):
    statement = select(User).where(User.id == user_id)
    user = self.session.exec(statement).one()
    self.session.delete(user)
    self.session.commit()
    return user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finlly, add the route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@router.delete("/{user_id}")
async def delete_user(user_id: int, user_service : UserService =Depends()):
    user = user_service.delete(user_id)
    return user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s about it for today! Now you have a boilerplate project that you can just clone and start adding endpoints.&lt;/p&gt;

&lt;p&gt;Hope you learned something new today!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have something to say? Get in touch with me via &lt;a href="https://www.linkedin.com/in/56faisal/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://www.mdfaisal.com/"&gt;Personal Website&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>react</category>
      <category>javascript</category>
      <category>fastapi</category>
    </item>
    <item>
      <title>NodeJS Security Best Practices</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Mon, 19 Feb 2024 11:46:18 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/nodejs-security-best-practices-34ck</link>
      <guid>https://dev.to/mohammadfaisal/nodejs-security-best-practices-34ck</guid>
      <description>&lt;p&gt;To read more articles like this, &lt;a href="https://www.mdfaisal.com/blog"&gt;visit my blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, we will see how we can improve the security of a NodeJS application. There are lots of aspects to security in the NodeJS application. We will get familiar with many of the concepts and see how to prevent unwanted attacks on our application.&lt;/p&gt;

&lt;p&gt;Nothing is bulletproof, but being safe doesn't hurt.&lt;/p&gt;

&lt;h3&gt;
  
  
  The most popular one!
&lt;/h3&gt;

&lt;p&gt;We will first use an excellent npm package named &lt;a href="https://www.npmjs.com/package/helmet"&gt;helmet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It sets up various HTTP headers to prevent attacks like Cross-Site-Scripting(XSS), clickjacking, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add helmet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use it inside your &lt;strong&gt;index.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;helmet&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! You don't need to do anything else!&lt;/p&gt;

&lt;p&gt;You should also take a look at &lt;a href="https://www.npmjs.com/package/helmet-csp"&gt;helmet-csp&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevent DOS attack
&lt;/h3&gt;

&lt;p&gt;DOS means Denial of Service. If an attacker tries to swamp your server with requests, our real users can feel the pain of slow response time.&lt;/p&gt;

&lt;p&gt;To prevent this, we can use an excellent package named &lt;a href="https://www.npmjs.com/package/toobusy-js"&gt;toobusy-js&lt;/a&gt;&lt;br&gt;
This will monitor the event loop, and we can define a lag parameter that will monitor the lag of the event loop and indicate if our event loop is too busy to serve requests right now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add toobusy-js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add a new middleware to indicate that the server is too busy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;too&lt;/span&gt; &lt;span class="nx"&gt;busy&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toobusy-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;toobusy&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server too busy!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rate Limiting
&lt;/h3&gt;

&lt;p&gt;Rate limiting helps your application from brute-force attacks. This allows to prevent the server from being throttled.&lt;/p&gt;

&lt;p&gt;Unauthorized users can perform any number of requests with malicious intent, and you can control that with rate-limiting.&lt;br&gt;
For example, you can allow a user to make five requests per 15 minutes for creating an account.&lt;br&gt;
Or you can allow unsubscribed users to make requests at a certain rate limit. something like 100requests/day&lt;/p&gt;

&lt;p&gt;There is a nice package named &lt;a href="https://www.npmjs.com/package/express-rate-limit"&gt;express-rate-limit&lt;/a&gt;. First, install it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add express-rate-limit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a rate-limiting configuration for it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;rateLimit&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express-rate-limit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;rateLimiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;rateLimit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;windowMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 24 hrs in milliseconds&lt;/span&gt;
  &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// maximum number of request inside a window&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You have exceeded the 100 requests in 24 hrs limit!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// the message when they exceed limit&lt;/span&gt;
  &lt;span class="na"&gt;standardHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Return rate limit info in the `RateLimit-*` headers&lt;/span&gt;
  &lt;span class="na"&gt;legacyHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Disable the `X-RateLimit-*` headers&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rateLimiter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will allow you to add a rate limit for all of your routes. You can also just add rate-limiting for specific routes.&lt;/p&gt;

&lt;p&gt;But if you are behind a proxy. This is the case for most cases when you use any cloud provider like Heroku aws etc., then the IP of the request is basically the IP of the proxy, which makes it look like that request is coming from a single source, and the server gets clogged up pretty quick.&lt;/p&gt;

&lt;p&gt;To resolve this issue, you can find out the &lt;strong&gt;numberOfProxies&lt;/strong&gt; between you and the server and set that count right after you create the express application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numberOfProxies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;trust proxy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;numberOfProxies&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To learn more about &lt;a href="https://expressjs.com/en/guide/behind-proxies.html"&gt;&lt;strong&gt;trust proxy&lt;/strong&gt;&lt;/a&gt; refer to the &lt;a href="https://expressjs.com/en/guide/behind-proxies.html"&gt;documentation&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure Cors
&lt;/h3&gt;

&lt;p&gt;CORS will keep your application safe from malicious attacks from unknown sources&lt;br&gt;
It's really easy to configure in nodejs.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;then use it inside the index.ts file&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;corsOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;optionsSuccessStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// some legacy browsers (IE11, various SmartTVs) choke on 204&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prevent XSS attacks
&lt;/h2&gt;

&lt;p&gt;XSS attack means cross-site scripting attacks. It injects malicious scripts into your application.&lt;/p&gt;

&lt;p&gt;An attacker can use XSS to send a malicious script to an unsuspecting user. The end user's browser has no way to know that the script should not be trusted and will execute the script. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other sensitive information retained by the browser and used with that site.&lt;/p&gt;

&lt;p&gt;You can protect your application by using &lt;code&gt;xss-clean&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add xss-clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use it inside the &lt;code&gt;index.ts&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;xss&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prevent SQL Query injection attacks
&lt;/h3&gt;

&lt;p&gt;If you use user input without checking them, a user can pass unexpected data and fundamentally change your SQL queries.&lt;/p&gt;

&lt;p&gt;For example, if your code looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;"' + req.body.first_name +  '"&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a user types his first name as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Bobby&lt;span class="s2"&gt;", last_name="&lt;/span&gt;Egg&lt;span class="s2"&gt;"; --
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the query becomes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;UPDATE &lt;span class="nb"&gt;users
    &lt;/span&gt;SET &lt;span class="nv"&gt;first_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Bobby"&lt;/span&gt;, &lt;span class="nv"&gt;last_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Egg"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="s2"&gt;" WHERE id=1001;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So all your users are named Bobby Egg which is not cool.&lt;/p&gt;

&lt;p&gt;If you use &lt;a href="https://sequelize.org/"&gt;Sequalize&lt;/a&gt;, &lt;a href="https://typeorm.io/"&gt;TypeORM&lt;/a&gt; or for MongoDB, we have &lt;a href="https://mongoosejs.com/"&gt;Mongoose&lt;/a&gt; these types of ORM tools, then you are safe by default because these help us against the SQL query injection attacks by default.&lt;/p&gt;

&lt;p&gt;If you don't want to use ORM then there are some other packages as well!&lt;br&gt;
For PostgreSQL we have &lt;a href="https://node-postgres.com/"&gt;node-postgres&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Limit the size of the body of the request
&lt;/h2&gt;

&lt;p&gt;Using &lt;a href="https://github.com/expressjs/body-parser"&gt;body-parser&lt;/a&gt; you can set the limit on the size of the payload&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;By default, body-parser is configured to allow 100kb payloads size. You can set the limit like the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;50kb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use linter
&lt;/h2&gt;

&lt;p&gt;A linter can force you to follow these best practices by default. You can use &lt;a href="https://www.npmjs.com/package/eslint-plugin-security"&gt;eslint-plugin-security&lt;/a&gt; for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; eslint-plugin-security
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And inside your &lt;strong&gt;.eslintrc&lt;/strong&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"plugin:@typescript-eslint/recommended"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"plugin:security/recommended"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enforce HTTPS
&lt;/h3&gt;

&lt;p&gt;It would be best if you always use HTTPS over HTTP when possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add hsts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use it inside your &lt;strong&gt;index.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;hsts&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15552000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 180 days in seconds&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Strict-Transport-Security: max-age: 15552000; includeSubDomains&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use CSRF Protection middleware
&lt;/h3&gt;

&lt;p&gt;To learn more about CSRF. &lt;a href="https://github.com/pillarjs/understanding-csrf"&gt;Go here&lt;/a&gt;&lt;br&gt;
Consider using &lt;a href="https://github.com/expressjs/csurf"&gt;csurf&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;csrf&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;csurf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;csrfProtection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;csrf&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;csrfProtection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// generate and pass the csrfToken to the view&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;send&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;csrfToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;csrfToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not required for an application that doesn't handle any form of data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validate Incoming Requests
&lt;/h3&gt;

&lt;p&gt;You should consider validating the incoming requests to your application to check if they contain any malicious data. There are many ways to do this, but the most popular way is to use a schema validation library like Joi or class-validator.&lt;/p&gt;

&lt;p&gt;You can refer to the following article for more information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.mohammadfaisal.dev/blog/request-validation-nodejs-express"&gt;https://www.mohammadfaisal.dev/blog/request-validation-nodejs-express&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Validating Output
&lt;/h3&gt;

&lt;p&gt;You want to secure the incoming data instead you should try to validate any data that you give output.&lt;br&gt;
For example, if you render to the frontend using NodeJS, then this becomes an issue.&lt;/p&gt;

&lt;p&gt;Let's say our user generates the following data for showing in the browser later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I am not sanitized!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is harmless, but if you don't sanitize it before giving it back to the javascript frontend, then it can cause trouble.&lt;/p&gt;

&lt;p&gt;To avoid this, we have several options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/html-escape"&gt;&lt;code&gt;html-escape&lt;/code&gt;&lt;/a&gt; // if you need to render html output&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/xml-escape"&gt;&lt;code&gt;xml-escape&lt;/code&gt;&lt;/a&gt; // if you need to give xml output&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/shell-escape"&gt;&lt;code&gt;shell-escape&lt;/code&gt;&lt;/a&gt; // for shell commands&lt;/p&gt;

&lt;p&gt;These libraries can help you to sanitize the output as well.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using Hash for Sensitive Information
&lt;/h3&gt;

&lt;p&gt;Storing passwords in plain text was never a good idea. You should instead create a has of your password.&lt;/p&gt;

&lt;p&gt;A Hash is a fixed-sized string that we can generate from any string, and it's not decryptable by design. You can only produce it again if the same input text is given again.&lt;/p&gt;

&lt;p&gt;So while storing passwords, you will create a hash of your password and store it in the database. This way, even if our database is exposed, the passwords will not be exposed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using the Salt with Hash
&lt;/h3&gt;

&lt;p&gt;There is a problem with the Hashing mechanism because two identical texts will always generate the same hash. As most people use very common passwords, this technique is vulnerable to exploitation.&lt;/p&gt;

&lt;p&gt;To avoid this issue, we use a technique called salt. It's basically a random string that is appended to the given input. So even if you give two identical inputs, the outputs will not be the same.&lt;/p&gt;
&lt;h3&gt;
  
  
  Hide errors from end-users
&lt;/h3&gt;

&lt;p&gt;It would be best if you did not expose errors to your users. In order to do that, you will need to handle production environment error handling seriously. Following is a good guide on where you can start.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.mohammadfaisal.dev/blog/error-handling-nodejs-express"&gt;https://www.mohammadfaisal.dev/blog/error-handling-nodejs-express&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Load secrets securely
&lt;/h3&gt;

&lt;p&gt;Be extra careful about loading secrets into your application. You must not include secrets as plain strings in the application. Using some kind of environment file is necessary to achieve this. You can refer to the following example for that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.mohammadfaisal.dev/blog/nodejs-environment-handling"&gt;https://www.mohammadfaisal.dev/blog/nodejs-environment-handling&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Compression
&lt;/h3&gt;

&lt;p&gt;Compression is a technique that can reduce the size of the static file and JSON response.&lt;br&gt;
In nodejs, that we can do with a nice middleware package named &lt;a href="https://www.npmjs.com/package/compression"&gt;&lt;strong&gt;compression&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, install it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add compression
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add it inside your &lt;strong&gt;index.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;compression&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compression&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;compression&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! There are other options that you can use. Refer to the documentation for that.&lt;/p&gt;

&lt;h4&gt;
  
  
  Some more resources:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html"&gt;https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.com/@nodepractices/were-under-attack-23-node-js-security-best-practices-e33c146cb87d"&gt;https://medium.com/@nodepractices/were-under-attack-23-node-js-security-best-practices-e33c146cb87d&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Github Repo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Mohammad-Faisal/nodejs-security-best-practices"&gt;https://github.com/Mohammad-Faisal/nodejs-security-best-practices&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have something to say? Get in touch with me via &lt;a href="https://www.linkedin.com/in/56faisal/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://www.mdfaisal.com/"&gt;Personal Website&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>react</category>
      <category>aws</category>
    </item>
    <item>
      <title>Best Software Documentation Tools</title>
      <dc:creator>Mohammad Faisal</dc:creator>
      <pubDate>Mon, 05 Feb 2024 15:18:52 +0000</pubDate>
      <link>https://dev.to/mohammadfaisal/best-software-documentation-tools-200j</link>
      <guid>https://dev.to/mohammadfaisal/best-software-documentation-tools-200j</guid>
      <description>&lt;p&gt;To read more articles like this, &lt;a href="https://www.mdfaisal.com/blog"&gt;visit my blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In software development, documentation is like the broccoli of the meal — not always the most exciting part, but it’s essential for a healthy project.&lt;/p&gt;

&lt;p&gt;Like how broccoli can be cooked in many different ways to make it more palatable, many tools are available to make the documentation less of a chore and more of a delight.&lt;/p&gt;

&lt;p&gt;This article’ll explore the benefits of using these tools and how they can turn your documentation from a bland, forgettable side dish into a mouth-watering main course.&lt;/p&gt;

&lt;p&gt;So grab your forks, and let’s dig in!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Docusaurus
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docusaurus.io/"&gt;This&lt;/a&gt; is developed by Meta. You can create really nice-looking documentation websites super fast.&lt;/p&gt;

&lt;p&gt;It can also be used to build static websites. &lt;a href="https://docusaurus.io/showcase?tags=personal&amp;amp;tags=favorite"&gt;You can take a look here&lt;/a&gt; for some inspiration.&lt;/p&gt;

&lt;p&gt;To create a website, Just run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-docusaurus@latest my-website classic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It supports markdown files. You can write both &lt;code&gt;blogs&lt;/code&gt; and &lt;code&gt;docs&lt;/code&gt; with this tool.&lt;/p&gt;

&lt;p&gt;You can also customize the look and feel using the &lt;a href="https://docusaurus.io/docs/configuration"&gt;configuration options &lt;/a&gt;of Docusaurus&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is based on React.&lt;/strong&gt; So if you are already familiar with &lt;strong&gt;ReactJS&lt;/strong&gt; then, it will help a lot!&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docusaurus.io/"&gt;&lt;strong&gt;Build optimized websites quickly, focus on your content | Docusaurus&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Docsify
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docsify.js.org/#/"&gt;This&lt;/a&gt; is a nice-looking, feature-rich documentation generator tool. &lt;strong&gt;It’s built on top of VueJS&lt;/strong&gt;. So having prior knowledge of &lt;strong&gt;VueJS&lt;/strong&gt; will come in handy.&lt;/p&gt;

&lt;p&gt;To get started, you will need to run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i docsify-cli -g
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then initialize the project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docsify init ./docs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can edit the pages and see the changes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docsify serve docs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the documentation will be served at &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hnukMRnh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2AKMrquFxdnEBdF4DUs_M0Bg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hnukMRnh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2AKMrquFxdnEBdF4DUs_M0Bg.png" alt="Docsify documentation" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can customize everything, From the loading bars to the side nav bars, cover pages… Everything!&lt;/p&gt;

&lt;p&gt;Also, it’s really easy to deploy using GitHub, GitLab, Vercel, etc.&lt;br&gt;
&lt;a href="https://docsify.js.org/#/awesome"&gt;&lt;strong&gt;docsify&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/docsifyjs/awesome-docsify#showcase"&gt;&lt;strong&gt;GitHub - docsifyjs/awesome-docsify: 💖 A curated list of awesome things related to docsify&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Gitbook
&lt;/h2&gt;

&lt;p&gt;This is another general-purpose tool that can be used to write books or documentation. It’s also super easy to distribute as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4AvSHPZc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2AV7hj6D_18dM04qi_IwurGg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4AvSHPZc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2AV7hj6D_18dM04qi_IwurGg.png" alt="Publish Gitbook" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;GitBook allows multiple users to collaborate on the same document&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitBook uses Git, a popular &lt;strong&gt;version control&lt;/strong&gt; system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitBook &lt;strong&gt;integrates&lt;/strong&gt; with GitHub, Slack, and Trello.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitBook allows users to publish their documentation in multiple formats, including PDF, EPUB, and HTML.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can set custom domains; the documentation is also auto-indexable. It supports internationalization as well. Overall it’s a fantastic tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://app.gitbook.com/"&gt;&lt;strong&gt;&lt;em&gt;GitBook&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
GitBookapp.gitbook.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s have a look at some of the API documentation tools now!&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Swagger
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://swagger.io/"&gt;Swagger&lt;/a&gt; is a widely used tool for documenting and testing APIs.&lt;/p&gt;

&lt;p&gt;It has an &lt;a href="https://editor.swagger.io/"&gt;online editor&lt;/a&gt;. You can easily play around with it and generate easy-to-use documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ALiLvg4P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2AR7BHe0GLIs5XAx6K9JO7Ag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ALiLvg4P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2AR7BHe0GLIs5XAx6K9JO7Ag.png" alt="Swagger Editor" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It provides a &lt;strong&gt;standardized way&lt;/strong&gt; to document APIs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Interactive documentation&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Swagger can &lt;strong&gt;auto-generate API documentation&lt;/strong&gt; based on the code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Collaboration&lt;/strong&gt; is a breeze here.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should definitely make yourself familiar with this platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://swagger.io/"&gt;&lt;strong&gt;API Documentation &amp;amp; Design Tools for Teams | Swagger&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Redoc
&lt;/h2&gt;

&lt;p&gt;Redocly is another OpenAPI documentation generator tool. It’s like Swagger but with a better interface (In my opinion).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aZPRTY1C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2AR1aOfgQZQzgzLuULp1TEWA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aZPRTY1C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2AR1aOfgQZQzgzLuULp1TEWA.png" alt="Redoc" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can provide an open API file, and it will auto-generate the documentation and provide you with some boilerplate code as well!&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://redocly.github.io/redoc/"&gt;&lt;strong&gt;ReDoc Interactive Demo&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It has a VS code extension&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tons of customization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Direct integration with OpenAPI&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It’s not completely free. It has paid versions as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://app.redocly.com/"&gt;&lt;strong&gt;Redocly Workflows&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Readme
&lt;/h2&gt;

&lt;p&gt;This is another API documentation generator tool for enterprise applications.&lt;/p&gt;

&lt;p&gt;You can sync your API using this tool, and it supports &lt;a href="https://spec.openapis.org/oas/v3.0.3"&gt;OpenAPI 3.0&lt;/a&gt;,  &lt;a href="https://spec.openapis.org/oas/v3.1.0"&gt;OpenAPI 3.1&lt;/a&gt;, &lt;a href="https://spec.openapis.org/oas/v2.0"&gt;Swagger 2&lt;/a&gt;,  and &lt;a href="https://schema.postman.com/"&gt;Postman&lt;/a&gt; API formats.&lt;/p&gt;

&lt;p&gt;You can import your open API file, and it will produce this beautiful-looking documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WSuD_rGs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2ATj4AejG4SpBqMNPqsBBMqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WSuD_rGs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2ATj4AejG4SpBqMNPqsBBMqw.png" alt="Readme" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In fact, it will add an example code snipped automatically! Also, it provides you a nice dashboard with statistics.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1J-3bM0J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2ACB8irxFngU4bc-JkE7VQvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1J-3bM0J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3814/1%2ACB8irxFngU4bc-JkE7VQvw.png" alt="Documentation view statistics" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But it has both free and paid plans, So choose accordingly!&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://readme.com/"&gt;&lt;strong&gt;ReadMe&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Documenting code may never be as fun as binge-watching your favorite TV show, but with the right tools, it can be almost as enjoyable as ordering a pizza.&lt;/p&gt;

&lt;p&gt;So don’t let documentation be the Brussels sprouts of your software project — spice it up with some humor, creativity, and a good documentation tool.&lt;/p&gt;

&lt;p&gt;Who knows, you may even discover that you have a hidden talent for technical writing. And if not, at least you’ll have some well-documented code and a satisfied appetite.&lt;/p&gt;

&lt;p&gt;Happy coding, and bon appétit! I hope you learned something new today!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have something to say? Get in touch with me via &lt;a href="https://www.linkedin.com/in/56faisal/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://www.mdfaisal.com/"&gt;Personal Website&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>aws</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
