<?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: LePhuongTrung</title>
    <description>The latest articles on DEV Community by LePhuongTrung (@lephuongtrung).</description>
    <link>https://dev.to/lephuongtrung</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%2F979479%2Fa927ca65-45dc-4a0a-8907-b67e53afd9f3.jpg</url>
      <title>DEV Community: LePhuongTrung</title>
      <link>https://dev.to/lephuongtrung</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lephuongtrung"/>
    <language>en</language>
    <item>
      <title>I Built an "AI Meal Planner." It Almost Produced a Nutritionally Invalid Plan.</title>
      <dc:creator>LePhuongTrung</dc:creator>
      <pubDate>Sun, 24 May 2026 09:05:19 +0000</pubDate>
      <link>https://dev.to/lephuongtrung/i-built-an-ai-meal-planner-it-almost-produced-a-nutritionally-invalid-plan-34pm</link>
      <guid>https://dev.to/lephuongtrung/i-built-an-ai-meal-planner-it-almost-produced-a-nutritionally-invalid-plan-34pm</guid>
      <description>&lt;p&gt;Last week, my constraint-optimization engine suggested I live on nothing but protein powder and frozen peas for 7 days to stay under my $27/week budget. It wasn't trying to be funny; it was a &lt;strong&gt;logical failure in my multi-step agentic workflow.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’m a NestJS engineer. I thought I could solve "budget meal prep" with a clean schema and a prompt. I was wrong. Building this for the Google I/O 2026 challenge wasn't about building a demo; it was about fixing a system that kept breaking in the messiest ways possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The "Failure" Moment: The Gap Between Logic and Reality
&lt;/h2&gt;

&lt;p&gt;My initial MVP was simple: feed the API a budget, get back a JSON list of meals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Failure:&lt;/strong&gt; The model hallucinated prices based on global averages, not my local market. My engine accepted the hallucinated price as "ground truth," resulting in a plan that was technically within budget but &lt;strong&gt;nutritionally invalid&lt;/strong&gt; (missing critical micronutrients).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Insight:&lt;/strong&gt; AI isn't an "optimizer"; it's a "generator." I had to shift my architecture from a Single-Prompt Request to a &lt;strong&gt;Multi-Step Validation Loop&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Quantitative Results: Measuring the Drift
&lt;/h2&gt;

&lt;p&gt;I didn't just "fix" the prompts; I implemented a hard constraint-validation layer. Here is how the system improved after I introduced the &lt;strong&gt;Zod-based Fallback Strategy:&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%2Fgmv2rzaltkzq6zih4d15.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%2Fgmv2rzaltkzq6zih4d15.png" alt="Measuring the Drift" width="799" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Implementation: Failing Safely
&lt;/h2&gt;

&lt;p&gt;I learned that you cannot JSON.parse() your way to a production app. My agentic workflow now treats AI output as "untrusted input."&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="c1"&gt;// The Reality: Handling LLM non-determinism in NestJS&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;optimizeBudget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;budget&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MealPlan&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;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gemini&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;budget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Schema validation ensures we never crash on malformed AI output&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;MealPlanSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&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;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// When AI reasoning drifts, we don't return an invalid plan. &lt;/span&gt;
    &lt;span class="c1"&gt;// We pivot to a deterministic "safe-mode" heuristic.&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="s2"&gt;AI reasoning drift detected, falling back to deterministic heuristic.&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;staticMealService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFallbackPlan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;budget&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;h2&gt;
  
  
  4. What Google I/O 2026 Taught Me
&lt;/h2&gt;

&lt;p&gt;This year’s I/O keynotes shifted my perspective on "Deterministic Agentic Workflows."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serverless is a feature: I moved my reasoning logic to Cloud Run. During Sunday-night traffic spikes, the system auto-scales. I only pay for compute when the agent is actually "thinking."&lt;/li&gt;
&lt;li&gt;Firestore as the Ambient Glue: By using Firestore, my meal plan isn't just a web app state—it’s an ambient data stream that syncs instantly to my mobile device. It’s the "ambient computing" vision I saw on stage, 
applied to my own grocery list.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Conclusion: The Real Goal
&lt;/h2&gt;

