<?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: Abhinav Anand</title>
    <description>The latest articles on DEV Community by Abhinav Anand (@abhinavan00).</description>
    <link>https://dev.to/abhinavan00</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%2F3213463%2F526e4e20-10d9-433c-9249-a6078abea908.png</url>
      <title>DEV Community: Abhinav Anand</title>
      <link>https://dev.to/abhinavan00</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abhinavan00"/>
    <language>en</language>
    <item>
      <title>Building My First Full-Stack App: Part 3 - Integrating the Database with PostgreSQL &amp; Knex.js</title>
      <dc:creator>Abhinav Anand</dc:creator>
      <pubDate>Fri, 13 Jun 2025 08:48:17 +0000</pubDate>
      <link>https://dev.to/abhinavan00/building-my-first-full-stack-app-part-3-integrating-the-database-with-postgresql-knexjs-2674</link>
      <guid>https://dev.to/abhinavan00/building-my-first-full-stack-app-part-3-integrating-the-database-with-postgresql-knexjs-2674</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;As discussed in Part 2, I designed the overall layout of the backend server by creating all the essential endpoints, connecting it to the frontend, and tested it using a mock database.&lt;/p&gt;

&lt;p&gt;Now, it's time to transition to a real database. Why is a persistent database essential?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manual Data Updates:&lt;/strong&gt; With a mock database, data updates are manual and not persistent across sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability Limitations:&lt;/strong&gt; In-memory arrays become inefficient and unmanageable with growing datasets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inefficient Authentication:&lt;/strong&gt; Each login attempt requires iterating through the entire dataset, which is highly inefficient for real applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;What We'll Cover: The Database Layer&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;In this part, we'll cover how I set up a relational database using PostgreSQL, and connected it to the backend server using Knex.js. We'll also explore why I chose synchronous &lt;code&gt;bcryptjs&lt;/code&gt; for password hashing, and the crucial step of securely transferring the Clarifai API call to the backend (a task we deferred in Part 2).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Key Technologies for This Section&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; PostgreSQL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query Builder:&lt;/strong&gt; Knex.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database Management:&lt;/strong&gt; Combination of DBeaver and psql&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password Hashing:&lt;/strong&gt; bcryptjs&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Setting Up Your Database: PostgreSQL&lt;/strong&gt;
&lt;/h1&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why PostgreSQL?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I specifically chose a relational database, opting for PostgreSQL due to its widespread popularity, robustness, and the invaluable learning opportunity it offers over non-relational alternatives. PostgreSQL is a mature, reliable, and widely supported database system.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Database Installation and Setup&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To install PostgreSQL, I utilized Homebrew (as I'm using a Mac). Here are the steps I took to successfully install and start PostgreSQL:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, I ran &lt;code&gt;brew update&lt;/code&gt; to ensure Homebrew was up-to-date.&lt;/li&gt;
&lt;li&gt;Next, I executed &lt;code&gt;brew doctor&lt;/code&gt; for system health checks.&lt;/li&gt;
&lt;li&gt;Then, I simply ran &lt;code&gt;brew install postgresql&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Finally, &lt;code&gt;brew services start postgresql&lt;/code&gt; to start the PostgreSQL service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After starting PostgreSQL, I created a new database using the command: &lt;code&gt;createdb 'your_database_name'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To connect to the database via the command line, I used: &lt;code&gt;psql 'your_database_name'&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Designing the Database Schema&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Next, I designed a simple, secure database schema comprising two interconnected tables: &lt;code&gt;users&lt;/code&gt; (for general user information) and &lt;code&gt;login&lt;/code&gt; (for storing hashed passwords and login credentials, ensuring user privacy).&lt;/p&gt;

&lt;p&gt;To simplify visualization and management, I connected the PostgreSQL database to &lt;strong&gt;DBeaver&lt;/strong&gt;, a graphical tool, which greatly helped visualize the database for a first-timer. &lt;em&gt;(Consider adding a screenshot of DBeaver here showing your tables!)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The &lt;code&gt;users&lt;/code&gt; Table&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;users&lt;/code&gt; table stores general user information. For this table, I created columns for &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;entries&lt;/code&gt;, and &lt;code&gt;joined&lt;/code&gt;. The &lt;code&gt;id&lt;/code&gt; column serves as the primary key.&lt;/p&gt;

&lt;p&gt;To build the &lt;code&gt;users&lt;/code&gt; table, I ran this query in DBeaver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;CREATE&lt;/span&gt; &lt;span class="nx"&gt;TABLE&lt;/span&gt; &lt;span class="nf"&gt;users &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="nx"&gt;serial&lt;/span&gt; &lt;span class="nx"&gt;PRIMARY&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;name&lt;/span&gt; &lt;span class="nc"&gt;VARCHAR &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="nx"&gt;email&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="nx"&gt;UNIQUE&lt;/span&gt; &lt;span class="nx"&gt;NOT&lt;/span&gt; &lt;span class="nx"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;entries&lt;/span&gt; &lt;span class="nx"&gt;BIGINT&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;joined&lt;/span&gt; &lt;span class="nx"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="nx"&gt;NOT&lt;/span&gt; &lt;span class="nx"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;The &lt;code&gt;login&lt;/code&gt; Table&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This &lt;code&gt;login&lt;/code&gt; table includes valuable login information. It consists of &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;hash&lt;/code&gt; (for the hashed password), and &lt;code&gt;email&lt;/code&gt;. The &lt;code&gt;id&lt;/code&gt; also serves as the primary key, connecting it to the &lt;code&gt;users&lt;/code&gt; table (though implicitly in this setup, often via foreign keys in more complex designs).&lt;/p&gt;

&lt;p&gt;To build the &lt;code&gt;login&lt;/code&gt; table, I ran this query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;CREATE&lt;/span&gt; &lt;span class="nx"&gt;TABLE&lt;/span&gt; &lt;span class="nf"&gt;login &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="nx"&gt;serial&lt;/span&gt; &lt;span class="nx"&gt;PRIMARY&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;hash&lt;/span&gt; &lt;span class="nc"&gt;VARCHAR&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="nx"&gt;NOT&lt;/span&gt; &lt;span class="nx"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="nx"&gt;UNIQUE&lt;/span&gt; &lt;span class="nx"&gt;NOT&lt;/span&gt; &lt;span class="nx"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Connecting Backend to Database with Knex.js&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Introducing Knex.js: Your SQL Query Builder&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Knex.js is a powerful SQL query builder for JavaScript, simplifying database interactions and query construction in Node.js applications without the full abstraction of an ORM. It provides a simple and powerful way to build and execute SQL queries, as well as a helpful set of utilities for working with databases.&lt;/p&gt;

&lt;p&gt;I chose Knex.js over raw SQL or a full ORM due to its clear documentation and a more intuitive query building syntax, which I found easier for this project's scope. Ultimately, the choice depends on project needs and personal preference.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Installation and Configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now, it’s time to install Knex.js to establish the connection with our database:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To install Knex.js, I simply ran the command: &lt;code&gt;npm install knex&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Since I was using PostgreSQL, I also installed its client library: &lt;code&gt;npm install pg&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then, I imported Knex into my server file: &lt;code&gt;import knex from 'knex'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, I configured the database connection:JavaScript&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;knex&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;127.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// localhost&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Add your database username here&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Standard PostgreSQL port. Ensure this matches your setup.&lt;/span&gt;
      &lt;span class="na"&gt;password&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="c1"&gt;// Add your correct password here&lt;/span&gt;
      &lt;span class="na"&gt;database&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;smartweb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Add your database name here&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;p&gt;&lt;em&gt;(&lt;/em&gt;&lt;em&gt;Note:&lt;/em&gt;* Ensure your &lt;code&gt;port&lt;/code&gt; is correctly set to &lt;code&gt;5432&lt;/code&gt; unless you've configured a custom port.)*&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To test that the connection was established, I used a &lt;code&gt;SELECT&lt;/code&gt; query builder from Knex's documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&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;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;data&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="o"&gt;=&amp;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="s2"&gt;Database connection test failed:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn’t get any errors, which meant everything was working fine. Now, it was time for Refactoring API Endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Refactoring API Endpoints for Database Interaction&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Implementing Password Hashing with bcryptjs&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Password hashing is critical: storing plain text passwords is a severe security vulnerability. I chose &lt;strong&gt;&lt;code&gt;bcryptjs&lt;/code&gt;&lt;/strong&gt; for its proven reliability and adherence to modern security standards, ensuring user password privacy. Passwords should only be known to the user, not even the company.&lt;/p&gt;

&lt;p&gt;To integrate &lt;code&gt;bcryptjs&lt;/code&gt;, I installed it first:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install bcryptjs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, I imported it into my &lt;code&gt;server.js&lt;/code&gt; file: &lt;code&gt;import bcrypt from "bcryptjs";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For this initial implementation, I opted for &lt;code&gt;bcryptjs&lt;/code&gt;'s synchronous hashing to simplify the learning curve. Future iterations will adopt asynchronous methods for improved performance and non-blocking operations in a production environment.&lt;/p&gt;

&lt;p&gt;Now, let's refactor the endpoints. I largely referred to the Knex.js documentation for guidance during this process.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Refactoring the &lt;code&gt;/register&lt;/code&gt; Endpoint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To make it easier to understand, here's the code, followed by a line-by-line explanation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&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;email&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&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;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Incorrect form submission&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;salt&lt;/span&gt; &lt;span class="o"&gt;=&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;genSaltSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hashSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trx&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;trx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hash&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;email&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;returning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loginEmail&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;trx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;returning&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&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;name&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;loginEmail&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="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;joined&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="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commit&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;trx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rollback&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unable to register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;               
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;const {name, email, password} = req.body;&lt;/code&gt;: This is a simple destructuring method, used for cleaner code by avoiding &lt;code&gt;req.body.name&lt;/code&gt; repeatedly.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;if (!name || !email || !password) { return res.status(400).json('Incorrect form submission'); }&lt;/code&gt;: This validation ensures all required fields are submitted, preventing incomplete user registrations and improving data integrity.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;const salt = bcrypt.genSaltSync(10); const hash = bcrypt.hashSync(password, salt);&lt;/code&gt;: This step is for hashing the password using &lt;code&gt;bcryptjs&lt;/code&gt;. As mentioned, I used the synchronous method for simplicity in this initial project.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db.transaction(trx =&amp;gt; { ... });&lt;/code&gt;: I utilized &lt;strong&gt;Knex.js transactions&lt;/strong&gt; to ensure atomic operations when inserting user data into both the &lt;code&gt;login&lt;/code&gt; and &lt;code&gt;users&lt;/code&gt; tables. This guarantees that either both inserts succeed, or neither does, maintaining data consistency.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;trx.insert({ hash: hash, email: email }).into('login').returning('email')&lt;/code&gt;: Inserts the hashed password and email into the &lt;code&gt;login&lt;/code&gt; table, returning the email to be used in the next step.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.then(loginEmail =&amp;gt; { return trx('users').returning('*').insert({ ... }) ... });&lt;/code&gt;: Takes the returned email from the &lt;code&gt;login&lt;/code&gt; table and inserts it into the &lt;code&gt;users&lt;/code&gt; table along with other user information, returning the newly created user record.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;.then(user =&amp;gt; { res.json(user[0]); })&lt;/code&gt;: Sends the newly created user object back to the client.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;.then(trx.commit).catch(trx.rollback)&lt;/code&gt;: &lt;code&gt;.then(trx.commit)&lt;/code&gt; ensures the transaction is committed if all operations succeed, while &lt;code&gt;.catch(trx.rollback)&lt;/code&gt; rolls back all changes if any error occurs within the transaction, maintaining data consistency.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;.catch(err =&amp;gt; res.status(400).json('Unable to register'));&lt;/code&gt;: Catches any errors during the transaction and returns a generic 'Unable to register' message to the client for security reasons, avoiding revealing exact error details.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Refactoring the &lt;code&gt;/signin&lt;/code&gt; Endpoint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now, it’s time for refactoring the sign-in endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/signin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;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;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please enter email and password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&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="s1"&gt;hash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&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="s1"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Check if user exists before attempting to access data[0]&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wrong credentials&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;isValid&lt;/span&gt; &lt;span class="o"&gt;=&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;compareSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&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="nx"&gt;hash&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;isValid&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&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;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&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="s1"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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="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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unable to get user&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wrong credentials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&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 user&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;ul&gt;
&lt;li&gt;
&lt;code&gt;db.select('email', 'hash').from('login').where('email', '=', email)&lt;/code&gt;: This step fetches the email and hashed password (&lt;code&gt;hash&lt;/code&gt;) from the &lt;code&gt;login&lt;/code&gt; table for the provided email.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;if (!data.length) { return res.status(400).json('Wrong credentials'); }&lt;/code&gt;: Crucially, this check ensures that a user with the provided email exists before attempting to compare passwords, preventing errors if &lt;code&gt;data&lt;/code&gt; is empty.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;const isValid = bcrypt.compareSync(password, data[0].hash);&lt;/code&gt;: The retrieved hash is then compared with the provided password using &lt;code&gt;bcryptjs.compareSync()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;isValid&lt;/code&gt; is true (password matches), the code fetches the full user profile from the &lt;code&gt;users&lt;/code&gt; table and responds with &lt;code&gt;user[0]&lt;/code&gt;. Otherwise, it responds with 'Wrong credentials' or 'Unknown user' in case of other errors, again avoiding specific error details.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Refactoring the &lt;code&gt;/profile/:id&lt;/code&gt; Endpoint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This endpoint is simpler, as it only needs to retrieve a user's profile based on their ID from &lt;code&gt;req.params&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Corrected endpoint path&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;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&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;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&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="s1"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not Found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&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 getting user&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;h3&gt;
  
  
  &lt;strong&gt;Refactoring the &lt;code&gt;/image&lt;/code&gt; Endpoint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Similar to &lt;code&gt;/profile/:id&lt;/code&gt;, this endpoint updates the image entries count for a user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&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="s1"&gt;/image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&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="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="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&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="s1"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;entries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;returning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;entries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entries&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="nx"&gt;entries&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;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unable to update entries&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;After implementing these changes, I thoroughly tested all endpoints, and everything was working correctly without errors. This was a significant step forward!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Handling Database Errors and Security Considerations&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Robust Error Management&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For error management, I ensured that no exact error details are exposed to the user. All endpoints return generic error messages (e.g., 'Unable to register', 'Wrong credentials', 'Not Found'), enhancing security and user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Basic Frontend Response Handling&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;While the backend handles primary security like hashing and API key management, the frontend also plays a role in how it processes responses. After fetching data from the backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadUser&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;this&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="nf"&gt;onRouteChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home&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;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid credentials&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet ensures that if a valid user ID is returned from the backend, the user's data is loaded, and the application navigates to the 'home' route. If no user ID is present, an alert indicates invalid credentials. The &lt;code&gt;loadUser&lt;/code&gt; function (defined in &lt;code&gt;App.jsx&lt;/code&gt;) updates the application's state with the user's details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;loadUser&lt;/span&gt; &lt;span class="o"&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&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;id&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;data&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;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="na"&gt;entries&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;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;joined&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;joined&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 state management ensures the frontend accurately reflects the logged-in user's information.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(&lt;/em&gt;&lt;em&gt;Important Security Note:&lt;/em&gt;* For production applications, storing sensitive user data or tokens directly in &lt;code&gt;localStorage&lt;/code&gt; or &lt;code&gt;sessionStorage&lt;/code&gt; on the frontend should be done with extreme caution due to XSS vulnerabilities. More secure methods, like &lt;code&gt;httpOnly&lt;/code&gt; cookies, are typically preferred for handling authentication tokens.)*&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Transferring Clarifai API to Backend&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To prevent exposing my Personal Access Token (PAT) key from the frontend console, I transferred the Clarifai API call to the backend. This is a critical security measure.&lt;/p&gt;

&lt;p&gt;Here’s the backend code snippet for handling the Clarifai API call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleAPICall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;input&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// IMPORTANT: These should be loaded from environment variables (.env file)&lt;/span&gt;
    &lt;span class="c1"&gt;// and NOT hardcoded or committed to version control in a real application.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PAT&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;CLARIFAI_PAT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Your Personal Access Token&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USER_ID&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;CLARIFAI_USER_ID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Your Clarifai User ID&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;APP_ID&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;CLARIFAI_APP_ID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Your Clarifai App ID&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MODEL_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;face-detection&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;IMAGE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Clarifai API request setup (largely from Clarifai Docs)&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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_app_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="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="nx"&gt;USER_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app_id&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_ID&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputs&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IMAGE_URL&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="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&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;Accept&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="s1"&gt;application/json&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="s1"&gt;Authorization&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="s1"&gt;Key &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;PAT&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.clarifai.com/v2/models/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;MODEL_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;/outputs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unable to work with API&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// You'll also need an endpoint to handle this API call, e.g.:&lt;/span&gt;
&lt;span class="c1"&gt;// app.post('/imageurl', (req, res) =&amp;gt; { handleAPICall(req, res); });&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core API call structure largely follows Clarifai's documentation, adapted for a Node.js environment. I've created a dedicated endpoint (&lt;code&gt;/imageurl&lt;/code&gt;) on the backend to manage this API call securely. The key modification is handling the API response and passing it back to the frontend.&lt;/p&gt;

&lt;p&gt;Here's the frontend code snippet after adjusting the Clarifai API call to the backend:&lt;/p&gt;

&lt;p&gt;JavaScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;onButtonSubmit&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;:&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000/imageurl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// IMPORTANT: Change this to your DEPLOYED backend URL for production!&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&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;Content-Type&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="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;body&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;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&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;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000/image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// IMPORTANT: Change this to your DEPLOYED backend URL for production!&lt;/span&gt;
              &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;put&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&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;Content-Type&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="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="na"&gt;body&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;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&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;state&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="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;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&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;state&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="na"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;count&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;displayFaceBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calculateFaceLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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="o"&gt;=&amp;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="s1"&gt;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="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend now sends the image URL to its own backend endpoint (&lt;code&gt;/imageurl&lt;/code&gt;), which then securely handles the Clarifai API interaction and returns the results. If a successful result is received, a subsequent call updates the user's image entry count.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion: The Full-Stack Picture Nears Completion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It was incredibly satisfying to see everything working seamlessly after creating the real database and connecting it to the backend server using Knex.js. Knex made building queries and interacting with the backend surprisingly simple. My application now feels like a complete full-stack app, with user data stored perfectly and securely in the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Key Learning Points:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Database design principles (including table separation for security).&lt;/li&gt;
&lt;li&gt;Working with PostgreSQL for persistent data storage.&lt;/li&gt;
&lt;li&gt;Mastering Knex.js for efficient and readable database operations.&lt;/li&gt;
&lt;li&gt;Implementing secure password hashing with &lt;code&gt;bcryptjs&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Refactoring API endpoints for robust database interaction.&lt;/li&gt;
&lt;li&gt;Understanding the importance of moving sensitive API calls to the backend for security.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What's Next: Deployment&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Deployment proved to be a significant challenge. While my prior learning focused on Heroku, I opted for Render.com due to its free tier – a platform with distinct deployment processes. Despite taking a full day, successfully deploying the application was a highly rewarding experience.&lt;/p&gt;

&lt;p&gt;I'm thinking of sharing my complete experience with Render.com, a step-by-step guide on how I deployed my app, as it might help someone else facing similar issues.&lt;/p&gt;




&lt;p&gt;Okay, lastly, don’t forget to share your thoughts and leave some comments below. And as I also say at the end of my every blog, if you find something advisable, please tell me—I’m always open to advice!&lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building My First Full-Stack App: Part 2 - Crafting the Node.js Backend for Face Detection</title>
      <dc:creator>Abhinav Anand</dc:creator>
      <pubDate>Fri, 13 Jun 2025 08:06:48 +0000</pubDate>
      <link>https://dev.to/abhinavan00/building-my-first-full-stack-app-part-2-crafting-the-nodejs-backend-for-face-detection-52n2</link>
      <guid>https://dev.to/abhinavan00/building-my-first-full-stack-app-part-2-crafting-the-nodejs-backend-for-face-detection-52n2</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Setting Up the Node.js and Express.js Server&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Initializing the Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I started by creating a dedicated folder for the server and ran npm init to set up the basic Node.js package.json file. After that, I created the main server file, &lt;code&gt;server.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Express.js Fundamentals in Action&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To get the server running, I installed &lt;strong&gt;Express.js&lt;/strong&gt; by running npm install express.&lt;/p&gt;

&lt;p&gt;My basic server setup in &lt;code&gt;server.js&lt;/code&gt; looked like this:&lt;/p&gt;

&lt;p&gt;import express from 'express';&lt;br&gt;
const app = express();&lt;/p&gt;

&lt;p&gt;// Root route to test if the server is working&lt;br&gt;
app.get('/', (req, res) =&amp;gt; {&lt;br&gt;
    res.json('working');&lt;br&gt;
});` &lt;/p&gt;

&lt;p&gt;`app.listen(3000, () =&amp;gt; {&lt;br&gt;
    console.log('Server is running on port 3000');&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;I tested this root route with Postman.com to confirm the server was up and running.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A Crucial Middleware Lesson: Parsing Request Bodies&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;During initial testing, I quickly encountered an error. The server wasn't able to read the incoming request bodies from the frontend. After some investigation, I realized I'd forgotten to add the necessary middleware to parse the response. To fix this, I simply added app.use(express.json()). With this in place, my server could now correctly interpret JSON data sent from the frontend, and everything started working as expected.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;Designing API Endpoints for Face Detection&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Planning the API Structure&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before diving into implementation, I like to outline the overall structure of my API endpoints. This planning phase simplifies development, even for a smaller number of routes. My planned structure looked something like this:&lt;/p&gt;

&lt;p&gt;/*&lt;br&gt;
/signin --&amp;gt; POST = will respond =&amp;gt; success/failed&lt;br&gt;
/register --&amp;gt; POST = will respond =&amp;gt; user&lt;br&gt;
/profile/:id --&amp;gt; GET = will respond =&amp;gt; user&lt;br&gt;
/image --&amp;gt; PUT = will respond =&amp;gt; updated user's data&lt;br&gt;
*/&lt;/p&gt;

&lt;p&gt;Now, let's create each of these API endpoints step by step.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The /signin Endpoint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To test this endpoint, I started with a simple, temporary &lt;strong&gt;fake database&lt;/strong&gt; containing two users. This allowed me to simulate authentication without setting up a full database yet.&lt;/p&gt;

&lt;p&gt;Here's the initial sign-in route I created:&lt;/p&gt;

&lt;p&gt;app.post('/signin', (req, res) =&amp;gt; {&lt;br&gt;
    const { email, password } = req.body; // Destructuring for cleaner code&lt;br&gt;
    // For simplicity during testing, hardcoded a single user for authentication.&lt;br&gt;
    if (database.user[0].email === email &amp;amp;&amp;amp; database.user[0].password === password) {&lt;br&gt;
        res.json('success');&lt;br&gt;
    } else {&lt;br&gt;
        res.status(400).json('Invalid Credentials');&lt;br&gt;
    }&lt;br&gt;
});&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The /register Endpoint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For the registration route, I simulated adding a new user to our temporary database using the array's &lt;code&gt;push&lt;/code&gt; method:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app.post('/register', (req, res) =&amp;gt; {&lt;br&gt;
    const { email, name, password } = req.body;&lt;br&gt;
    database.users.push({&lt;br&gt;
        id: '125',&lt;br&gt;
        name: name,&lt;br&gt;
        email: email,&lt;br&gt;
        password: password,&lt;br&gt;
        entries: 0,&lt;br&gt;
        joined: new Date()&lt;br&gt;
    });&lt;br&gt;
    res.json(database.users[database.users.length - 1]);&lt;br&gt;
});&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The &lt;code&gt;/profile/:id&lt;/code&gt; Endpoint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;While not immediately used by the frontend in this version, I included this route for future expandability, allowing users to view their profiles later.&lt;/p&gt;

&lt;p&gt;JavaScript&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app.get('/profile/:id', (req, res) =&amp;gt; {&lt;br&gt;
    const { id } = req.params;&lt;br&gt;
    let found = false;&lt;br&gt;
    database.users.forEach(user =&amp;gt; {&lt;br&gt;
        if (user.id === id) {&lt;br&gt;
            found = true;&lt;br&gt;
            return res.json(user);&lt;br&gt;
        }&lt;br&gt;
    });&lt;br&gt;
    if (!found) {&lt;br&gt;
        res.status(404).json('User Not Found');&lt;br&gt;
    }&lt;br&gt;
});&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The &lt;code&gt;/image&lt;/code&gt; Endpoint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This endpoint is designed to receive a user ID and increment their &lt;code&gt;entries&lt;/code&gt; count, similar to the profile route.&lt;/p&gt;

&lt;p&gt;JavaScript&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app.put('/image', (req, res) =&amp;gt; {&lt;br&gt;
    const { id } = req.body;&lt;br&gt;
    let found = false;&lt;br&gt;
    database.users.forEach(user =&amp;gt; {&lt;br&gt;
        if (user.id === id) {&lt;br&gt;
            found = true;&lt;br&gt;
            user.entries++;&lt;br&gt;
            return res.json(user.entries);&lt;br&gt;
        }&lt;br&gt;
    });&lt;br&gt;
    if (!found) {&lt;br&gt;
        res.status(404).json('User Not Found');&lt;br&gt;
    }&lt;br&gt;
});&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After implementing each endpoint, I thoroughly tested it using Postman before moving to the next, ensuring functionality.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Crucial for Full-Stack: Understanding and Implementing CORS&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;All necessary endpoints were created and tested. It was time to connect them to the frontend. However, after connecting the sign-in endpoint and testing it with my frontend, I encountered the infamous &lt;strong&gt;CORS (Cross-Origin Resource Sharing) issue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The browser console showed that the request was blocked due to "no-cors." After doing some research, I understood that CORS ensures security by allowing controlled sharing of resources across different origins (domains) in a web browser. The backend is the proper place to handle this issue because it ensures that security rules are consistently applied and cannot be bypassed by malicious clients.&lt;/p&gt;

&lt;p&gt;To solve this, I added the &lt;code&gt;cors&lt;/code&gt; middleware to the backend. I installed it using &lt;code&gt;npm install cors&lt;/code&gt;, imported it (&lt;code&gt;import cors from 'cors'&lt;/code&gt;), and then added it as middleware (&lt;code&gt;app.use(cors())&lt;/code&gt;). With this, the sign-in endpoint now works perfectly with the frontend.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;Conclusion: The Backend's Power and What's Next&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;In this part, we successfully built and connected a foundational backend server to our frontend. While currently using a mock database for initial testing, this setup was crucial for establishing the core application flow.&lt;/p&gt;

&lt;p&gt;I learned a lot in this phase, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The value of outlining basic server endpoints before connecting to a final database.&lt;/li&gt;
&lt;li&gt;How to efficiently test API endpoints using &lt;strong&gt;Postman.com&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The importance of &lt;code&gt;express.json()&lt;/code&gt; middleware for parsing request bodies.&lt;/li&gt;
&lt;li&gt;The practical steps to connect backend endpoints to a frontend.&lt;/li&gt;
&lt;li&gt;How to identify and effectively handle &lt;strong&gt;CORS issues&lt;/strong&gt; in a full-stack application.&lt;/li&gt;
&lt;li&gt;The fundamental concepts of backend server development.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A Note on Clarifai API Integration (Next Steps)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You might have noticed that I haven't moved the Clarifai API integration to the backend in this specific part. My development approach was to first ensure all core components (frontend, backend server, and eventually database) were functional and communicating correctly. In a later refinement stage, or in a subsequent blog post, I'll integrate the Clarifai API directly into this backend for enhanced security and a more robust application architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What's Coming in Part 3&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that our frontend and backend are communicating, the next logical step is to introduce persistence! In Part 3, we'll dive into the &lt;strong&gt;database part&lt;/strong&gt;. We'll talk about how I created the database and connected it to the backend server using &lt;strong&gt;Knex.js&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Please don't forget to share your thoughts and leave comments about this blog. I'm always open to advice, so if you find something that needs to be changed or can be improved, just tell me!&lt;/p&gt;

</description>
      <category>backenddevelopment</category>
      <category>node</category>
      <category>express</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building My First Full-Stack App: Part 1 - Crafting the React Frontend for Face Detection</title>
      <dc:creator>Abhinav Anand</dc:creator>
      <pubDate>Tue, 27 May 2025 10:10:13 +0000</pubDate>
      <link>https://dev.to/abhinavan00/building-my-first-full-stack-app-part-1-crafting-the-react-frontend-for-face-detection-48k1</link>
      <guid>https://dev.to/abhinavan00/building-my-first-full-stack-app-part-1-crafting-the-react-frontend-for-face-detection-48k1</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;This is my first deep dive into building a full-stack web application, and I'm excited to share my learning journey and the technical steps involved. My goal with this project was to solidify my understanding of frontend development with React, connect to an external API, build a robust backend server, and manage a database – culminating in a deployed application.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is this app?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is a simple web application where users can paste an image URL, and the app will detect and highlight faces within that image.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Key Technologies Used:&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Front-End:&lt;/strong&gt; Vite + React.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Back-End:&lt;/strong&gt; Node.js + Express.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; PostgreSQL (managed with dBeaver)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  You can explore the full codebase here:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/abhinavan00/face_detection_app" rel="noopener noreferrer"&gt;https://github.com/abhinavan00/face_detection_app&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;The Frontend (React.js)&lt;/strong&gt;
&lt;/h1&gt;

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

&lt;p&gt;I initiated the React project using &lt;code&gt;npm create vite@latest&lt;/code&gt;, selecting JavaScript as the language. This provided a lightweight and fast development environment. After initial setup, I streamlined the project by removing unnecessary boilerplate from &lt;code&gt;App.jsx&lt;/code&gt;, &lt;code&gt;App.css&lt;/code&gt;, and &lt;code&gt;index.css&lt;/code&gt; to align with my specific design requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Core Component Architecture:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before writing any code, I planned the application's skeletal structure to ensure modularity and maintainability. The design included several functional components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Logo:&lt;/strong&gt; Displays the application branding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigation:&lt;/strong&gt; Handles user authentication links (Sign In, Register).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entry Count:&lt;/strong&gt; Shows user-specific data (e.g., images processed).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ImageLinkForm:&lt;/strong&gt; Contains the input field for image URLs and the submission button.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FaceRecognition:&lt;/strong&gt; Responsible for displaying the image and overlaying the detected bounding boxes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Components:&lt;/strong&gt; &lt;code&gt;App.jsx&lt;/code&gt; (the main container), &lt;code&gt;SignIn&lt;/code&gt;, and &lt;code&gt;Register&lt;/code&gt; pages. The &lt;code&gt;SignIn&lt;/code&gt; and &lt;code&gt;Register&lt;/code&gt; components were styled efficiently using &lt;strong&gt;Tachyons&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Handling User Input and Displaying Results:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For state management, I opted for &lt;strong&gt;React Class Components&lt;/strong&gt; in this project, although I have also practiced with React Hooks. The core state elements were &lt;code&gt;input&lt;/code&gt; (to capture the image URL from the form) and &lt;code&gt;imageUrl&lt;/code&gt; (to store the URL for image display).&lt;/p&gt;

&lt;p&gt;Upon user submission, the &lt;code&gt;input&lt;/code&gt; value updates &lt;code&gt;imageUrl&lt;/code&gt;. This &lt;code&gt;imageUrl&lt;/code&gt; is then passed as a prop to the &lt;code&gt;FaceRecognition&lt;/code&gt; component via &lt;code&gt;ImageLinkForm&lt;/code&gt;, enabling the image to be displayed.&lt;/p&gt;

&lt;p&gt;To detect faces and draw bounding boxes, I utilized &lt;strong&gt;Clarifai's face-detection API&lt;/strong&gt;. The initial API call was performed via &lt;strong&gt;JavaScript's Fetch API&lt;/strong&gt; (RESTful method). I also explored integrating this API using gRPC for a more robust backend solution in a separate practice session.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Overcoming the CORS Challenge (A First-Time Debugging Experience):&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This particular challenge significantly deepened my understanding of web security. Initially, my frontend API requests were consistently being rejected. I quickly identified the issue as a &lt;strong&gt;CORS (Cross-Origin Resource Sharing) policy violation&lt;/strong&gt;, a concept I hadn't encountered directly in my coursework.&lt;/p&gt;

&lt;p&gt;My local frontend server (running on &lt;code&gt;localhost&lt;/code&gt;) was attempting to make a direct request to the Clarifai API, which was blocking it for security reasons. After extensive searching and troubleshooting (including exploring my course's Discord channel and external resources), I understood the need to proxy the request.&lt;/p&gt;

&lt;p&gt;My immediate solution for testing was to create a &lt;strong&gt;"fake server"&lt;/strong&gt; (a simple local proxy) that would appear as the origin to Clarifai, bypassing the CORS restriction for development purposes. This temporary solution allowed me to successfully retrieve API results and proceed with development, though I knew a proper backend proxy would be essential for the final application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calculating and Displaying Bounding Boxes:&lt;/strong&gt;&lt;br&gt;
Once I received the data from Clarifai, the next step was to parse the API response to calculate the precise coordinates for the bounding boxes. This involved some careful geometric calculations based on the image dimensions and the API's returned data.&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%2Fkhuk45bqcync02g1pkkk.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%2Fkhuk45bqcync02g1pkkk.png" alt="Image description" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The calculated &lt;code&gt;displayFaceBox&lt;/code&gt; object was then passed as a prop to the &lt;code&gt;FaceRecognition&lt;/code&gt; component, which dynamically rendered the bounding boxes around the detected faces.&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%2F9s6wohgwg6lxpgp6m1w8.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%2F9s6wohgwg6lxpgp6m1w8.png" alt="Image description" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;I hope this first part has given you a clear insight into building the frontend of a full-stack application with React. I'd love to hear your thoughts or questions about anything covered here – feel free to leave them in the comments below!"&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>react</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