&lt;p&gt;The goal was never just to build an AI meal planner. It was to build a system that &lt;strong&gt;fails safely.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As developers, we are moving into an era where AI is no longer a "nice-to-have" feature; it is a core dependency. If we cannot build systems that fail gracefully when the LLM hallucinates, we aren't building software—we're just building technical debt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Live Mess:&lt;/strong&gt; &lt;a href="http://lephuongtrung.id.vn" rel="noopener noreferrer"&gt;lephuongtrung&lt;/a&gt;&lt;/p&gt;

</description>
      <category>googleiochallenge</category>
      <category>googleio</category>
    </item>
    <item>
      <title>How I Built an Intelligent, Budget-Friendly Meal Planner to Refactor My Fitness Journey</title>
      <dc:creator>LePhuongTrung</dc:creator>
      <pubDate>Sun, 24 May 2026 04:01:36 +0000</pubDate>
      <link>https://dev.to/lephuongtrung/how-i-built-an-intelligent-budget-friendly-meal-planner-to-refactor-my-fitness-journey-5doe</link>
      <guid>https://dev.to/lephuongtrung/how-i-built-an-intelligent-budget-friendly-meal-planner-to-refactor-my-fitness-journey-5doe</guid>
      <description>&lt;p&gt;Every software engineer knows the concept of refactoring—improving the internal structure of code without changing its external behavior. But a few months ago, I decided to apply this exact mindset to a different kind of system: my own body.&lt;/p&gt;

&lt;p&gt;As a full-stack developer navigating a serious fitness and body recomposition journey, I quickly hit a major bottleneck that wasn't code-related. It was meal prepping. Calculating macro targets (Protein, Carbs, Fats) manually on Excel is tedious. Worse, trying to balance those nutrient goals with a strict weekly budget while avoiding foods I dislike felt like solving an NP-hard problem every single Sunday.&lt;/p&gt;

&lt;p&gt;So, instead of complaining, I did what any developer would do: I built a web application to automate it.&lt;/p&gt;

&lt;p&gt;The Core Product Workflow&lt;br&gt;
I designed the application to be completely streamlined, focusing on constraints that matter to real people: fitness goals, budget restrictions, and personal food preferences.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dynamic Constraint Setting (Goal &amp;amp; Budget)
The workflow starts by letting the user choose their fitness direction—either Cut (caloric deficit for fat loss) or Bulk (caloric surplus for clean muscle gain).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next is the strict budget input. The system is smart enough to calculate a baseline budget based on the user's physical metrics. If you try to input an unrealistic budget, the system warns you. For my current cutting phase, I locked in a budget of 700,000 VND/week (~$27 USD).&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%2Fijglyekziwbkxeilkmj3.jpg" 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%2Fijglyekziwbkxeilkmj3.jpg" alt="Goal and budget setup" width="596" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 1: English localized UI for goal and weekly budget configuration (700,000 VND / ~$27 USD).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Preference Filtering (Blacklisting Ingredients)
We all have foods we absolutely refuse to eat. Whether it's pork liver, specific greens, or seafood, the app allows users to toggle off ingredients. The backend algorithm dynamically excludes these food items from the pool before generating the menu.&lt;/li&gt;
&lt;/ol&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%2Fdzxvuxqjc62h2txxytl3.jpg" 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%2Fdzxvuxqjc62h2txxytl3.jpg" alt="Disliked ingredients checklist" width="592" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 2: Ingredient blacklist interface showing localized Vietnamese data layer mapped against an English UI framework.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Smart Weekly Menu Generation
Once you hit "Generate", the application builds a customized weekly meal plan. For instance, looking at my generated Sunday menu, the app successfully hit a highly optimized macro profile: 1350 kcal, 95g Protein, 199g Carbs, and 20g Fats. It broke the meals down into delicious, budget-friendly options like pan-seared tilapia fillets, boiled sweet potatoes, and steamed carrots.&lt;/li&gt;
&lt;/ol&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%2Fr2fu4qujhfq57beliikv.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%2Fr2fu4qujhfq57beliikv.png" alt="Weekly meal plan generator" width="514" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 3: Weekly view and single-day macro breakdown using localized clean-eating ingredients.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Consolidated Automated Shopping List
The biggest time-saver is the automated grocery list aggregation. The app parses the entire week’s menu, calculates the exact weight needed for every ingredient, and presents a checkbox list.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;According to the app, I needed exactly 1086g of tilapia fillet (costing around 84,972 VND) and 1053g of raw sweet potatoes (76,253 VND) for the week. The final calculated cost for the entire week came out to just 501,707 VND—well under my 700k budget!&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%2Ffru4aubzqndfyovn7a29.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%2Ffru4aubzqndfyovn7a29.png" alt="Automated grocery shopping list" width="528" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 4: Automated grocery list aggregating exact weights. The algorithm successfully optimized the total cost well below the 700k limit.&lt;/p&gt;

&lt;p&gt;The Engineering Behind the Scenes (Tech Stack)&lt;br&gt;
To keep the system highly responsive, type-safe, and capable of scaling into a mobile app later, I leveraged a modern full-stack ecosystem:&lt;/p&gt;

&lt;p&gt;Frontend: React / Next.js with a dark-themed, sleek user interface optimized for scannability.&lt;/p&gt;

&lt;p&gt;Backend: Node.js &amp;amp; NestJS managing the heavy data parsing, modular routing, and ingredient databases.&lt;/p&gt;

&lt;p&gt;Language: TypeScript end-to-end to ensure robust type-safety across data payloads.&lt;/p&gt;

&lt;p&gt;How the Algorithm Thinks&lt;br&gt;
The fundamental challenge was mapping fluid monetary constraints against fixed nutritional values. The database stores individual ingredients with their respective market prices per gram and their nutritional profile (P/C/F per 100g).&lt;/p&gt;

&lt;p&gt;The application core filters out the blacklisted items first, estimates the daily caloric target based on body data, and then executes a matching mechanism to find the cheapest combinations of ingredients that successfully fulfill the required macro distribution.&lt;/p&gt;

&lt;p&gt;🌐 A Smart Approach to Hybrid Localization&lt;br&gt;
If you look closely at the application screenshots, you will notice an interesting architectural choice: The Frontend UI is fully localized in English, while the dynamic dataset (ingredients like "Bắp bò tươi", "Chả lụa") remains in Vietnamese. This is a deliberate Hybrid Localization strategy.&lt;/p&gt;

&lt;p&gt;Frontend Presentation Layer: All static text, user instructions, navigation buttons, and system alerts are handled via localization JSONs, making the application immediately friendly to an international audience or English-speaking expats.&lt;/p&gt;

&lt;p&gt;Dynamic Data Layer: The core database—storing ingredient names, localized nutrition profiles, and historical market pricing—is kept in the regional language. Why? Because these items are tightly coupled with physical inventory at local Vietnamese supermarkets, traditional wet markets, and regional grocery costs.&lt;/p&gt;

&lt;p&gt;By separating the UI translation layer from the localized data layer, the system remains highly accurate for the target market's budget calculation, while the codebase is structurally prepared to scale globally just by swapping the underlying ingredient database.&lt;/p&gt;

&lt;p&gt;What’s Next?&lt;br&gt;
Building this tool in public has drastically optimized my weekly developer routine and body metrics. No more guessing at the grocery store, no more macro calculation errors, and zero wasted budget.&lt;/p&gt;

&lt;p&gt;Moving forward, I am planning to expand this system into a cross-platform mobile application, integrate voice-transcription AI to allow seamless hands-free food logging, implement an LLM-driven cooking instruction assistant, and expand multi-language localization to global ingredient databases.&lt;/p&gt;

&lt;p&gt;🔗 Connect With Me &amp;amp; Follow the Journey&lt;br&gt;
I am actively building this project in public and regularly sharing deep-dives, architectural updates, and my personal fitness transformation. Let's connect!&lt;/p&gt;

&lt;p&gt;Discover my engineering work: Check out my personal project hub at &lt;a href="https://lephuongtrung.id.vn/" rel="noopener noreferrer"&gt;lephuongtrung.id.vn&lt;/a&gt; to see my portfolio and active dev experiments.&lt;/p&gt;

&lt;p&gt;Watch the app in action: Follow my "Refactor Body" series on TikTok &lt;a href="https://www.tiktok.com/@lephuongtrung" rel="noopener noreferrer"&gt;@lephuongtrung&lt;/a&gt; to see real-world grocery shopping, meal prepping, and lifting routines.&lt;/p&gt;

&lt;p&gt;How do you manage your meal preps and fitness goals as a developer? I’d love to hear your thoughts, feature ideas, or tech suggestions in the comments below!&lt;/p&gt;

&lt;p&gt;Feel free to drop a comment, reaction, or follow my blog here on Hashnode if you want to see more content blending Software Engineering and FitTech!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Complete code Send mail on node JS for 60s</title>
      <dc:creator>LePhuongTrung</dc:creator>
      <pubDate>Sat, 03 Dec 2022 04:53:02 +0000</pubDate>
      <link>https://dev.to/lephuongtrung/complete-code-send-mail-on-node-js-for-80s-23jc</link>
      <guid>https://dev.to/lephuongtrung/complete-code-send-mail-on-node-js-for-80s-23jc</guid>
      <description>&lt;h2&gt;
  
  
  Install Nodemailer
&lt;/h2&gt;

&lt;p&gt;If you want to learn more about Nodemailer you can read here:&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/nodemailer" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/nodemailer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Turn on the Terminal and type the following command to install&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i nodemailer
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Handling Send Mail
&lt;/h2&gt;

&lt;p&gt;The outermost of the project creates the file as follows the following folder&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%2Fvdlv7bainrhzl218w8rv.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%2Fvdlv7bainrhzl218w8rv.png" alt="handle sendMail" width="294" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code handle send mail (sendMail.js)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const nodemailer = require("nodemailer");
const transport = nodemailer.createTransport({
  service: "Gmail",
  auth: {
    user: Email name you use to send,
    pass: Email password you use to send,
  },
});
module.exports.sendConfirmationEmail = (name, email) =&amp;gt; {
  transport
    .sendMail({
      from: user,
      to: email,
      subject: "Confirm your registered account",
      html: `&amp;lt;h1&amp;gt;Email Confirmation&amp;lt;/h1&amp;gt;
        &amp;lt;h2&amp;gt;Hello ${name}&amp;lt;/h2&amp;gt;
        &amp;lt;p&amp;gt;You have successfully registered an account. Please confirm your email by clicking on the following link&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;`,
    })
    .catch((err) =&amp;gt; console.log(err));
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Handling Router
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Code handle router (router.js)&lt;/strong&gt;&lt;br&gt;
Add the following code to the router .js&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sendMail = require("../utils/sendMail");
router.post("/sendmail", async (req, res, next) =&amp;gt; {
  try {
    sendMail.sendConfirmationEmail(req.body.name, req.body.email);
    return res.status(200).send("Oke");
  } catch (err) {
    console.log("🚀 ~ file: Routers.js:11 ~ router.post ~ err", err);
    next(err);
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Run test results
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Here I use insomnia to test API&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%2Ftef30g7kh5ca29ivnh7h.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%2Ftef30g7kh5ca29ivnh7h.png" alt="insomnia" width="800" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check mail&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%2Fzswz3lb3eqmxxlxn4hfi.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%2Fzswz3lb3eqmxxlxn4hfi.png" alt="Check mail" width="799" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;We have successfully implemented email notification functionality using Nodemailer. In the next posts, we will explore deeper into system architecture and security. You can follow all my upcoming technical insights and lifestyle updates at &lt;a href="https://www.lephuongtrung.id.vn" rel="noopener noreferrer"&gt;Lê Phương Trung - Middle Fullstack Developer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you do not understand something, feel free to message me or join our Zalo community: Join Node.js Backend Group to exchange knowledge about Node.js and Backend development!&lt;/p&gt;

</description>
      <category>backend</category>
      <category>javascript</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Fix CORS policy error on Nodejs with 2 super simple steps</title>
      <dc:creator>LePhuongTrung</dc:creator>
      <pubDate>Sat, 03 Dec 2022 03:57:50 +0000</pubDate>
      <link>https://dev.to/lephuongtrung/fix-cors-policy-error-on-nodejs-with-2-super-simple-steps-302i</link>
      <guid>https://dev.to/lephuongtrung/fix-cors-policy-error-on-nodejs-with-2-super-simple-steps-302i</guid>
      <description>&lt;h2&gt;
  
  
  What is CORS?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cross-origin resource sharing (CORS)&lt;/strong&gt; is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does CORS policy error show?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Access to XMLHttpRequest at 'http://localhost:3333/user/Login' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to fix CORS policy error on nodejs?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Step 1: Install CORS &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i cors
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Step 2: put CORS in request
Open the app.js file and add the following 3 lines.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var cors = require('cors')
var app = express()
app.use(cors())
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also, you can add some more customizations here: &lt;a href="https://www.npmjs.com/package/cors" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/cors&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Fixing CORS is one of the first steps to making your backend production-ready. You can follow my blog updates, fitness journey, and more full-stack web development tips directly at &lt;a href="https://www.lephuongtrung.id.vn" rel="noopener noreferrer"&gt;Lê Phương Trung - Middle Fullstack Developer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you do not understand something, you can message me or join this group Zalo: Link, to exchange knowledge about BackEnd NodejsBackEnd Nodejs&lt;/p&gt;

</description>
      <category>security</category>
      <category>career</category>
    </item>
    <item>
      <title>User Security - P1 How to encrypt password in Nodejs?</title>
      <dc:creator>LePhuongTrung</dc:creator>
      <pubDate>Sun, 27 Nov 2022 10:10:01 +0000</pubDate>
      <link>https://dev.to/lephuongtrung/user-security-p1-how-to-encrypt-password-in-nodejs-1j9o</link>
      <guid>https://dev.to/lephuongtrung/user-security-p1-how-to-encrypt-password-in-nodejs-1j9o</guid>
      <description>&lt;p&gt;With any software provider, there is also a responsibility that is to protect user information. Data breaches can cause millions of dollars in damages, and according to Imperva, the US has the highest data breach costs.&lt;/p&gt;

&lt;p&gt;One of the ways to secure user information is to encrypt confidential information. This article will guide you to encrypt passwords with Bcrypt in Node.js. If you want to check out more backend best practices or follow my fullstack coding journey, feel free to visit &lt;strong&gt;&lt;a href="https://www.lephuongtrung.id.vn" rel="noopener noreferrer"&gt;Lê Phương Trung Hub&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 Install the necessary dependencies
&lt;/h2&gt;

&lt;p&gt;in your &lt;strong&gt;Project&lt;/strong&gt;  open &lt;strong&gt;terminal&lt;/strong&gt; and enter command &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npm install bcrypt&lt;br&gt;
npm install dotenv&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;in the &lt;strong&gt;package.json&lt;/strong&gt; file the &lt;strong&gt;dependencies&lt;/strong&gt; section has &lt;strong&gt;"bcrypt": "^5.1.0"&lt;/strong&gt; and &lt;strong&gt;"dotenv": "^16.0.3",&lt;/strong&gt;, which is ok&lt;br&gt;
Note the version may change depending on the time of installation (currently the latest version)&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2 Define environment variable
&lt;/h2&gt;

&lt;p&gt;in the outermost create file .env&lt;br&gt;
&lt;strong&gt;SALT&lt;/strong&gt;: number of data hashes&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SALT=10&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Step 3 HashPassword
&lt;/h2&gt;

&lt;p&gt;create a new founder named &lt;strong&gt;utils&lt;/strong&gt;, in utils create a new file named &lt;strong&gt;handlePassword&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;const&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bcrypt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hashPassword&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="nx"&gt;plainPassword&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;hashPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plainPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;parseInt&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;SALT&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;hashPassword&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🚀 ~ file: bcrypt.js ~ line 12 ~ hashPassword ~ error&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="k"&gt;return&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;hashPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4 Handle Controller
&lt;/h2&gt;

&lt;p&gt;in the outermost create the &lt;strong&gt;Controller&lt;/strong&gt; folder, in the controller create the file &lt;strong&gt;Auth.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;const&lt;/span&gt; &lt;span class="nx"&gt;UserModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../Database/Models/User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;hashPassword&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../utils/bcrypt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signUp&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;//look in database User has email entered yet&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;findAccount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;UserModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fullName&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;412&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You have not filled in the required information&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;findAccount&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The email has already been registered&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hashedPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;hashPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createNewAccount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;UserModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hashedPassword&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="nx"&gt;createNewAccount&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Internal server error&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;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&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="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🚀 ~ file: Controllers.js ~ line 34 ~ signUp ~ err&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5 Handle router
&lt;/h2&gt;

&lt;p&gt;in the outermost create the &lt;strong&gt;Router&lt;/strong&gt; folder, in the Router folder create the file &lt;strong&gt;AuthRouter.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;var&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Router&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;AuthController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../Controllers/Auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&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;/register&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AuthController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signUp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the additional App.js 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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;authRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Router/AuthRouter&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/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;userRouter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//IIFE&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connectDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;With today's post we have done the password hashing, tomorrow we will continue with 2 articles: login and send verified mail.&lt;br&gt;
If you do not understand something, you can message me or join this group Zalo: &lt;a href="https://zalo.me/g/ogwolo655" rel="noopener noreferrer"&gt;Link&lt;/a&gt;, to exchange knowledge about BackEnd Nodejs&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
