<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Shivang Yadav]]></title><description><![CDATA[Shivang Yadav]]></description><link>https://blogs.shivangyadav.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 07 Apr 2026 22:01:58 GMT</lastBuildDate><atom:link href="https://blogs.shivangyadav.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Have you ever dealt with race conditions in your code?]]></title><description><![CDATA[While working on one of the feature in Leadlly, a platform designed to help students organize and maintain their self-studies, I encountered an interesting issue that got me thinking about race conditions in code.
The app is designed to generate new ...]]></description><link>https://blogs.shivangyadav.com/have-you-ever-dealt-with-race-conditions-in-your-code</link><guid isPermaLink="true">https://blogs.shivangyadav.com/have-you-ever-dealt-with-race-conditions-in-your-code</guid><category><![CDATA[scalability]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[System Design]]></category><category><![CDATA[software development]]></category><category><![CDATA[queue]]></category><category><![CDATA[message queue]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Sat, 19 Oct 2024 01:19:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729247650181/6d9bfa2e-a1ce-43b8-8bad-41662ab5e93c.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While working on one of the feature in <a target="_blank" href="https://www.leadlly.in/">Leadlly</a>, a platform designed to help students organize and maintain their self-studies, I encountered an interesting issue that got me thinking about <strong>race conditions</strong> in code.</p>
<p>The app is designed to generate new weekly planners for students every Sunday. Each planner contains multiple topics, and for each topic, a tracker is created to monitor the student's progress. Initially, everything seemed to be working perfectly fine when I was testing the app with just a few users—trackers were being created without any problems, and all operations went smoothly.</p>
<p>But then, as I scaled up the test environment to include a larger number of students and more topics, things started to break down. Trackers were no longer being created as expected, and the system's behavior became inconsistent. Some topic trackers were being generated successfully, while others were not. This inconsistency pointed to a deeper issue.</p>
<h3 id="heading-diagnosing-the-problem-a-race-condition">Diagnosing the Problem: A Race Condition</h3>
<p>After digging into the problem, I discovered that <strong>multiple trackers</strong> were being created simultaneously, and they were all trying to write to the <strong>same spot</strong> in MongoDB at the same time. This simultaneous access led to conflicts—basically, several processes were attempting to create trackers at the same index, which caused errors and inconsistencies.</p>
<p>This situation is a classic example of a <strong>race condition</strong>—a situation where multiple processes try to access and modify shared data simultaneously, resulting in unpredictable outcomes.</p>
<h3 id="heading-the-solution-implementing-a-queue-system">The Solution: Implementing a Queue System</h3>
<p>To solve the issue, I introduced a <strong>queue system</strong> for the tracker creation process. Instead of allowing all the tracker creation tasks to run at the same time and conflict with each other, I used a queue to process these tasks sequentially.</p>
<p>By integrating <strong>BullMQ</strong> (a popular message queue library), I was able to manage the tracker creation process in a controlled, orderly fashion. BullMQ allows tasks to be queued up and processed one by one, ensuring that each student's trackers are created without interference from other tasks.</p>
<p>With this system in place, each student's tracker is now generated in sequence, and there's no more chaos or conflict in the database. The result? Smooth and consistent tracker creation across the board.</p>
<p>Learn more about queues and how they work in detail in this <a target="_blank" href="https://blogs.shivangyadav.me/scaling-backend-servers-with-messaging-queues-a-deep-dive-using-bullmq"><strong>blog</strong></a><strong>.</strong></p>
<h3 id="heading-other-possible-solutions">Other Possible Solutions</h3>
<p>While the queue system solved my problem efficiently, it's not the only way to handle such race conditions. Here are two other potential approaches:</p>
<ol>
<li><p><strong>Database Transactions</strong></p>
<p> One approach to solving race conditions is to use <strong>database transactions</strong>. By wrapping the operations that create planners and trackers in a transaction, you can ensure that all operations are atomic—meaning either everything is completed successfully, or none of it happens. This ensures that partial or conflicting updates do not occur, as the database guarantees consistency during the entire process.</p>
</li>
<li><p><strong>Batch Processing</strong></p>
<p> Another alternative is to implement <strong>batch processing</strong>. Rather than creating trackers immediately as requests come in, you could schedule jobs to run in batches at specific intervals (such as every hour or at night). This would allow the system to process tracker creation tasks in bulk, minimizing the risk of race conditions and reducing the load on the database during peak times.</p>
</li>
</ol>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Race conditions can be tricky, especially when scaling an application that handles many concurrent tasks. In Leadlly, the race condition I faced with tracker creation was resolved by introducing a queue system with BullMQ, which ensured that each task was processed sequentially and in an orderly manner. However, solutions like database transactions and batch processing are also viable alternatives, depending on your application's specific needs.</p>
<p>If you're dealing with a similar problem in your application, consider which solution fits best for your use case—whether it's introducing a queue, using transactions, or scheduling batch jobs.</p>
<p>Have you faced similar challenges while scaling your application? How did you handle race conditions?</p>
]]></content:encoded></item><item><title><![CDATA[How Payment Gateways Work: Complete Guide with Razorpay Integration in Node.js]]></title><description><![CDATA[1. What is a Payment Gateway?
A payment gateway is a service that facilitates online payments between buyers and sellers. It acts as a bridge between the customer, the merchant, and the bank. Payment gateways securely transmit payment information for...]]></description><link>https://blogs.shivangyadav.com/how-payment-gateway-works-a-detailed-guide</link><guid isPermaLink="true">https://blogs.shivangyadav.com/how-payment-gateway-works-a-detailed-guide</guid><category><![CDATA[payment gateway]]></category><category><![CDATA[Payment Gateway integrations on website]]></category><category><![CDATA[razorpay]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[software development]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Fri, 18 Oct 2024 02:18:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729217772474/502725da-33ba-45ea-9456-973913057930.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-1-what-is-a-payment-gateway"><strong>1. What is a Payment Gateway?</strong></h4>
<p>A payment gateway is a service that facilitates online payments between buyers and sellers. It acts as a bridge between the customer, the merchant, and the bank. Payment gateways securely transmit payment information for credit cards, debit cards, UPI, and other payment methods.</p>
<h4 id="heading-2-components-of-a-payment-gateway"><strong>2. Components of a Payment Gateway</strong></h4>
<ol>
<li><p><strong>Merchant</strong>: The business or individual selling a product or service.</p>
</li>
<li><p><strong>Customer</strong>: The buyer who makes the payment.</p>
</li>
<li><p><strong>Acquiring Bank</strong>: The merchant's bank that receives the payment.</p>
</li>
<li><p><strong>Issuing Bank</strong>: The customer’s bank that issues the credit or debit card.</p>
</li>
<li><p><strong>Payment Processor</strong>: Handles the transaction processing and communicates between the acquiring bank and issuing bank.</p>
</li>
<li><p><strong>Payment Gateway</strong>: The service that authorizes and handles the secure transmission of payment information.</p>
</li>
</ol>
<h4 id="heading-3-how-payment-gateway-works-transaction-flow"><strong>3. How Payment Gateway Works: Transaction Flow</strong></h4>
<p>Here’s the step-by-step flow of how a payment gateway processes payments:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729154036920/6ca1e845-4cba-421a-a37f-567327dd918d.png" alt class="image--center mx-auto" /></p>
<p><strong>Step 1: Customer Initiates Payment</strong></p>
<ul>
<li><p>The customer selects products/services on a merchant’s website and proceeds to checkout.</p>
</li>
<li><p>At the checkout, the customer chooses a payment method (e.g., credit/debit card, UPI).</p>
</li>
</ul>
<p><strong>Step 2: Payment Gateway Authorization</strong></p>
<ul>
<li>Once the customer submits the payment details, the payment gateway securely encrypts and transmits this information to the acquiring bank.</li>
</ul>
<p><strong>Step 3: Acquirer Requests Authorization</strong></p>
<ul>
<li>The acquiring bank sends the payment request to the respective card network (e.g., Visa, MasterCard) or UPI network.</li>
</ul>
<p><strong>Step 4: Issuing Bank Validates</strong></p>
<ul>
<li>The issuing bank (customer’s bank) checks if the customer has sufficient funds or credit limit and performs fraud checks.</li>
</ul>
<p><strong>Step 5: Approval or Denial</strong></p>
<ul>
<li><p>Based on the validation, the issuing bank approves or denies the transaction.</p>
</li>
<li><p>The decision is communicated back to the payment gateway.</p>
</li>
</ul>
<p><strong>Step 6: Payment Confirmation</strong></p>
<ul>
<li><p>The payment gateway informs the merchant if the payment was successful or failed.</p>
</li>
<li><p>If successful, the merchant processes the order.</p>
</li>
</ul>
<p><strong>Step 7: Settlement</strong></p>
<ul>
<li>The acquiring bank collects the payment from the issuing bank and settles the amount with the merchant’s bank account, usually within a few business days.</li>
</ul>
<h3 id="heading-4-payment-gateway-security"><strong>4. Payment Gateway Security</strong></h3>
<ol>
<li><p><strong>SSL Encryption</strong>: Ensures secure data transmission between customers and payment gateways.</p>
</li>
<li><p><strong>PCI-DSS Compliance</strong>: Industry standard for securely handling credit card information stated in <a target="_blank" href="https://www.pcisecuritystandards.org/document_library/">Payment Card Industry Data Security Standard</a>.</p>
</li>
<li><p><strong>Tokenization</strong>: Sensitive data is replaced by unique identification symbols (tokens) that are exchanged during the payment.</p>
</li>
<li><p><strong>3D Secure</strong>: 3D Secure (3-domain structure), an additional security layer that addresses issues of fraud in online debit or credit card transactions.</p>
</li>
</ol>
<h3 id="heading-5-introduction-to-razorpay-payment-gateway"><strong>5. Introduction to Razorpay Payment Gateway</strong></h3>
<p>Razorpay is a popular payment gateway that supports multiple payment methods, including credit/debit cards, UPI, net banking, and wallets. Razorpay simplifies the process for merchants by providing an easy-to-integrate API for accepting payments.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729153403220/77dd2a0c-1fe2-4402-88d1-6ab9ae4c1382.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-6-integrating-razorpay-in-nodejs-application"><strong>6. Integrating Razorpay in Node.js Application</strong></h3>
<p>Let’s now go step by step on how to integrate Razorpay into a Node.js project.</p>
<h4 id="heading-step-1-install-required-packages"><strong>Step 1: Install Required Packages</strong></h4>
<p>You need to install the Razorpay Node.js SDK and any other required dependencies.</p>
<pre><code class="lang-bash">npm install razorpay express body-parser
</code></pre>
<h4 id="heading-step-2-set-up-razorpay-account"><strong>Step 2: Set up Razorpay Account</strong></h4>
<ul>
<li><p>Sign up on <a target="_blank" href="https://razorpay.com/">Razorpay</a>.</p>
</li>
<li><p>Create an API key in the Razorpay dashboard. You will get a <code>key_id</code> and <code>key_secret</code>, which will be used to authenticate API requests.</p>
</li>
</ul>
<h4 id="heading-step-3-initialize-razorpay"><strong>Step 3: Initialize Razorpay</strong></h4>
<p>In your Node.js application, you need to initialize Razorpay using the SDK. Create a file called <code>payment.js</code> to manage your payment logic.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Razorpay = <span class="hljs-built_in">require</span>(<span class="hljs-string">"razorpay"</span>);

<span class="hljs-keyword">const</span> razorpayInstance = <span class="hljs-keyword">new</span> Razorpay({
  <span class="hljs-attr">key_id</span>: process.env.RAZORPAY_KEY_ID, <span class="hljs-comment">// Replace with your Razorpay key_id</span>
  <span class="hljs-attr">key_secret</span>: process.env.RAZORPAY_KEY_SECRET, <span class="hljs-comment">// Replace with your Razorpay key_secret</span>
});
</code></pre>
<h4 id="heading-step-4-create-payment-order-api"><strong>Step 4: Create Payment Order API</strong></h4>
<p>You need to create an endpoint to generate a payment order before sending it to the client for payment.</p>
<pre><code class="lang-javascript">app.post(<span class="hljs-string">"/api/create-order"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { amount, currency, receipt } = req.body;

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> options = {
      <span class="hljs-attr">amount</span>: amount * <span class="hljs-number">100</span>, <span class="hljs-comment">// amount in the smallest currency unit (e.g., paise for INR)</span>
      currency,
      receipt,
    };

    <span class="hljs-keyword">const</span> order = <span class="hljs-keyword">await</span> razorpayInstance.orders.create(options);
    res.status(<span class="hljs-number">200</span>).json(order);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: error.message });
  }
});
</code></pre>
<h4 id="heading-step-5-frontend-integration"><strong>Step 5: Frontend Integration</strong></h4>
<p>On the client side, you need to display the Razorpay payment form. Use the Razorpay checkout script:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://checkout.razorpay.com/v1/checkout.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Then, initialize Razorpay when the user clicks on the "Pay Now" button.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> options = {
  <span class="hljs-attr">key</span>: <span class="hljs-string">"YOUR_RAZORPAY_KEY_ID"</span>, <span class="hljs-comment">// Enter the Key ID generated from Razorpay Dashboard</span>
  <span class="hljs-attr">amount</span>: order.amount, <span class="hljs-comment">// Amount in paise</span>
  <span class="hljs-attr">currency</span>: order.currency,
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Merchant Name"</span>,
  <span class="hljs-attr">description</span>: <span class="hljs-string">"Test Transaction"</span>,
  <span class="hljs-attr">order_id</span>: order.id, <span class="hljs-comment">// Order ID created in the backend</span>
  <span class="hljs-attr">callback_url</span>: <span class="hljs-string">"/api/verify-payment"</span>, <span class="hljs-comment">// Usually for verifying subscription</span>
  <span class="hljs-attr">prefill</span>: {
    <span class="hljs-attr">name</span>: <span class="hljs-string">"Customer Name"</span>,
    <span class="hljs-attr">email</span>: <span class="hljs-string">"customer@example.com"</span>,
    <span class="hljs-attr">contact</span>: <span class="hljs-string">"9999999999"</span>,
  },
};
<span class="hljs-keyword">const</span> rzp = <span class="hljs-keyword">new</span> Razorpay(options);
rzp.open();
</code></pre>
<h4 id="heading-step-6-handle-payment-success"><strong>Step 6: Handle Payment Success</strong></h4>
<p>Once the payment is successful, Razorpay sends back a payment ID and order ID. You can use this data to verify the payment on the server side.</p>
<pre><code class="lang-javascript">app.post(<span class="hljs-string">"/api/verify-payment"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { razorpay_order_id, razorpay_payment_id, razorpay_signature } = req.body;

  <span class="hljs-keyword">const</span> body = razorpay_order_id + <span class="hljs-string">"|"</span> + razorpay_payment_id;
  <span class="hljs-keyword">const</span> crypto = <span class="hljs-built_in">require</span>(<span class="hljs-string">"crypto"</span>);
  <span class="hljs-keyword">const</span> expectedSignature = crypto
    .createHmac(<span class="hljs-string">"sha256"</span>, process.env.RAZORPAY_KEY_SECRET)
    .update(body.toString())
    .digest(<span class="hljs-string">"hex"</span>);

  <span class="hljs-keyword">if</span> (expectedSignature === razorpay_signature) {
    res.send({ <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span> });
  } <span class="hljs-keyword">else</span> {
    res.send({ <span class="hljs-attr">success</span>: <span class="hljs-literal">false</span> });
  }
});
</code></pre>
<h3 id="heading-7-conclusion"><strong>7. Conclusion</strong></h3>
<p>A payment gateway ensures that online transactions are conducted securely and efficiently. In this blog, we discussed how payment gateways work, and we provided a detailed guide on integrating Razorpay with Node.js. You can now enable payments in your Node.js app using Razorpay, following this step-by-step guide.</p>
<hr />
<h3 id="heading-additional-resources"><strong>Additional Resources</strong></h3>
<ul>
<li><a target="_blank" href="https://razorpay.com/docs/">Razorpay Documentation</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Decoding JWT: Authentication and Authorization in Node.js]]></title><description><![CDATA[JSON Web Token (JWT) is widely used for handling authentication and authorization in modern web applications. JWT allows secure and compact transmission of information between parties as a JSON object, and this information is verifiable and trusted b...]]></description><link>https://blogs.shivangyadav.com/decoding-jwt-authentication-and-authorization-in-nodejs</link><guid isPermaLink="true">https://blogs.shivangyadav.com/decoding-jwt-authentication-and-authorization-in-nodejs</guid><category><![CDATA[authentication]]></category><category><![CDATA[JWT]]></category><category><![CDATA[JSON Web Tokens (JWT)]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[authorization]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Wed, 16 Oct 2024 06:24:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729059758751/14b7583d-fec9-4c00-96d6-a240bfdd4d75.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>JSON Web Token (JWT) is widely used for handling authentication and authorization in modern web applications. JWT allows secure and compact transmission of information between parties as a JSON object, and this information is verifiable and trusted because it is digitally signed. In this blog, we will explore the underlying mechanisms of JWT, understand its importance in web security, and walk through a practical implementation in Node.js.</p>
<h3 id="heading-what-is-jwt">What is JWT?</h3>
<p><strong>JSON Web Token (JWT)</strong> is an open standard (<a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc7519">RFC 7519</a>) to send information between two parties securely. It uses a compact format that is safe to use in URLs, and it contains claims (data) that can be verified and trusted.</p>
<p>A JWT is essentially a long string made up of three parts:</p>
<ol>
<li><p><strong>Header</strong></p>
</li>
<li><p><strong>Payload</strong></p>
</li>
<li><p><strong>Signature</strong></p>
</li>
</ol>
<p>These parts are concatenated with dots (<code>.</code>), making up a token of the form:</p>
<pre><code class="lang-bash">{Base64Url encoded header}.{Base64Url encoded payload}.{Signature}
</code></pre>
<h3 id="heading-jwt-structure">JWT Structure</h3>
<p>Let’s break down each of the three parts of JWT in detail:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728962196049/00e83096-a46a-4acf-8560-3a49a08277a9.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-1-header">1. Header</h4>
<p>The header contains two critical elements:</p>
<ul>
<li><p><code>alg</code>: The algorithm used to sign the token (e.g., HMAC SHA256 or RSA).</p>
</li>
<li><p><code>typ</code>: The type of token, which is usually <code>"JWT"</code>.</p>
</li>
</ul>
<p>Here’s an example of what a JWT header might look like:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"alg"</span>: <span class="hljs-string">"HS256"</span>,
  <span class="hljs-attr">"typ"</span>: <span class="hljs-string">"JWT"</span>
}
</code></pre>
<p>The header is Base64Url encoded to form the first part of the token.</p>
<h4 id="heading-2-payload">2. Payload</h4>
<p>The payload is where the actual data is stored in the form of <strong>claims</strong>. Claims are statements about an entity (usually the user) and additional metadata. JWT defines three types of claims:</p>
<ul>
<li><p><strong>Registered Claims</strong>: Predefined, optional claims that are useful across many use cases. Examples include:</p>
<ul>
<li><p><code>iss</code>: Issuer (who issued the token).</p>
</li>
<li><p><code>sub</code>: Subject (the user or entity the token is for).</p>
</li>
<li><p><code>aud</code>: Audience (who the token is intended for).</p>
</li>
<li><p><code>exp</code>: Expiration time (when the token expires).</p>
</li>
<li><p><code>iat</code>: Issued at (the time when the token was issued).</p>
</li>
</ul>
</li>
</ul>
<p>    These registered claims are optional, but using them is a good practice as they standardize token structure.</p>
<ul>
<li><p><strong>Public Claims</strong>: These claims are custom, and you define them according to your needs. An example could be the role of the user (<code>admin</code>, <code>editor</code>, <code>viewer</code>).</p>
<pre><code class="lang-json">  {
    <span class="hljs-attr">"sub"</span>: <span class="hljs-string">"1234567890"</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>,
    <span class="hljs-attr">"admin"</span>: <span class="hljs-literal">true</span>
  }
</code></pre>
</li>
<li><p><strong>Private Claims</strong>: Claims created specifically for sharing information between parties that agree on using them. These are generally application-specific and should not collide with registered or public claims.</p>
</li>
</ul>
<p>The payload is also Base64Url encoded.</p>
<h4 id="heading-what-is-a-claim">What is a Claim?</h4>
<p>A <strong>claim</strong> is a piece of information in a JWT that expresses something about the user, the authentication session, or other relevant context. Claims can be anything from a user’s identity (<code>sub</code>) to their role (<code>admin</code>), or even metadata like the time the token was issued (<code>iat</code>) or its expiration (<code>exp</code>). Claims allow the server to enforce access control based on the information contained in the token.</p>
<h4 id="heading-3-signature">3. Signature</h4>
<p>The signature is the key to verifying that the token hasn’t been tampered with. It is created by taking the encoded header, encoded payload, and a secret key and signing them using the algorithm specified in the header.</p>
<p>The signature process looks like this:</p>
<pre><code class="lang-bash">HMACSHA256(
  base64UrlEncode(header) + <span class="hljs-string">"."</span> + base64UrlEncode(payload),
  secret
)
</code></pre>
<p>The signature ensures that the token’s contents have not been modified. If someone tries to tamper with the payload or header, the signature verification will fail on the server.</p>
<h3 id="heading-how-jwt-works">How JWT Works</h3>
<p>Now that we’ve broken down the structure of a JWT, let’s see how it works in practice.</p>
<h4 id="heading-1-authentication">1. <strong>Authentication</strong></h4>
<p>When a user logs in to an application (by providing their credentials, for example), the server authenticates the user and creates a JWT that includes information about the user (e.g., <code>sub</code>: the user's ID). This token is then sent to the client, which stores it (usually in localStorage or cookies).</p>
<h4 id="heading-2-authorization">2. <strong>Authorization</strong></h4>
<p>When the client makes subsequent requests to the server (for example, accessing a protected route), the JWT is sent along in the HTTP <code>Authorization</code> header, in the format:</p>
<pre><code class="lang-bash">Authorization: Bearer &lt;token&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728962218743/ad6a676a-8d65-41bb-9619-c427821b41be.png" alt class="image--center mx-auto" /></p>
<p>The server verifies the token using the secret key. If the token is valid and has not expired, the server grants access to the requested resource. If the token is invalid (e.g., due to tampering or expiration), the server rejects the request.</p>
<h3 id="heading-jwt-lifecycle">JWT Lifecycle</h3>
<ol>
<li><p><strong>User Login</strong>: The client sends credentials (username and password) to the server.</p>
</li>
<li><p><strong>Token Generation</strong>: The server verifies the credentials and generates a JWT containing the user's information (payload), signing it with a secret.</p>
</li>
<li><p><strong>Token Storage</strong>: The client stores the token in localStorage, sessionStorage, or a cookie.</p>
</li>
<li><p><strong>Authenticated Requests</strong>: For protected routes, the client includes the token in the <code>Authorization</code> header.</p>
</li>
<li><p><strong>Token Verification</strong>: The server verifies the token and checks for valid claims (e.g., expiration, issuer).</p>
</li>
<li><p><strong>Response</strong>: If the token is valid, the server responds with the requested data. Otherwise, it rejects the request.</p>
</li>
</ol>
<h3 id="heading-implementing-jwt-in-nodejs">Implementing JWT in Node.js</h3>
<p>Let’s now implement JWT for authentication and authorization in a simple Node.js application using the <code>jsonwebtoken</code> library.</p>
<h4 id="heading-step-1-project-setup">Step 1: Project Setup</h4>
<pre><code class="lang-bash">npm init -y
npm install express jsonwebtoken bcrypt
</code></pre>
<h4 id="heading-step-2-create-a-simple-authentication-system">Step 2: Create a Simple Authentication System</h4>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'jsonwebtoken'</span>);
<span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'bcrypt'</span>);

<span class="hljs-keyword">const</span> app = express();
app.use(express.json());

<span class="hljs-keyword">const</span> users = [];
<span class="hljs-keyword">const</span> SECRET_KEY = <span class="hljs-string">'your_jwt_secret_key'</span>;

<span class="hljs-comment">// Register Endpoint</span>
app.post(<span class="hljs-string">'/register'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { username, password } = req.body;
  <span class="hljs-keyword">const</span> hashedPassword = <span class="hljs-keyword">await</span> bcrypt.hash(password, <span class="hljs-number">10</span>);
  users.push({ username, <span class="hljs-attr">password</span>: hashedPassword });
  res.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'User registered successfully!'</span> });
});

<span class="hljs-comment">// Login Endpoint</span>
app.post(<span class="hljs-string">'/login'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { username, password } = req.body;
  <span class="hljs-keyword">const</span> user = users.find(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.username === username);

  <span class="hljs-keyword">if</span> (!user || !(<span class="hljs-keyword">await</span> bcrypt.compare(password, user.password))) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Invalid credentials'</span> });
  }

  <span class="hljs-keyword">const</span> token = jwt.sign({ username }, SECRET_KEY, { <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">'1h'</span> });
  res.json({ token });
});

<span class="hljs-comment">// Protected Route</span>
app.get(<span class="hljs-string">'/protected'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> token = req.headers[<span class="hljs-string">'authorization'</span>]?.split(<span class="hljs-string">' '</span>)[<span class="hljs-number">1</span>];

  <span class="hljs-keyword">if</span> (!token) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">401</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Token required'</span> });
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> decoded = jwt.verify(token, SECRET_KEY);
    res.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">`Welcome, <span class="hljs-subst">${decoded.username}</span>!`</span> });
  } <span class="hljs-keyword">catch</span> (err) {
    res.status(<span class="hljs-number">401</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Invalid token'</span> });
  }
});

app.listen(<span class="hljs-number">3000</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server running on port 3000'</span>);
});
</code></pre>
<p>In this code:</p>
<ul>
<li><p>Users register with a username and password, which is hashed using <code>bcrypt</code>.</p>
</li>
<li><p>Upon login, a JWT is generated and sent back to the client.</p>
</li>
<li><p>The protected route <code>/protected</code> is only accessible to users with a valid JWT token in the <code>Authorization</code> header.</p>
</li>
</ul>
<h3 id="heading-conclusion">Conclusion</h3>
<p>JWT is an essential part of modern authentication and authorization systems due to its stateless, compact, and secure nature. By using claims, JWT provides flexibility in representing user data while ensuring the integrity and authenticity of that data through signatures.</p>
]]></content:encoded></item><item><title><![CDATA[Exploring Amazon S3 Pre-Signed URLs: A Scalable Approach to Secure File Access]]></title><description><![CDATA[We know, as applications grow in complexity and usage, efficient, secure, and scalable data handling becomes crucial. Handling file uploads is a common requirement in web applications, especially in scenarios where users upload large amounts of data ...]]></description><link>https://blogs.shivangyadav.com/exploring-amazon-s3-pre-signed-urls-a-scalable-approach-to-secure-file-access</link><guid isPermaLink="true">https://blogs.shivangyadav.com/exploring-amazon-s3-pre-signed-urls-a-scalable-approach-to-secure-file-access</guid><category><![CDATA[AWS]]></category><category><![CDATA[AWS s3]]></category><category><![CDATA[S3-bucket]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[software development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[scalability]]></category><category><![CDATA[File handling]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Mon, 14 Oct 2024 00:55:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728867066343/70dabd92-5655-44b3-944e-601c2c9404be.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We know, as applications grow in complexity and usage, efficient, secure, and scalable data handling becomes crucial. Handling file uploads is a common requirement in web applications, especially in scenarios where users upload large amounts of data like images, videos, or documents. Traditionally, this involves sending files to the backend server, which processes the upload and forwards it to a storage solution like AWS S3. However, as your user base grows, this approach can cause significant performance bottlenecks, scalability issues, and security concerns. This is where <strong>Amazon S3 pre-signed URLs</strong> come to the rescue!</p>
<p>In this blog, we’ll explore how <strong>Amazon S3 pre-signed URLs</strong> work, how they can help offload your server from handling file uploads directly, and how to implement them in a Node.js backend for a more scalable and efficient architecture.</p>
<h2 id="heading-what-is-amazon-s3">What is Amazon S3?</h2>
<p>Amazon Simple Storage Service (Amazon S3) is a cloud storage service provided by AWS (Amazon Web Services). It allows you to store and retrieve any amount of data at any time from anywhere on the web. S3 is ideal for storing files such as images, videos, documents, and backups. It provides high availability, security, and scalability for storing large amounts of data.</p>
<h4 id="heading-key-components-of-amazon-s3">Key Components of Amazon S3</h4>
<ol>
<li><p><strong>Buckets</strong>:</p>
<ul>
<li><p>Buckets are the fundamental containers in S3 that hold your data. Each bucket has a unique name within the AWS region and acts as a namespace for the objects stored inside it. You can think of a bucket as a folder or directory that can contain multiple files.</p>
</li>
<li><p>For example, you might create a bucket named <code>my-photos</code> to store all your image files, or <code>my-backups</code> for backup files.</p>
</li>
</ul>
</li>
<li><p><strong>Objects</strong>:</p>
<ul>
<li><p>The actual files stored in S3 are referred to as objects. Each object consists of the data itself, metadata (information about the data), and a unique identifier known as the object key (the path to the file within the bucket).</p>
</li>
<li><p>For instance, an object key could look like <code>my-photos/image1.jpg</code>, representing an image stored in the <code>my-photos</code> bucket.</p>
</li>
</ul>
</li>
<li><p><strong>Unlimited Storage</strong>:</p>
<ul>
<li>One of the significant advantages of S3 is its virtually unlimited storage capability. You can create as many buckets as you need and store an unlimited number of objects within those buckets. This flexibility makes S3 an ideal choice for businesses and applications with growing data storage needs.</li>
</ul>
</li>
<li><p><strong>Storage Classes</strong>:</p>
<ul>
<li><p>Amazon S3 offers various storage classes designed to optimize cost and performance for different use cases. For example:</p>
<ul>
<li><p><strong>S3 Standard</strong>: Best for frequently accessed data.</p>
</li>
<li><p><strong>S3 Intelligent-Tiering</strong>: Automatically moves data between two access tiers when access patterns change.</p>
</li>
<li><p><strong>S3 Glacier</strong>: Low-cost storage for data archiving, with retrieval times ranging from minutes to hours.</p>
</li>
<li><p><strong>S3 One Zone-IA</strong>: For infrequently accessed data that doesn't require multiple availability zone resilience.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Access Control</strong>:</p>
<ul>
<li>Amazon S3 provides robust security and access control features. You can set permissions at both the bucket and object levels, allowing you to define who can access your data and what actions they can perform. This is managed through AWS Identity and Access Management (IAM) policies, bucket policies, and Access Control Lists (ACLs).</li>
</ul>
</li>
<li><p><strong>Data Management and Lifecycle Policies</strong>:</p>
<ul>
<li>S3 offers features to help manage your data efficiently. You can create lifecycle policies to automatically transition objects between different storage classes or delete them after a specified period. This helps optimize storage costs by moving less frequently accessed data to more cost-effective storage classes.</li>
</ul>
</li>
</ol>
<h2 id="heading-the-challenge-with-traditional-file-uploads">The Challenge with Traditional File Uploads</h2>
<p>In traditional setups, files uploaded by users are first sent to the backend server. The server processes these files, perhaps performing validation or format conversion, and then stores them in a storage service like S3.</p>
<p>Let’s take the example of a <strong>video-sharing platform</strong> similar to YouTube, where users frequently upload large video files. In a traditional setup, the backend would need to handle each video file upload, which could be hundreds of megabytes or even gigabytes in size. With multiple users uploading videos simultaneously, the server’s bandwidth and CPU would be overwhelmed, causing high latency and slow uploads. This situation gets worse during peak hours or when the platform's popularity grows. As a result, scaling such a system would require adding more powerful servers or load balancers, significantly increasing costs.</p>
<p>The flow looks something like this:</p>
<ol>
<li><p><strong>Client</strong> → Uploads a file to <strong>Backend Server</strong>.</p>
</li>
<li><p><strong>Backend Server</strong> → Receives the file, validates it, processes it, and uploads it to <strong>S3</strong>.</p>
</li>
</ol>
<h3 id="heading-problems-with-this-approach">Problems with this approach:</h3>
<ul>
<li><p><strong>Server Load</strong>: Your server must handle multiple uploads, which can consume bandwidth and CPU resources. This can slow down the server and lead to poor performance as more users upload files simultaneously.</p>
</li>
<li><p><strong>Scaling Issues</strong>: As the number of users and file uploads increases, scaling your backend servers becomes challenging and costly.</p>
</li>
<li><p><strong>Latency</strong>: Uploading files to the server and then transferring them to S3 introduces delays, affecting the overall user experience.</p>
</li>
</ul>
<h2 id="heading-the-solution-amazon-s3-pre-signed-urls">The Solution: Amazon S3 Pre-signed URLs</h2>
<p>With <strong>Amazon S3 pre-signed URLs</strong>, you can bypass the backend server and upload files directly from the client to S3. The server's role is limited to generating a URL that gives the client temporary permission to upload a file directly to S3.</p>
<h3 id="heading-how-it-works">How It Works:</h3>
<ol>
<li><p>The client requests a pre-signed URL from the server.</p>
</li>
<li><p>The server generates a <strong>pre-signed URL</strong> with specific permissions and an expiration time.</p>
</li>
<li><p>The client uses this pre-signed URL to upload the file directly to <strong>Amazon S3</strong>.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728864295590/310407d6-4ca8-444e-a102-bae604e9df7f.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-benefits">Benefits:</h3>
<ul>
<li><p><strong>Reduced Server Load</strong>: Since files are uploaded directly to S3, your backend doesn’t have to handle the file data.</p>
</li>
<li><p><strong>Scalability</strong>: S3 is highly scalable, capable of handling thousands of file uploads simultaneously, so you don’t have to worry about scaling your backend servers for uploads.</p>
</li>
<li><p><strong>Security</strong>: Pre-signed URLs are time-limited and only allow specific operations (like uploads), reducing the risk of unauthorized access to your S3 bucket.</p>
</li>
</ul>
<h2 id="heading-understanding-pre-signed-urls">Understanding Pre-signed URLs</h2>
<p>A <strong>pre-signed URL</strong> is a URL that you generate in your backend using your AWS credentials. It gives a client temporary access to upload or download a file in S3. The URL contains parameters like:</p>
<ul>
<li><p><strong>Bucket Name</strong>: The name of the S3 bucket where the file will be uploaded.</p>
</li>
<li><p><strong>Key (File Name)</strong>: The path and name of the file within the bucket.</p>
</li>
<li><p><strong>Permissions</strong>: The action the client can perform (e.g., PUT for uploading files).</p>
</li>
<li><p><strong>Expiration Time</strong>: How long the URL will be valid (e.g., 15 minutes).</p>
</li>
</ul>
<p>Once the URL is generated, the client can use it to interact with S3 without needing access to your AWS credentials.</p>
<h2 id="heading-implementation-in-nodejs">Implementation in Node.js</h2>
<p>Let’s implement a simple Node.js API that generates a pre-signed URL for uploading files to S3.</p>
<h3 id="heading-prerequisites">Prerequisites:</h3>
<ul>
<li><p>AWS Account with S3 permissions.</p>
</li>
<li><p>Node.js installed.</p>
</li>
<li><p>AWS SDK for Node.js installed.</p>
</li>
</ul>
<h3 id="heading-step-1-set-up-aws-sdk-and-s3-bucket">Step 1: Set Up AWS SDK and S3 Bucket</h3>
<p>First, install the AWS SDK in your Node.js project:</p>
<pre><code class="lang-bash">npm install aws-sdk @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
</code></pre>
<p>In your AWS console, create an S3 bucket where the files will be stored. Note the bucket name for use in the code.</p>
<h3 id="heading-step-2-set-up-nodejs-environment">Step 2: Set Up Node.js Environment</h3>
<p>In your project, create a <code>.env</code> file to store your AWS credentials:</p>
<pre><code class="lang-plaintext">AWS_ACCESS_KEY_ID=your-access-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
AWS_REGION=your-region
S3_BUCKET_NAME=your-s3-bucket-name
</code></pre>
<p>Then, create an <code>index.js</code> file for your server:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { S3Client, PutObjectCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-s3"</span>;
<span class="hljs-keyword">import</span> { getSignedUrl } <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/s3-request-presigner"</span>;
<span class="hljs-keyword">import</span> { config } <span class="hljs-keyword">from</span> <span class="hljs-string">"dotenv"</span>;
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;

config();

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

<span class="hljs-comment">// Configure AWS SDK with credentials</span>
<span class="hljs-keyword">const</span> S3 = <span class="hljs-keyword">new</span> S3Client({
  <span class="hljs-attr">region</span>: process.env.AWS_REGION, 
  <span class="hljs-attr">credentials</span>: {
    <span class="hljs-attr">accessKeyId</span>: process.env.AWS_ACCESS_KEY_ID,
    <span class="hljs-attr">secretAccessKey</span>: process.env.AWS_SECRET_ACCESS_KEY,
  },
});

<span class="hljs-comment">// Generate a pre-signed URL</span>
app.get(<span class="hljs-string">'/generate-presigned-url'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { fileName, fileType } = req.query;

  <span class="hljs-keyword">if</span> (!fileName || !fileType) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Missing fileName or fileType"</span> });
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Define parameters for the pre-signed URL</span>
    <span class="hljs-keyword">const</span> command = <span class="hljs-keyword">new</span> PutObjectCommand({
      <span class="hljs-attr">Bucket</span>: process.env.AWS_S3_BUCKET, 
      <span class="hljs-attr">Key</span>: fileName, 
      <span class="hljs-attr">ContentType</span>: fileType, 
    });

    <span class="hljs-comment">// Generate the pre-signed URL</span>
    <span class="hljs-keyword">const</span> requestURL = <span class="hljs-keyword">await</span> getSignedUrl(S3, command, { <span class="hljs-attr">expiresIn</span>: <span class="hljs-number">3600</span> }); <span class="hljs-comment">// URL valid for 1 hour</span>

    res.json({ requestURL });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error generating presigned URL"</span>, error);
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Error generating presigned URL"</span> });
  }
});

<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>;
app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running on port <span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<h3 id="heading-step-3-using-the-pre-signed-url-in-the-client">Step 3: Using the Pre-signed URL in the Client</h3>
<p>Once the pre-signed URL is generated, the client can use it to upload the file directly to S3. Here’s an example of how you can use the pre-signed URL in a frontend application:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">uploadFile</span>(<span class="hljs-params">file</span>) </span>{

  <span class="hljs-keyword">const</span> fileName = file.name;
  <span class="hljs-keyword">const</span> fileType = file.type;

  <span class="hljs-comment">// Request the pre-signed URL from the server</span>
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`/generate-presigned-url?fileName=<span class="hljs-subst">${fileName}</span>&amp;fileType=<span class="hljs-subst">${fileType}</span>`</span>);
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();

  <span class="hljs-comment">// Use the pre-signed URL to upload the file to S3</span>
  <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> fetch(data.url, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'PUT'</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Content-Type'</span>: fileType,
    },
    <span class="hljs-attr">body</span>: file,
  });

  <span class="hljs-keyword">if</span> (result.ok) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'File uploaded successfully'</span>);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'File upload failed'</span>);
  }
}
</code></pre>
<p>Now, you can see that the file upload process is entirely <strong>client-side</strong>, meaning there’s no heavy load on the server for handling file uploads. This makes the system <strong>highly scalable</strong>, as the server’s responsibility is limited to generating pre-signed URLs. The actual file transfer happens directly between the client and Amazon S3.</p>
<p>Additionally, the pre-signed URL is <strong>secure</strong>, as the server authenticates the request and only generates URLs with limited, time-bound access to the files, ensuring security without exposing sensitive AWS credentials.</p>
<h2 id="heading-building-scalable-systems-with-pre-signed-urls">Building Scalable Systems with Pre-signed URLs</h2>
<p>Pre-signed URLs are a powerful tool when it comes to building <strong>scalable file upload systems</strong>. Here’s why:</p>
<ol>
<li><p><strong>Load Offloading</strong>: By bypassing the backend server, you offload the load of handling large files directly to Amazon S3, which is built for such tasks.</p>
</li>
<li><p><strong>Horizontal Scaling</strong>: Since your backend no longer handles the file upload process, it can scale horizontally to handle other tasks, like processing business logic, without being tied down by file transfers.</p>
</li>
<li><p><strong>Reduced Latency</strong>: Direct upload to S3 minimizes the round-trip time for uploading files, improving user experience.</p>
</li>
<li><p><strong>Cost Efficiency</strong>: Offloading file uploads to S3 reduces the need for powerful, resource-intensive backend servers, which can save infrastructure costs.</p>
</li>
</ol>
<h2 id="heading-security-considerations">Security Considerations</h2>
<p>Pre-signed URLs are a great way to securely upload files directly to S3, but there are a few things to keep in mind:</p>
<ul>
<li><p><strong>Expiration</strong>: Always set a reasonable expiration time for pre-signed URLs to limit their window of usage.</p>
</li>
<li><p><strong>File Validation</strong>: You should still validate the file type and size on the backend when generating the pre-signed URL to avoid uploading malicious or oversized files.</p>
</li>
<li><p><strong>Bucket Policies</strong>: Use S3 bucket policies to restrict access and control who can generate pre-signed URLs.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Amazon S3 pre-signed URLs are a highly effective way to manage file uploads in a scalable, secure, and efficient manner. By allowing users to upload files directly to S3, you reduce the load on your servers, improve performance, and enable your application to scale more easily.</p>
<p>Using pre-signed URLs is simple to implement with Node.js and AWS SDK, and they bring immense benefits, particularly for applications with heavy file uploads.</p>
<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Scaling Backend Servers with Messaging Queues: A Deep Dive Using BullMQ]]></title><description><![CDATA[Scaling backend infrastructure is one of the most critical steps in handling growing traffic and ensuring smooth operation under heavy loads. As systems grow, a single server processing all the tasks synchronously can become a bottleneck. This is whe...]]></description><link>https://blogs.shivangyadav.com/scaling-backend-servers-with-messaging-queues-a-deep-dive-using-bullmq</link><guid isPermaLink="true">https://blogs.shivangyadav.com/scaling-backend-servers-with-messaging-queues-a-deep-dive-using-bullmq</guid><category><![CDATA[backend]]></category><category><![CDATA[Redis]]></category><category><![CDATA[message queue]]></category><category><![CDATA[software development]]></category><category><![CDATA[bullmq]]></category><category><![CDATA[scalability]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Sat, 12 Oct 2024 05:47:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728711473832/4cb981dd-3bbb-414c-a3b9-dabdf798b807.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Scaling backend infrastructure is one of the most critical steps in handling growing traffic and ensuring smooth operation under heavy loads. As systems grow, a single server processing all the tasks synchronously can become a bottleneck. This is where messaging queue systems like BullMQ come into play. By offloading tasks and distributing them across worker processes, you can make your application scalable, reliable, and fault-tolerant.</p>
<h3 id="heading-1-why-messaging-queues-are-essential-for-backend-scalability"><strong>1. Why Messaging Queues Are Essential for Backend Scalability</strong></h3>
<p>In a typical backend system, certain operations—like sending emails, processing large data files, handling third-party API calls—can take significant time. If these operations are performed synchronously within the main server, they block other tasks, causing delays and reducing system throughput.</p>
<p><strong>Key problems without queues</strong>:</p>
<ul>
<li><p><strong>Synchronous processing</strong>: Every request waits until the operation is completed, slowing down response time.</p>
</li>
<li><p><strong>Resource overuse</strong>: Tasks like video processing or data-intensive computations consume CPU/memory, reducing the capacity to handle incoming requests.</p>
</li>
<li><p><strong>No fault tolerance</strong>: If a task fails, the entire request might need to be retried, leading to inefficiencies.</p>
</li>
</ul>
<p><strong>Messaging queues</strong> solve these problems by enabling asynchronous task processing:</p>
<ul>
<li><p><strong>Decoupling</strong>: The main server can offload long-running tasks to a queue and focus on handling incoming requests.</p>
</li>
<li><p><strong>Resiliency</strong>: Queued tasks can be retried, delayed, and processed independently by worker processes.</p>
</li>
<li><p><strong>Scalability</strong>: You can add more workers to handle an increasing load without affecting the main application.</p>
</li>
</ul>
<h3 id="heading-2-how-messaging-queues-work"><strong>2. How Messaging Queues Work</strong></h3>
<p>Messaging queues introduce a <strong>producer-consumer</strong> model:</p>
<ul>
<li><p><strong>Producer</strong>: The part of the system that generates tasks (e.g., API request handler).</p>
</li>
<li><p><strong>Queue</strong>: A message broker that stores tasks until they are processed.</p>
</li>
<li><p><strong>Consumer</strong>: Worker processes that consume tasks from the queue and process them independently.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728713621193/6e51eab9-e87d-40bd-8ae3-26649c6f7692.png" alt class="image--center mx-auto" /></p>
<p><strong>BullMQ</strong>, a popular choice for Node.js, is built on top of Redis. It handles job queuing, retries, delays, and more. Let’s see how you can use BullMQ to implement a scalable architecture.</p>
<h3 id="heading-3-introducing-bullmq-concepts"><strong>3. Introducing BullMQ Concepts</strong></h3>
<p>Before we dive into the implementation, let’s familiarize ourselves with some key concepts and terms in BullMQ:</p>
<ol>
<li><p><strong>Queue</strong>: The queue is the central point of interaction. It is where jobs are added (by producers) and where workers (consumers) process these jobs.</p>
</li>
<li><p><strong>Job</strong>: A job is the actual unit of work added to the queue. It consists of:</p>
<ul>
<li><p><strong>Job Data</strong>: Custom data needed to process the job (e.g., email content, user details).</p>
</li>
<li><p><strong>Job Options</strong>: Metadata like retries, delays, priority, and timeout settings.</p>
</li>
</ul>
</li>
<li><p><strong>Worker</strong>: A worker is a process that consumes jobs from a queue and executes them. It is responsible for processing jobs asynchronously.</p>
</li>
<li><p><strong>Producer</strong>: Any part of your application that adds jobs to a queue. Typically, API requests or background tasks act as producers.</p>
</li>
<li><p><strong>Consumer</strong>: The worker that processes jobs from the queue.</p>
</li>
<li><p><strong>Job Lifecycle</strong>: Jobs in BullMQ go through various states like <strong>waiting</strong>, <strong>active</strong>, <strong>completed</strong>, <strong>failed</strong>, <strong>delayed</strong>, and more.</p>
</li>
<li><p><strong>Redis</strong>: BullMQ uses Redis as the message broker to persist job data, manage job states, and allow communication between producers and consumers.</p>
</li>
</ol>
<h3 id="heading-4-implementing-a-messaging-queue-system-with-bullmq"><strong>4. Implementing a Messaging Queue System with BullMQ</strong></h3>
<p>In this section, we'll build a task processing system using BullMQ to scale a Node.js backend.</p>
<h4 id="heading-step-1-install-bullmq-and-redis"><strong>Step 1: Install BullMQ and Redis</strong></h4>
<p>First, install BullMQ and Redis as dependencies in your project. Redis will act as the backend for our queue.</p>
<pre><code class="lang-bash">npm install bullmq redis
</code></pre>
<p>Ensure that Redis is installed and running on your system. You can install Redis using Docker:</p>
<pre><code class="lang-bash">docker run -d --name redis -p 6379:6379 redis
</code></pre>
<h4 id="heading-step-2-setting-up-the-queue"><strong>Step 2: Setting Up the Queue</strong></h4>
<p>Let’s create a queue for processing email notifications, a common use case in many applications.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Queue } <span class="hljs-keyword">from</span> <span class="hljs-string">'bullmq'</span>;
<span class="hljs-keyword">import</span> Redis <span class="hljs-keyword">from</span> <span class="hljs-string">'ioredis'</span>;

<span class="hljs-comment">// Set up a connection to Redis</span>
<span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">new</span> Redis();

<span class="hljs-comment">// Create a queue</span>
<span class="hljs-keyword">const</span> emailQueue = <span class="hljs-keyword">new</span> Queue(<span class="hljs-string">'emailQueue'</span>, { connection });

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> emailQueue;
</code></pre>
<p>In this setup, <code>emailQueue</code> is a queue that will handle email notification jobs.</p>
<h4 id="heading-step-3-adding-jobs-to-the-queue"><strong>Step 3: Adding Jobs to the Queue</strong></h4>
<p>When a new user signs up or an event triggers an email, instead of sending the email directly, we can offload the task to the <code>emailQueue</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// addJob.js</span>
<span class="hljs-keyword">import</span> emailQueue <span class="hljs-keyword">from</span> <span class="hljs-string">'./emailQueue'</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendEmailJob</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-keyword">await</span> emailQueue.add(<span class="hljs-string">'sendEmail'</span>, {
    <span class="hljs-attr">recipient</span>: data.email,
    <span class="hljs-attr">subject</span>: <span class="hljs-string">'Welcome to our platform'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-string">'Thanks for signing up!'</span>
  });
}

<span class="hljs-comment">// Usage in API endpoint</span>
app.post(<span class="hljs-string">'/signup'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> createUser(req.body);

  <span class="hljs-comment">// Add email sending task to the queue</span>
  <span class="hljs-keyword">await</span> sendEmailJob({ <span class="hljs-attr">email</span>: user.email });

  res.status(<span class="hljs-number">201</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'User created. Email will be sent shortly.'</span> });
});
</code></pre>
<p>Here, the user sign-up handler doesn’t wait for the email to be sent but offloads the task to the queue.</p>
<h4 id="heading-step-4-processing-the-queue-with-workers"><strong>Step 4: Processing the Queue with Workers</strong></h4>
<p>Now, we need a <strong>worker</strong> to consume tasks from the <code>emailQueue</code> and send the emails. Workers run independently of the main server and can be scaled horizontally to handle high volumes of tasks.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// emailWorker.js</span>
<span class="hljs-keyword">import</span> { Worker } <span class="hljs-keyword">from</span> <span class="hljs-string">'bullmq'</span>;
<span class="hljs-keyword">import</span> nodemailer <span class="hljs-keyword">from</span> <span class="hljs-string">'nodemailer'</span>;
<span class="hljs-keyword">import</span> Redis <span class="hljs-keyword">from</span> <span class="hljs-string">'ioredis'</span>;

<span class="hljs-comment">// Redis connection</span>
<span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">new</span> Redis();

<span class="hljs-comment">// Nodemailer transport for sending emails</span>
<span class="hljs-keyword">const</span> transporter = nodemailer.createTransport({
  <span class="hljs-attr">service</span>: <span class="hljs-string">'gmail'</span>,
  <span class="hljs-attr">auth</span>: {
    <span class="hljs-attr">user</span>: <span class="hljs-string">'your-email@gmail.com'</span>,
    <span class="hljs-attr">pass</span>: <span class="hljs-string">'your-password'</span>,
  },
});

<span class="hljs-comment">// Worker to process email jobs with retry logic</span>
<span class="hljs-keyword">const</span> emailWorker = <span class="hljs-keyword">new</span> Worker(<span class="hljs-string">'emailQueue'</span>, <span class="hljs-keyword">async</span> (job) =&gt; {
  <span class="hljs-keyword">const</span> { recipient, subject, body } = job.data;

  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Send email</span>
    <span class="hljs-keyword">await</span> transporter.sendMail({
      <span class="hljs-attr">from</span>: <span class="hljs-string">'"Your App" &lt;your-email@gmail.com&gt;'</span>,
      <span class="hljs-attr">to</span>: recipient,
      subject,
      <span class="hljs-attr">text</span>: body,
    });
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Email sent to <span class="hljs-subst">${recipient}</span>`</span>);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Failed to send email to <span class="hljs-subst">${recipient}</span>:`</span>, error.message);
    <span class="hljs-keyword">throw</span> error; <span class="hljs-comment">// This will trigger a retry if attempts are configured</span>
  }
}, {
  connection
});

<span class="hljs-comment">// Event listener for failed jobs</span>
emailWorker.on(<span class="hljs-string">'failed'</span>, <span class="hljs-function">(<span class="hljs-params">job, err</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Job failed <span class="hljs-subst">${job.id}</span> with error: <span class="hljs-subst">${err.message}</span>`</span>);
});
</code></pre>
<p>The worker listens to the queue, consumes jobs, and processes them asynchronously. If the email sending fails, BullMQ will retry the job based on the configuration.</p>
<h4 id="heading-step-5-scaling-the-workers"><strong>Step 5: Scaling the Workers</strong></h4>
<p>When traffic increases, a single worker might not be enough. You can scale your application by simply adding more workers:</p>
<pre><code class="lang-bash">node emailWorker.js
node emailWorker.js
node emailWorker.js
</code></pre>
<p>Each worker will fetch and process jobs concurrently, allowing your system to handle higher loads.</p>
<h3 id="heading-job-options-in-bullmq"><strong>Job Options in BullMQ</strong></h3>
<p>While adding jobs to a queue, you can pass <strong>job options</strong> to control how the job behaves during its lifecycle. These options allow you to fine-tune when and how jobs are processed, retried, delayed, or scheduled.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> queue.add(jobName, data, options);
</code></pre>
<p>Some commonly used job options include:</p>
<ol>
<li><p><strong>delay</strong>: Delay the job by <code>x</code> milliseconds before processing. For example, delay an email notification to be sent 1 minute after a user registers.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">await</span> queue.add(<span class="hljs-string">'sendEmail'</span>, jobData, { <span class="hljs-attr">delay</span>: <span class="hljs-number">60000</span> }); <span class="hljs-comment">// 60 seconds delay</span>
</code></pre>
</li>
<li><p><strong>attempts</strong>: The number of times to retry the job if it fails. For example, retry sending an email up to 3 times.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">await</span> queue.add(<span class="hljs-string">'sendEmail'</span>, jobData, { <span class="hljs-attr">attempts</span>: <span class="hljs-number">3</span> });
</code></pre>
</li>
<li><p><strong>backoff</strong>: Set a backoff strategy for job retries. This can be either fixed or exponential, specifying the delay between retry attempts.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">await</span> queue.add(<span class="hljs-string">'sendEmail'</span>, jobData, { <span class="hljs-attr">attempts</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">backoff</span>: { <span class="hljs-attr">type</span>: <span class="hljs-string">'exponential'</span>, <span class="hljs-attr">delay</span>: <span class="hljs-number">5000</span> } });
</code></pre>
</li>
<li><p><strong>lifo</strong>: Use a LIFO (Last In, First Out) processing order instead of the default FIFO (First In, First Out). Newer jobs will be processed before older ones if this is set to true.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">await</span> queue.add(<span class="hljs-string">'processData'</span>, jobData, { <span class="hljs-attr">lifo</span>: <span class="hljs-literal">true</span> });
</code></pre>
</li>
<li><p><strong>priority</strong>: Jobs with higher numeric priority values are processed before those with lower priority. Use this to prioritize critical tasks.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">await</span> queue.add(<span class="hljs-string">'criticalTask'</span>, jobData, { <span class="hljs-attr">priority</span>: <span class="hljs-number">1</span> });
</code></pre>
</li>
<li><p><strong>repeat</strong>: You can configure jobs to run on a recurring schedule (like cron jobs) using this option.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">await</span> queue.add(<span class="hljs-string">'dailyReport'</span>, jobData, { <span class="hljs-attr">repeat</span>: { <span class="hljs-attr">cron</span>: <span class="hljs-string">'0 0 * * *'</span> } }); <span class="hljs-comment">// Runs daily at midnight</span>
</code></pre>
</li>
</ol>
<h3 id="heading-common-queue-events-in-bullmq"><strong>Common Queue Events in BullMQ</strong></h3>
<p>BullMQ provides a rich set of events that allow you to track the state and progress of jobs. These events are especially useful for logging, debugging, and monitoring the system. Some of the key events include:</p>
<ol>
<li><p><strong>waiting</strong>: This event is emitted when a job is added to the queue and is waiting to be processed.</p>
</li>
<li><p><strong>active</strong>: Fired when a job has been started by a worker and is actively being processed.</p>
</li>
<li><p><strong>completed</strong>: Emitted when a job is processed successfully by a worker.</p>
</li>
<li><p><strong>failed</strong>: This event is fired when a job fails due to an error during processing.</p>
</li>
<li><p><strong>paused</strong>: Triggered when a queue is paused, meaning no new jobs will be processed.</p>
</li>
<li><p><strong>resumed</strong>: Fired when a paused queue is resumed.</p>
</li>
<li><p><strong>cleaned</strong>: This event is triggered when jobs are cleaned up (e.g., old completed jobs are removed due to storage limits).</p>
</li>
</ol>
<h3 id="heading-5-using-redisinsight-for-monitoring-bullmq-jobs"><strong>5. Using RedisInsight for Monitoring BullMQ Jobs</strong></h3>
<p>When dealing with multiple queues and jobs, having visibility into the state and performance of your queues is critical for debugging and scaling. <strong>RedisInsight</strong> is a visual tool that lets you monitor Redis instances and gain insights into BullMQ queues and jobs.</p>
<h4 id="heading-step-1-install-redisinsight"><strong>Step 1: Install RedisInsight</strong></h4>
<p>RedisInsight can be downloaded from the official Redis website or installed using Docker:</p>
<pre><code class="lang-bash">docker run -d --name redisinsight -p 5540:5540 redis/redisinsight:latest
</code></pre>
<h4 id="heading-step-2-connect-redisinsight-to-your-redis-server"><strong>Step 2: Connect RedisInsight to Your Redis Server</strong></h4>
<p>Once RedisInsight is running, navigate to <a target="_blank" href="http://localhost:8001"><code>http://localhost:5540</code></a> and connect it to your local or remote Redis instance by providing the Redis host and port (e.g., <a target="_blank" href="http://localhost:6379"><code>localhost:6379</code></a>).</p>
<h4 id="heading-step-3-monitoring-bullmq-queues"><strong>Step 3: Monitoring BullMQ Queues</strong></h4>
<p>Once connected, RedisInsight provides detailed insights into BullMQ queues:</p>
<ul>
<li><p><strong>Queue Statistics</strong>: Shows the number of jobs in various states (waiting, active, completed, failed, delayed).</p>
</li>
<li><p><strong>Job Details</strong>: Allows you to inspect individual jobs, view their data, and see the exact error messages if they failed.</p>
</li>
<li><p><strong>Job Performance</strong>: Monitor job processing times and identify bottlenecks.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728709968939/01bbe537-6350-4178-8bb9-c1c91bfddd4a.png" alt class="image--center mx-auto" /></p>
<p>RedisInsight makes it easy to:</p>
<ul>
<li><p>Monitor job lifecycles in real time.</p>
</li>
<li><p>Debug failed jobs by inspecting their data and error stack.</p>
</li>
<li><p>Track delayed jobs and their execution schedules.</p>
</li>
<li><p>Optimize queue performance based on processing metrics.</p>
</li>
</ul>
<p>This visual interface becomes invaluable for scaling, debugging, and optimizing job queues in production environments.</p>
<h3 id="heading-6-where-and-when-to-use-queues-in-your-backend"><strong>6. Where and When to Use Queues in Your Backend</strong></h3>
<p>You can use messaging queues for various tasks that don't need to be processed synchronously, including:</p>
<ul>
<li><p><strong>Email notifications</strong>: Offload email sending tasks to avoid blocking user-facing endpoints.</p>
</li>
<li><p><strong>File processing</strong>: Large video, image, or document processing can be queued and handled by workers.</p>
</li>
<li><p><strong>Data aggregation</strong>: Complex calculations (e.g., analytics) can be performed asynchronously without affecting user experience.</p>
</li>
<li><p><strong>API requests to third parties</strong>: If you're integrating with external services (e.g., payment gateways), use queues to handle retries, failures, and timeouts more gracefully.</p>
</li>
<li><p><strong>Scheduled tasks</strong>: BullMQ supports delayed tasks, so you can schedule jobs to be processed in the future (e.g., sending a reminder email after 24 hours).</p>
</li>
</ul>
<h3 id="heading-7-best-practices-for-scaling-with-bullmq"><strong>7. Best Practices for Scaling with BullMQ</strong></h3>
<p>To ensure your system scales efficiently with BullMQ:</p>
<ol>
<li><p><strong>Monitor queues</strong>: Use BullMQ’s built-in UI to track job status, retry counts, and failures.</p>
</li>
<li><p><strong>Retry logic</strong>: Configure retry strategies for handling intermittent failures (e.g., network issues).</p>
</li>
<li><p><strong>Graceful shutdown</strong>: Ensure your workers handle termination signals (SIGTERM) and complete ongoing jobs before shutting down.</p>
<pre><code class="lang-bash"> process.on(<span class="hljs-string">'SIGTERM'</span>, () =&gt; {
   emailWorker.close().<span class="hljs-keyword">then</span>(() =&gt; {
     console.log(<span class="hljs-string">'Worker shut down gracefully'</span>);
     process.exit(0);
   });
 });
</code></pre>
</li>
<li><p><strong>Scaling</strong>: Horizontally scale workers to meet traffic demands. Redis as the backend allows for distributed processing across multiple machines.</p>
</li>
<li><p><strong>Use Redis clusters</strong>: For larger applications, consider using Redis clusters for high availability and fault tolerance.</p>
</li>
</ol>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>By integrating messaging queues like BullMQ into your backend, you can significantly improve scalability, reliability, and efficiency. Offloading long-running tasks to worker processes allows your application to handle more traffic and stay responsive even under heavy load.</p>
<p>With BullMQ, implementing a robust queue system in Node.js is straightforward. You can process tasks asynchronously, manage retries, and scale your system by adding more workers as needed.</p>
]]></content:encoded></item><item><title><![CDATA[Setting Up Node.js CI/CD on EC2 with GitHub Actions and Nginx]]></title><description><![CDATA[Continuous Integration and Continuous Deployment (CI/CD) helps automate the process of testing and deploying code to production. In this blog, we’ll walk through setting up a CI/CD pipeline for a Node.js application using GitHub Actions and deploying...]]></description><link>https://blogs.shivangyadav.com/setting-up-nodejs-cicd-on-ec2-with-github-actions-and-nginx</link><guid isPermaLink="true">https://blogs.shivangyadav.com/setting-up-nodejs-cicd-on-ec2-with-github-actions-and-nginx</guid><category><![CDATA[AWS]]></category><category><![CDATA[ec2]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Thu, 10 Oct 2024 21:02:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728594077294/3aeef911-f6c4-4491-b54e-c2d74b70c9c6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Continuous Integration and Continuous Deployment (CI/CD) helps automate the process of testing and deploying code to production. In this blog, we’ll walk through setting up a <strong>CI/CD pipeline for a Node.js</strong> application using <strong>GitHub Actions</strong> and deploying it to an <strong>AWS EC2 instance</strong>.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before diving into the setup, ensure you have the following:</p>
<ol>
<li><p><strong>AWS Account</strong>: You will need access to AWS with permission to create and manage EC2 instances.</p>
</li>
<li><p><strong>Node.js Application</strong>: We will assume you have a Node.js project already set up.</p>
</li>
<li><p><strong>GitHub Repository</strong>: The Node.js application should be in a GitHub repository.</p>
</li>
</ol>
<h2 id="heading-step-1-launch-an-ec2-instance">Step 1: Launch an EC2 Instance</h2>
<p>To begin, we’ll launch an EC2 instance that will serve as the deployment target for our Node.js application.</p>
<ol>
<li><p><strong>Log in to your AWS Console</strong> and go to the <strong>EC2 Dashboard</strong>.</p>
</li>
<li><p>Click on <strong>Launch Instance</strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728569783817/35d47033-6cb3-490d-9086-fbd9c603f550.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Choose an <strong>Amazon Machine Image (AMI)</strong>. Select <strong>Ubuntu</strong> or <strong>Amazon Linux</strong> for Node.js applications.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728569843192/522d932e-140f-4b3b-89ff-8c5478231a8a.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Choose the <strong>Instance Type</strong>. For a basic application, the free-tier eligible <strong>t2.micro</strong> is sufficient and setup a keypair</p>
</li>
<li><p><strong>Key Pair</strong>: Create a new key pair or use an existing one. Make sure to download the private key (<code>.pem</code> file), as you will need it to connect to the instance later.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728569907522/d266ce5e-41a8-4d15-84f5-a0ebcdd079ca.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Configure Instance Details</strong>. In most cases, the default settings are fine.</p>
</li>
<li><p><strong>Add Storage</strong>. Use the default storage allocation (8 GB is typically enough for a small Node.js app).</p>
</li>
<li><p><strong>Configure Security Group</strong>:</p>
<ul>
<li><p>Create a new security group and add the following rules:</p>
<ul>
<li><p><strong>SSH (port 22)</strong>: Allow your IP address to connect via SSH.</p>
</li>
<li><p><strong>HTTP (port 80)</strong>: Allow access to your application.</p>
</li>
</ul>
</li>
<li><p>You can also add <strong>HTTPS (port 443)</strong> if you plan to use SSL.</p>
</li>
</ul>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728570118482/7e436041-5e1d-4306-8327-b9996133709a.png" alt class="image--center mx-auto" /></p>
<p> <strong>Launch the Instance</strong>.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728570081375/cb15e1e7-d2b9-48fb-8890-a0dee7dbb09a.png" alt class="image--center mx-auto" /></p>
<p>After the instance is launched, make a note of its <strong>Public IP address</strong> or <strong>Public DNS</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728570211073/972b789c-f7b3-491a-8d66-39e831a3c435.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-step-2-install-nodejs-and-set-up-the-environment-on-ec2">Step 2: Install Node.js and Set Up the Environment on EC2</h2>
<p>Once the EC2 instance is running, connect to it using SSH and set up Node.js.</p>
<ol>
<li><p><strong>Connect to the EC2 Instance</strong>: Open a terminal and run the following command to SSH into your instance:</p>
<pre><code class="lang-bash"> ssh -i /path/to/your-key.pem ubuntu@your-ec2-public-ip
</code></pre>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728575667514/f758ce4f-340a-4af0-8129-0df52b705e7a.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Update the Package List</strong>:</p>
<pre><code class="lang-bash"> sudo apt update
</code></pre>
</li>
<li><p><strong>Install Node.js</strong>: You can install the latest stable version of Node.js</p>
<pre><code class="lang-bash"> sudo apt-get install -y nodejs
</code></pre>
<p> This installs the latest LTS (Long-Term Support) version of Node.js.</p>
</li>
<li><p><strong>Install Nginx:</strong> We’ll install <strong>Nginx</strong>, which we’ll use as a reverse proxy for our Node.js application.</p>
<ul>
<li><p>Install Nginx:</p>
<pre><code class="lang-bash">  sudo apt-get install nginx
</code></pre>
</li>
<li><p>Start Nginx and enable it to run on startup:</p>
<pre><code class="lang-bash">  sudo systemctl start nginx
  sudo systemctl <span class="hljs-built_in">enable</span> nginx
</code></pre>
</li>
<li><p>Check the status of Nginx to ensure it is running:</p>
<pre><code class="lang-bash">  sudo systemctl status nginx
</code></pre>
</li>
</ul>
</li>
</ol>
<p>    At this point, Nginx should be running and accessible via the public IP of your EC2 instance. Open a browser and navigate to <a target="_blank" href="http://your-ec2-public-ip"><code>http://your-ec2-public-ip</code></a>, and you should see the default Nginx welcome page.</p>
<ol start="5">
<li><p><strong>Install PM2</strong>: PM2 is a process manager for Node.js applications. It ensures that your application runs in the background and automatically restarts if it crashes.</p>
<pre><code class="lang-bash"> sudo npm install -g pm2
</code></pre>
</li>
</ol>
<h2 id="heading-step-3-set-up-github-actions-for-cicd">Step 3: Set Up GitHub Actions for CI/CD</h2>
<p>Now, we’ll set up GitHub Actions to automatically deploy your Node.js application to the EC2 instance whenever you push changes to the <code>main</code> branch.</p>
<ol>
<li><p><strong>Create a Self-Hosted Runner in GitHub:</strong></p>
<ul>
<li><p>Go to your GitHub repository, click on <strong>Settings</strong> &gt; <strong>Actions</strong> &gt; <strong>Runners</strong>, and click on <strong>New self-hosted runner</strong> button.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728589246094/d9dc768c-7209-4998-be19-a1912831ef49.png" alt class="image--center mx-auto" /></p>
<p>  Select the OS type for your runner (Linux for an Ubuntu EC2 instance).</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728590834989/40a66242-4e69-4bc7-b99b-5c459c37c154.png" alt class="image--center mx-auto" /></p>
<p>  GitHub will show a set of instructions and a registration token, which you’ll use to set up the runner on your EC2 instance. Run those commands one by one on your EC2 instance.</p>
</li>
<li><p>Once you’ve completed the runner registration steps, you can install the runner as a systemd service.</p>
<ul>
<li><p><strong>Install the service</strong> by running the following command in your runner directory:</p>
<pre><code class="lang-bash">  sudo ./svc.sh install
</code></pre>
<p>  This command sets up the runner as a system service, so you don’t need to manually start it every time the EC2 instance is restarted or after logging out.</p>
</li>
<li><p><strong>Start the Runner Service</strong></p>
<pre><code class="lang-bash">  sudo ./svc.sh start
</code></pre>
<p>  This will start the self-hosted runner as a background service, and it will be ready to accept and execute workflows from your GitHub repository.</p>
</li>
<li><p><strong>Check the Service Status</strong></p>
<pre><code class="lang-bash">  sudo ./svc.sh status
</code></pre>
<p>  This command will show you whether the runner service is active. The output should display something like:</p>
<pre><code class="lang-bash">  ● actions.runner.your-repo.service - GitHub Actions Runner (your-repo)
     Loaded: loaded (/etc/systemd/system/actions.runner.your-repo.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2024-10-10 14:00:00 UTC; 5min ago
     ...
</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Create the GitHub Actions Workflow</strong>: Inside your Node.js project, create a directory <code>.github/workflows/</code> and add a file named <code>deploy.yml</code>.</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">name:</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">CI/CD</span>

 <span class="hljs-comment"># Trigger the workflow on pushes to the "main" branch</span>
 <span class="hljs-attr">on:</span>
   <span class="hljs-attr">push:</span>
     <span class="hljs-attr">branches:</span> [ <span class="hljs-string">"main"</span> ]

 <span class="hljs-attr">jobs:</span>
   <span class="hljs-attr">build:</span>

     <span class="hljs-comment"># This job runs on a self-hosted runner, in this case, your EC2 instance</span>
     <span class="hljs-attr">runs-on:</span> <span class="hljs-string">self-hosted</span>

     <span class="hljs-attr">steps:</span>
     <span class="hljs-comment"># Step 1: Checkout the latest code from the GitHub repository</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

     <span class="hljs-comment"># Step 2: Setup Node.js environment using the specified version (e.g., 20.x)</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-number">20.</span><span class="hljs-string">x</span>
       <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v3</span>
       <span class="hljs-attr">with:</span>
         <span class="hljs-attr">node-version:</span> <span class="hljs-string">'20.x'</span>  <span class="hljs-comment"># Specify Node.js version</span>
         <span class="hljs-attr">cache:</span> <span class="hljs-string">'npm'</span>          

     <span class="hljs-comment"># Step 3: Install dependencies</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>

     <span class="hljs-comment"># Step 4: Set up the environment variables by creating a .env file</span>
     <span class="hljs-comment">#         Secrets stored in GitHub will be used in the production environment</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">|
         touch .env
         echo "${{ secrets.PROD_ENV }}" &gt; .env
</span>
     <span class="hljs-comment"># Step 5: Build the project (only if a build script is present in package.json)</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span> <span class="hljs-string">--if-present</span>

     <span class="hljs-comment"># Step 6: This step you have to update after setting up the nodejs application on ec2 instance</span>
     <span class="hljs-comment">#  Restart the Node.js app using PM2 for zero-downtime deployment</span>
     <span class="hljs-comment"># - run: pm2 restart node-app</span>
</code></pre>
<p> <strong>Workflow Overview</strong></p>
<ul>
<li><p><strong>Trigger</strong>: The workflow is triggered every time code is pushed to the <code>main</code> branch of your GitHub repository.</p>
</li>
<li><p><strong>Runner</strong>: The job is executed on a <strong>self-hosted runner</strong>, which is typically an EC2 instance or any server you control. This is where the application will be deployed.</p>
</li>
</ul>
</li>
<li><p><strong>Verify Workflow Execution:</strong> After pushing your changes to the <code>main</code> branch and running the GitHub Actions workflow, your code should be deployed to the EC2 instance. GitHub Actions will place the code inside the <code>_work</code> folder in your runner directory.<br /> To access this folder:</p>
<ul>
<li><p><strong>SSH into your EC2 instance</strong>:</p>
<pre><code class="lang-bash">  ssh -i /path/to/your/key.pem ubuntu@your-ec2-ip
</code></pre>
</li>
<li><p><strong>Navigate to the GitHub Actions runner directory</strong>:</p>
<p>  By default, the runner's working directory will be something like:</p>
<pre><code class="lang-bash">  <span class="hljs-built_in">cd</span> ~/actions-runner/_work/&lt;your-repo-name&gt;/&lt;your-repo-name&gt;
</code></pre>
<p>  In this directory, you'll find the checked-out code from your repository after the GitHub Actions workflow runs.</p>
</li>
</ul>
</li>
<li><p><strong>Setup Nginx as a Reverse Proxy:</strong> Next, you need to set up <strong>Nginx</strong> to act as a reverse proxy for your Node.js application. This ensures that requests to your EC2 instance (e.g., through its public IP or domain) are routed to your Node.js app.</p>
<ul>
<li><p><strong>Configure Nginx</strong> for your Node.js app:</p>
<p>  Open the Nginx configuration file for editing:</p>
<pre><code class="lang-bash">  sudo vim /etc/nginx/sites-available/default
</code></pre>
<p>  Replace the contents with the following Nginx configuration, adjusting it for your app’s port (usually <code>3000</code> or another port if configured):</p>
<pre><code class="lang-bash">  server {
      listen 80;

     server_name _;

     <span class="hljs-comment"># Add this part to your file</span>
      location /api {
          rewrite ^\/api\/(.*)$ /api/<span class="hljs-variable">$1</span> <span class="hljs-built_in">break</span>;
          proxy_pass http://localhost:4000; <span class="hljs-comment">#assuming your nodejs appliction running on port 4000</span>
          proxy_set_header Host <span class="hljs-variable">$host</span>;
          proxy_set_header X-Real-IP <span class="hljs-variable">$remote_addr</span>;
          proxy_set_header X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
          }
  }
</code></pre>
<p>  The configuration specifies that any request path starting with <code>/api</code> will be forwarded to a <strong>backend Node.js application</strong> running on <a target="_blank" href="http://localhost:4000"><code>localhost:4000</code></a></p>
</li>
<li><p><strong>Test the Nginx configuration</strong>:</p>
<p>  Test that your Nginx configuration is valid:</p>
<pre><code class="lang-bash">  sudo nginx -t
</code></pre>
<p>  If everything is correct, you should see a message like <code>syntax is ok</code>.</p>
</li>
<li><p><strong>Restart Nginx</strong> to apply the changes:</p>
<pre><code class="lang-bash">  sudo systemctl restart nginx
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Start the Node.js App with PM2:</strong> To ensure your Node.js application is running, you’ll use <strong>PM2</strong> to manage the process.</p>
<ul>
<li><p><strong>Start the Node.js application</strong> using PM2:</p>
<p>  In the same directory where your application is located (inside <code>_work/&lt;your-repo-name&gt;</code>), start your app with PM2:</p>
<pre><code class="lang-bash">  pm2 start server.js --name node-app  <span class="hljs-comment"># Adjust `server.js` to your app's entry file</span>
</code></pre>
<p>  This command will run the app in the background and associate it with the name <code>node-app</code>.</p>
</li>
<li><p><strong>Check the status of the app</strong>:</p>
<p>  Use the following command to ensure that your app is running:</p>
<pre><code class="lang-bash">  pm2 status
</code></pre>
<p>  You should see your application listed with the status <code>online</code>.</p>
</li>
<li><p><strong>Enable PM2 startup</strong> to ensure it starts on boot:</p>
<p>  Run the following command to configure PM2 to start your app automatically after a system reboot:</p>
<pre><code class="lang-bash">  pm2 startup
</code></pre>
<p>  Follow the on-screen instructions to complete the setup.</p>
</li>
<li><p><strong>Save the PM2 process list</strong>:</p>
<p>  To save the current PM2 process list and restore it on reboot, use:</p>
<pre><code class="lang-bash">  pm2 save
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Verify the Setup:</strong> Now that Nginx is configured as a reverse proxy and your Node.js app is running under PM2:</p>
<ol>
<li><p><strong>Visit your server's public IP or domain name</strong> in the browser:</p>
<pre><code class="lang-plaintext"> http://your_domain_or_public_ip/api
</code></pre>
<p> You should see your Node.js application responding through Nginx.</p>
</li>
<li><p>If everything is set up correctly, your app should now be accessible publicly, with Nginx forwarding incoming requests to your Node.js application.</p>
</li>
<li><p>Now update your github workflow file step 6.</p>
<pre><code class="lang-yaml">  <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">pm2</span> <span class="hljs-string">restart</span> <span class="hljs-string">node-app</span>
</code></pre>
</li>
</ol>
</li>
</ol>
<h2 id="heading-step-4-push-changes-to-github">Step 4: Push Changes to GitHub</h2>
<p>Now, whenever you push changes to the <code>main</code> branch, GitHub Actions will:</p>
<ul>
<li><p>Run the build and tests.</p>
</li>
<li><p>If successful, deploy the updated code to your EC2 instance.</p>
</li>
</ul>
<p>Try making a small change in your repository and pushing it:</p>
<pre><code class="lang-bash">git add .
git commit -m <span class="hljs-string">"Test CI/CD deployment"</span>
git push origin main
</code></pre>
<p>You should see the GitHub Actions workflow running in the <strong>Actions</strong> tab of your repository. After it completes, the updated code will be deployed to your EC2 instance.</p>
<hr />
<h2 id="heading-step-5-verify-the-application">Step 5: Verify the Application</h2>
<p>Finally, check that your Node.js application is running on the EC2 instance:</p>
<ol>
<li><p>Access the public IP or DNS of your EC2 instance in a web browser:</p>
<pre><code class="lang-bash"> http://your-ec2-public-ip/api
</code></pre>
</li>
<li><p>You should see your Node.js application running!</p>
</li>
</ol>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>You’ve now set up a CI/CD pipeline for your Node.js application using GitHub Actions and deployed it to an AWS EC2 instance. This automated process ensures that your code is tested and deployed seamlessly with every push to the main branch.</p>
<p>Feel free to expand this workflow by adding additional stages like database migrations, performance monitoring, or scaling your EC2 instances.</p>
]]></content:encoded></item><item><title><![CDATA[React Server Components]]></title><description><![CDATA[React Server Components (RSC) are a new addition to the React ecosystem that allow components to be rendered exclusively on the server. Unlike traditional React components that run entirely on the client. This allows us to do things like write databa...]]></description><link>https://blogs.shivangyadav.com/react-server-components</link><guid isPermaLink="true">https://blogs.shivangyadav.com/react-server-components</guid><category><![CDATA[React]]></category><category><![CDATA[software development]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Thu, 10 Oct 2024 14:10:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728569336249/cbd49df7-6e6b-4bbd-b110-b069e7d94989.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>React Server Components (RSC) are a new addition to the React ecosystem that allow components to be rendered exclusively on the server. Unlike traditional React components that run entirely on the client. This allows us to do things like write database queries right inside our React components!  </p>
<p>In this new approach,  <strong>all components are assumed to be Server Components by default</strong> and the “traditional” React components we're familiar with are called Client Components. Despite the name, 𝘊𝘭𝘪𝘦𝘯𝘵 𝘊𝘰𝘮𝘱𝘰𝘯𝘦𝘯𝘵𝘴 𝘤𝘢𝘯 𝘳𝘦𝘯𝘥𝘦𝘳 𝘰𝘯 𝘣𝘰𝘵𝘩 𝘵𝘩𝘦 𝘤𝘭𝘪𝘦𝘯𝘵 𝘢𝘯𝘥 𝘵𝘩𝘦 𝘴𝘦𝘳𝘷𝘦𝘳. However, 𝘚𝘦𝘳𝘷𝘦𝘳 𝘊𝘰𝘮𝘱𝘰𝘯𝘦𝘯𝘵𝘴 𝘳𝘶𝘯 𝘦𝘹𝘤𝘭𝘶𝘴𝘪𝘷𝘦𝘭𝘺 𝘰𝘯 𝘵𝘩𝘦 𝘴𝘦𝘳𝘷𝘦𝘳.  </p>
<p>It’s important to understand that: <strong><em>Server components never re-render</em></strong>. They only render once on the server to generate the UI, and the rendered output is then sent to the client where it remains static. Since Server Components cannot re-render, they do not support state or effects. State requires the ability to change, and effects typically run after rendering on the client—both of which are incompatible with Server Components that do not execute client-side.<br />If you need a component to manage state or run effects, you can convert it into a Client Component by adding 'use client' at the top of the component file.</p>
<pre><code class="lang-javascript"><span class="hljs-string">'use client'</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [count, setCount] = React.useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setCount(count + 1)}&gt;
      Current value: {count}
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Counter;
</code></pre>
<h2 id="heading-react-server-components-vs-server-side-rendering-ssr">React Server Components vs. Server-Side Rendering (SSR)</h2>
<p>Let us understand server side rendering first-&gt;  </p>
<p>As we navigate the web, we often hear terms like "server-side rendering" (SSR) and "client-side rendering" (CSR) - but what do these actually mean for your browsing experience? Let's break it down into simple words!</p>
<h3 id="heading-client-side-rendering-csr">Client-Side Rendering (CSR):</h3>
<p>With CSR, when you visit a website, your browser receives a minimal page template from the server. Then, your browser gets to work, downloading javascript bundle, fetching content and filling out the details. The problem with this approach is that it takes time to do all of that work. And while it's all happening, the user is staring at a blank white screen.</p>
<h3 id="heading-server-side-rendering-ssr">Server-Side Rendering (SSR):</h3>
<p>Server side rendering was designed to improve the problem we faced in CSR.<br />With SSR, when you visit a website, the server already does most of the heavy lifting. Instead of sending an empty HTML file, server prepares the full page on its side before sending it to your browser. This means you can see and interact with the complete page almost immediately after it loads.</p>
<p><strong>SSR has several Advantages</strong></p>
<ol>
<li><p>Faster initial page load for users</p>
</li>
<li><p>Better SEO as search engines can crawl the complete page.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716371823538/25f75f7d-ce7d-49d1-bff4-d2575cc3192c.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-dont-get-confused-between-rsc-and-ssr">Don't get confused between RSC and SSR!</h3>
<p>While both involve server-side rendering, RSCs are a more advanced and integrated solution within React itself. SSR typically involves rendering the initial HTML on the server and then hydrating it on the client. RSCs builds on top of that, allowing us to omit certain components from the client-side JavaScript bundle, ensuring they only run on the server. This reduces the JavaScript bundle size on the client side, making the page interactive faster.</p>
<h3 id="heading-you-might-be-wondering-how-can-we-use-these-react-server-components">You might be wondering, how can we use these React Server Components?</h3>
<p>As of now, React Server Components (RSCs) can only be used in 𝘕𝘦𝘹𝘵.𝘫𝘴 13.4+ through their brand-new re-architected “𝘈𝘱𝘱 𝘙𝘰𝘶𝘵𝘦𝘳.” Next.js is the first framework to implement RSCs and is currently the only framework that fully supports them.</p>
<h3 id="heading-advantages">Advantages:</h3>
<p>RSCs offer several advantages. The most obvious benefit is performance. Since Server Components are not included in the JavaScript bundles, they reduce both the amount of JavaScript that needs to be downloaded and the number of components requiring hydration.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716372010144/f77370bb-72c7-44bf-bebb-c2e0f1ebdd2a.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Docker: Transforming Software Deployment]]></title><description><![CDATA[Docker is a platform designed to make it easier to develop, deploy, and run applications. It provides the ability to package and run an application in a completely isolated environment called a containers.
Containers allow a developer to package up a...]]></description><link>https://blogs.shivangyadav.com/docker-transforming-software-deployment</link><guid isPermaLink="true">https://blogs.shivangyadav.com/docker-transforming-software-deployment</guid><category><![CDATA[Docker]]></category><category><![CDATA[Devops]]></category><category><![CDATA[containers]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Wed, 20 Mar 2024 05:33:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1710904938064/10acbd4b-1c31-4525-8f20-06acbef51dfb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Docker is a platform designed to make it easier to develop, deploy, and run applications. It provides the ability to package and run an application in a completely isolated environment called a containers.</p>
<p>Containers allow a developer to package up an application with all of the parts it needs, such as libraries and other dependencies, and ship it all out as one package. By doing so, the developer can be confident that the application will run on any other machine regardless of any customized settings that machine might have that could differ from the machine used for writing and testing the code.</p>
<p>Before we delve into Docker's significance, let's first understand the necessity of containerization. To grasp this, we'll explore the evolution of development and deployment practices before containerization became prevalent, providing valuable context for appreciating the innovation Docker brings to modern software development and deployment.</p>
<h1 id="heading-why-do-we-need-docker">Why do we need Docker?</h1>
<p>To understand why do we need docker lets get back to the history of software development and deployment.</p>
<p>The journey of software deployment has traversed through various stages, each marked by distinct technological advancements and models. From the early days of bare-metal servers to the era of virtual machines (VMs) and finally to the emergence of containerization, the landscape of software deployment has undergone significant evolution. In this extensive exploration, we delve into the pre-VM and pre-container eras, understanding the challenges faced, the solutions offered, and the pivotal role played by Docker in revolutionizing software deployment.</p>
<h2 id="heading-pre-virtualization-era-bare-metal-servers-reign">Pre-Virtualization Era: Bare-Metal Servers Reign</h2>
<p>In the early years of computing, software deployment primarily revolved around bare-metal servers. Each server housed a single operating system instance, along with the applications and services it supported. This simplistic approach, while functional, posed <strong>several challenges:</strong></p>
<ol>
<li><p><strong>Resource Utilization</strong>: Bare-metal servers were resource-intensive, requiring dedicated hardware for each server instance. This led to inefficiencies in resource utilization, as server capacities remained underutilized during periods of low demand.</p>
</li>
<li><p><strong>Scalability and Flexibility</strong>: Scaling infrastructure in the bare-metal era was a difficult task. Adding new server instances required physical procurement, setup, and configuration, often resulting in lengthy lead times and increased operational overhead.</p>
</li>
<li><p><strong>Isolation and Security</strong>: With multiple applications running on the same physical server, achieving adequate isolation and security boundaries was challenging. A vulnerability in one application could potentially compromise the entire server, leading to system-wide outages and security breaches.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710820829946/b2dd0efe-22f2-46de-b4ae-402aaacbb63a.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-advent-of-virtualization-introducing-virtual-machines">The Advent of Virtualization: Introducing Virtual Machines</h2>
<p>The virtualization brought a new shift in software deployment, offering a solution to the limitations of bare-metal servers. Virtual machines (VMs) emerged as a groundbreaking technology, enabling multiple isolated instances of operating systems to run on a single physical server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710908725528/01676945-db13-4408-b3c2-12e7142618e0.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-advantages-of-virtualization">Advantages of Virtualization:</h3>
<ol>
<li><p><strong>Resource Consolidation</strong>: Virtualization enabled the consolidation of multiple workloads onto a single physical server, maximizing resource utilization and reducing hardware sprawl. This consolidation led to cost savings and improved operational efficiency.</p>
</li>
<li><p><strong>Scalability and Elasticity</strong>: With VMs, scaling infrastructure became more agile and responsive. Administrators can deploy new VM instances dynamically, adjusting to changing demand patterns with ease.</p>
</li>
<li><p><strong>Isolation and Security</strong>: VMs provided stronger isolation boundaries between applications, mitigating the risk of cross-contamination and enhancing overall security posture. Each VM operated as an independent entity, with its own dedicated resources and runtime environment.</p>
</li>
<li><p><strong>Portability</strong>: VMs enhanced portability, allowing applications to be encapsulated along with their dependencies into self-contained virtualized environments.</p>
</li>
</ol>
<h3 id="heading-challenges-of-vm-based-deployment">Challenges of VM-Based Deployment</h3>
<p>While Virtualization revolutionized software deployment, it also introduced its own set of challenges:</p>
<ol>
<li><p><strong>Resource Overhead</strong>: VMs incurred a significant overhead in terms of memory, storage, and CPU resources. Each VM required its own guest operating system, resulting in duplication of resources and increased management complexity.</p>
</li>
<li><p><strong>Boot Time</strong>: Booting a VM could be a time-consuming process, as it involved loading and initializing a complete operating system instance. Additionally, VM images were relatively large in size, leading to longer startup times and increased storage requirements.</p>
</li>
</ol>
<h2 id="heading-enter-containerization-the-docker-revolution">Enter Containerization: The Docker Revolution</h2>
<p>Amidst the challenges posed by VM-based deployment, containerization emerged as a disruptive force, promising lightweight, portable, and efficient alternatives. Docker, a leading containerization platform, spearheaded this revolution, fundamentally transforming the way applications were packaged, deployed, and managed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710739774187/49243bfc-b385-449b-b153-fe355efadaab.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-key-characteristics-of-containerization">Key Characteristics of Containerization:</h3>
<ol>
<li><p><strong>Lightweight Isolation</strong>: Containers offer lightweight isolation, leveraging the host operating system's kernel to run multiple isolated instances. Unlike VMs, containers share the host OS's resources, resulting in minimal overhead and faster startup times.</p>
</li>
<li><p><strong>Efficient Resource Utilization</strong>: Containers are highly resource-efficient, as they eliminate the need for redundant guest operating systems. Instead, they package only the application and its dependencies, optimizing resource utilization and maximizing density.</p>
</li>
<li><p><strong>Fast Startup and Deployment</strong>: Containers boast rapid startup times, allowing applications to launch within seconds. This enables faster development cycles, streamlined testing, and seamless deployment across different environments.</p>
</li>
<li><p><strong>Portability</strong>: Containers encapsulate applications and dependencies into self-contained units, ensuring consistency across development, testing, and production environments makes it extremely portable.</p>
</li>
</ol>
<h1 id="heading-docker">Docker</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710821008285/55b154c7-f5c3-4e75-a01d-35f112e488e6.png" alt class="image--center mx-auto" /></p>
<p>Docker, with its user-friendly interface and robust tooling ecosystem, democratized containerization, making it accessible to developers and operators. By introducing concepts such as Docker images, containers, and Dockerfiles, Docker provided a standardized workflow for building, shipping, and running applications.</p>
<h2 id="heading-docker-architecture"><strong>Docker</strong> Architecture</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710904674226/6072873e-0657-4158-b3fd-bf6bc8fc0ebf.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Docker Engine</strong>: The core component of Docker, responsible for creating and managing containers on a host system. Docker Engine interacts with the underlying operating system's kernel to run containers efficiently.</p>
</li>
<li><p><strong>Docker Daemon</strong>: The Docker Daemon (dockerd) is a background process that runs on the host machine. It listens for Docker API requests and manages Docker objects such as images, containers, networks, and volumes. The Docker Daemon handles tasks like starting and stopping containers, managing networks, and allocating resources to containers.</p>
</li>
<li><p><strong>Docker Client</strong>: The Docker Client (docker) is a command-line interface (CLI) tool that allows users to interact with the Docker Daemon. It sends commands to the Docker Daemon through the Docker API, enabling users to manage Docker objects from the command line. Users can use the Docker Client to perform tasks such as running containers, managing images, and configuring networks.</p>
</li>
<li><p><strong>Docker Images</strong>: Immutable templates that define the application's runtime environment and dependencies. Docker images serve as the building blocks for containers and can be shared, versioned, and distributed via Docker Hub.</p>
</li>
<li><p><strong>Docker Containers</strong>: Runnable instances of Docker images, isolated from one another and the host system. Containers encapsulate the application, its dependencies, and runtime environment, providing consistency and portability.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710901886573/7d505945-36c5-4aa7-830e-4d37aa2f748d.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Docker Hub</strong>: A centralized repository for Docker images, hosting a vast collection of public and private images across various categories. Docker Hub enables developers to discover, share, and collaborate on containerized applications and services.</p>
</li>
<li><p><strong>Dockerfile</strong>: A Dockerfile is a text file that contains instructions for building a Docker image. It defines the environment and configuration for an application, including its base image, dependencies, environment variables, and startup commands. Docker uses the instructions in the Dockerfile to create a reproducible image that can be run as a container.</p>
</li>
</ol>
<h1 id="heading-getting-started-with-docker">Getting Started with docker</h1>
<h2 id="heading-installation">Installation</h2>
<p>Before you can start using Docker, you'll need to install it on your system. Docker provides installation packages for various operating systems, including Windows, macOS, and Linux. Here's how you can install Docker on your system: <a target="_blank" href="https://docs.docker.com/engine/install/">https://docs.docker.com/engine/install</a></p>
<p>Once Docker is installed on your system, you can verify the installation by opening a terminal or command prompt and running the following command:</p>
<pre><code class="lang-bash">docker --version
</code></pre>
<p>This command should display the installed version of Docker, confirming that it was installed successfully.</p>
<h2 id="heading-introducing-docker-cli">Introducing Docker CLI</h2>
<p>Docker CLI, or Docker Command Line Interface, serves as the primary tool for interacting with Docker. It provides a set of commands that allow users to manage Docker containers, images, networks, volumes, and more. Docker CLI enables developers to build, deploy, and manage containerized applications efficiently. Let's explore what Docker CLI can do and how it facilitates the Docker workflow.</p>
<p>Basic Docker CLI Commands: Now that Docker is installed, let's explore some basic Docker CLI commands and understand what they do:</p>
<ol>
<li><code>docker run</code>: This command is used to run containers from Docker images. It creates a new container instance based on the specified image and starts it. For example:</li>
</ol>
<pre><code class="lang-bash">docker run -it ubuntu <span class="hljs-comment">#running the ubuntu image in interative mode</span>
</code></pre>
<p>This command runs an interactive Ubuntu container, providing you with a shell inside the container.</p>
<p><strong>What happens if image is not present locally?</strong></p>
<p>If the specified image is not present on the local system, Docker Engine automatically looks for it in the default Docker registry, Docker Hub and pull the image from there.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710840512282/e754081a-6f4f-444c-840e-4748df741dcd.png" alt class="image--center mx-auto" /></p>
<ol start="2">
<li><code>docker ps</code>: This command lists all running containers on your system:</li>
</ol>
<pre><code class="lang-bash">docker ps
</code></pre>
<p>Adding the <code>-a</code> flag to the command (<code>docker ps -a</code>) lists all containers, including those that are stopped.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710899499310/de29e920-44fe-4457-9c5c-291c6e70298d.png" alt class="image--center mx-auto" /></p>
<ol start="3">
<li><code>docker pull</code>: Use this command to download Docker images from a registry:</li>
</ol>
<pre><code class="lang-bash">docker pull ubuntu
</code></pre>
<p>This command fetches the latest version of the Ubuntu image from the Docker Hub registry.</p>
<ol start="4">
<li><code>docker stop/start</code>: These commands stop and start containers, respectively:</li>
</ol>
<pre><code class="lang-bash">docker stop &lt;container_id&gt;
docker start &lt;container_id&gt;
</code></pre>
<p>Replace <code>&lt;container_id&gt;</code> with the actual ID of the container.</p>
<ol start="5">
<li><code>docker images</code>: This command lists all Docker images available on your system:</li>
</ol>
<pre><code class="lang-bash">docker images
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710899426283/2235a129-d899-4eb6-ab06-227a97f384cd.png" alt class="image--center mx-auto" /></p>
<ol start="6">
<li><code>docker exec</code> Execute a command in a running container</li>
</ol>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -it &lt;container_id&gt; bash <span class="hljs-comment">#executing the ubuntu container in interative mode</span>
</code></pre>
<p>Ensure that you container must be in running phase for using this command.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710840922470/176196bb-c593-45bb-8eb6-58fef2033b56.png" alt class="image--center mx-auto" /></p>
<ol start="7">
<li><code>docker build</code> Build an image from a Dockerfile</li>
</ol>
<pre><code class="lang-bash">docker build -t myimage:latest .
</code></pre>
<p>This command will look for a Dockerfile in the current directory (<code>.</code>), and build an image with the tag <code>myimage:latest</code>. Latest denote the version of the image.</p>
<h2 id="heading-interactive-mode-vs-detached-mode">Interactive mode vs Detached mode</h2>
<p>In Docker, when you run containers, you can choose between two primary modes: <strong>detached mode</strong> and <strong>interactive mode</strong>.</p>
<h3 id="heading-detached-mode">Detached Mode</h3>
<p>In <strong>detached mode</strong>, the Docker container runs in the background. When you start a container in this mode, the Docker CLI returns control to the terminal immediately, and you won't see any output from the container in the terminal.</p>
<p>To run a container in detached mode, you use the <code>-d</code> flag with <code>docker run</code>. For example:</p>
<pre><code class="lang-bash">docker run -d ubuntu
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710902656312/e9281af4-f7d9-44e5-9f5a-c33a48fbb12a.png" alt class="image--center mx-auto" /></p>
<p>Even though the container runs in the background, you can still use Docker commands to view logs, stop the container, or interact with it in other ways as needed.</p>
<h3 id="heading-interactive-mode">Interactive mode</h3>
<p><strong>Interactive mode</strong> is used when you want to interact with the container, typically through a shell. When you start a container in interactive mode, it attaches the terminal's input and output to the container, allowing you to interact with it directly.</p>
<p>To run a container in interactive mode, you typically use the <code>-it</code> flag with <code>docker run</code>.</p>
<pre><code class="lang-bash">docker run -it ubuntu
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710902936717/92cb02fe-96d3-45cb-beed-35ce8f3d9e67.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-docker-desktop">Docker Desktop</h2>
<p>Docker Desktop offers a user-friendly graphical interface for managing Docker resources, including images and containers. It provides an intuitive way to perform tasks that are typically executed through the Docker command-line interface (CLI). With Docker Desktop, users can interact visually with Docker components, such as building and managing images, creating and monitoring containers, and configuring network settings.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710912694483/69e54319-1701-42e5-8528-0cfba91a0013.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In summary, Docker has revolutionized the way we build, ship, and run applications, offering unparalleled efficiency, scalability, and consistency. By embracing containerization, Docker has simplified the software development lifecycle, empowering developers to focus on innovation rather than infrastructure overhead.</p>
<h1 id="heading-whats-next">What's Next</h1>
<p>As Docker excels at containerizing applications, managing a growing number of containers poses challenges. To address scalability, resource allocation, and high availability, we need a container orchestration solutions and that's where <strong>Kubernetes</strong> comes into picture.</p>
]]></content:encoded></item><item><title><![CDATA[Setting Up Redis in Node.js Server]]></title><description><![CDATA[In this post, we'll explore the end-to-end implementation of Redis with a Node.js server. Before diving into the practical aspects, let's begin by understanding what Redis is.
What is Redis?
Redis (Remote Dictionary Server) is an open-source, high-pe...]]></description><link>https://blogs.shivangyadav.com/setting-up-redis-in-nodejs-server</link><guid isPermaLink="true">https://blogs.shivangyadav.com/setting-up-redis-in-nodejs-server</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Express]]></category><category><![CDATA[Redis]]></category><category><![CDATA[caching]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Sat, 16 Mar 2024 01:22:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1710551870412/b944378a-5b52-463a-82a6-fa87665c6d2b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this post, we'll explore the end-to-end implementation of Redis with a Node.js server. Before diving into the practical aspects, let's begin by understanding what Redis is.</p>
<h2 id="heading-what-is-redis">What is Redis?</h2>
<p>Redis (Remote Dictionary Server) is an open-source, high-performance in-memory database server that excels in storing key-value pairs. Its lightning-fast speed makes it ideal for caching frequently accessed data, implementing real-time features like chat applications, and accelerating various other use cases.</p>
<h3 id="heading-how-redis-works">How Redis works?</h3>
<p>When a client sends a request to fetch data from the server, Redis acts as an intermediary in-memory database. However, frequent page refreshes by users lead to repetitive database queries from the server, increasing the load on the database and causing longer wait times for users. To address this issue, implementing caching mechanisms within Redis to temporarily store frequently accessed data is advisable. By doing so, subsequent requests for the same data can be served directly from Redis, avoiding unnecessary querying of the database, thus reducing both database load and user wait times.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710491982628/cb893981-aa51-4792-9934-47855b22b852.png" alt class="image--center mx-auto" /></p>
<p>When the server receives a request from the client, it first checks Redis for cached data, two scenarios can happen -</p>
<ol>
<li><p><strong>Cache Hits:</strong> If cached data is present, it is retrieved directly from Redis and sent in the response to the client, thereby bypassing unnecessary database queries.</p>
</li>
<li><p><strong>Cache Miss:</strong> If the cached data is not present in Redis, the server then looks for the data in the database and fetches it from there. After fetching the data from the database, it first stores this data in Redis for future use, and then sends the response to the client.</p>
</li>
</ol>
<p>This approach not only reduces the strain on the database by decreasing the number of direct queries but also improves the response time for the user by serving frequently requested data more efficiently.</p>
<h2 id="heading-setting-up-redis-with-ioredis"><strong>Setting Up Redis with ioredis</strong></h2>
<p>To implement Redis within a Node.js environment, there are several external packages available. One of the most popular among these is <code>ioredis</code>.</p>
<ol>
<li><h3 id="heading-install-redis-server"><strong>Install Redis Server</strong></h3>
</li>
</ol>
<p>First, you need to install Redis server on your machine or use a cloud-based Redis service provider such as Redis Labs, Microsoft Azure Cache for Redis, or Aiven. You can download and install Redis from the official website <a target="_blank" href="https://redis.io/">Redis.io</a>.</p>
<p>Additionally, you can install RedisInsight, a GUI for Redis, which allows you to view your stored cache data, including key-value pairs.</p>
<ol start="2">
<li><h3 id="heading-install-ioredishttpswwwnpmjscompackageioredis-library"><strong>Install</strong> <a target="_blank" href="https://www.npmjs.com/package/ioredis"><strong>ioredis</strong></a> <strong>Library</strong></h3>
</li>
</ol>
<p>Next, create a new Node.js project or navigate to your existing project directory and install the ioredis library using npm or yarn:</p>
<pre><code class="lang-bash">npm install ioredis
</code></pre>
<p>or</p>
<pre><code class="lang-bash">yarn add ioredis
</code></pre>
<ol start="3">
<li><h3 id="heading-connect-to-redis-server"><strong>Connect to Redis Server</strong></h3>
</li>
</ol>
<p>Now, you can connect to the Redis server in your Node.js application by creating an instance of the <code>Redis</code> class provided by the ioredis library. Here's an example of how to connect to a local Redis server:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Redis <span class="hljs-keyword">from</span> <span class="hljs-string">'ioredis'</span>

<span class="hljs-keyword">const</span> redis = <span class="hljs-keyword">new</span> Redis({
    <span class="hljs-attr">port</span>: process.env.REDIS_PORT, <span class="hljs-comment">// Your Redis server's port</span>
    <span class="hljs-attr">host</span>: process.env.REDIS_HOST, <span class="hljs-comment">// Your Redis server's host</span>
    <span class="hljs-comment">// Optional: Add password if authentication is enabled</span>
    <span class="hljs-attr">password</span>: process.env.REDIS_PASS
});

redis.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected to Redis!'</span>));
redis.on(<span class="hljs-string">'error'</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Redis Client Error'</span>, err));

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> redis
</code></pre>
<p>For example, To connect with you local redis server -</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> redis = <span class="hljs-keyword">new</span> Redis({
    <span class="hljs-attr">host</span>: <span class="hljs-string">'localhost'</span>, 
    <span class="hljs-attr">port</span>: <span class="hljs-number">6379</span>, 
    <span class="hljs-attr">password</span>: <span class="hljs-string">'your_password'</span> <span class="hljs-comment">//optional</span>
});
</code></pre>
<p>Now, this Redis client can be utilized for executing various Redis commands throughout the code.</p>
<ol start="4">
<li><h3 id="heading-using-redis-commands"><strong>Using Redis Commands</strong></h3>
</li>
</ol>
<p><code>set</code> Stores a key-value pair:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> redis.set(<span class="hljs-string">'name'</span>: <span class="hljs-string">'John'</span>);
</code></pre>
<p><code>get</code> Retrieve the value associated with a key:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> value = <span class="hljs-keyword">await</span> redis.get(<span class="hljs-string">'name'</span>);
<span class="hljs-built_in">console</span>.log(value); <span class="hljs-comment">// Output: John: Delete a key-value pair:</span>
</code></pre>
<p><code>del</code> Delete a key-value pair:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> redis.del(<span class="hljs-string">'name'</span>);
</code></pre>
<p><code>expire</code> Set the expiry of the key value pair:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> redis.expire(<span class="hljs-string">'name'</span>, <span class="hljs-number">30</span>); <span class="hljs-comment">//expires the data after 30 sec</span>
</code></pre>
<p><code>setex</code> Set a key-value pair along with an expiration time in seconds:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> redis.setex(key, <span class="hljs-number">30</span>, value); <span class="hljs-comment">//Sets the key value pair which expires in 30 sec</span>
</code></pre>
<h2 id="heading-implementing-redis-in-large-projects"><strong>Implementing Redis in Large Projects</strong></h2>
<ol>
<li><p><strong>Redis Module</strong>: Create a Redis module (<code>redis.js</code>) using ioredis, as described above in the blog.</p>
</li>
<li><p><strong>Caching Middleware</strong>: Develop middleware that checks if a request can be served from Redis before hitting the API logic. If cached data exists, return it; otherwise, proceed with the request and cache the response for future use.</p>
</li>
<li><p><strong>Apply to Routes</strong>: Apply this middleware selectively to routes that benefit most from caching, considering factors like data volatility and request frequency.</p>
</li>
</ol>
<h3 id="heading-caching-middleware"><strong>Caching Middleware</strong></h3>
<p>Create a middleware <code>cacheMiddleware.js</code> that attempts to fetch a response from Redis before proceeding to the controller logic:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> redis <span class="hljs-keyword">from</span> <span class="hljs-string">"./redis.js"</span>;

<span class="hljs-keyword">const</span> cacheMiddleware = <span class="hljs-keyword">async</span>(req, res, next) =&gt; {
    <span class="hljs-keyword">const</span> key = req.path; 

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> cachedData = <span class="hljs-keyword">await</span> redisClient.get(key);
        <span class="hljs-keyword">if</span> (cachedData) {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"cache hit"</span>)
            <span class="hljs-keyword">return</span> res.send(<span class="hljs-built_in">JSON</span>.parse(cachedData));
        }
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"cache miss"</span>)
        next();
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Cache error: <span class="hljs-subst">${error}</span>`</span>);
        next();
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> cacheMiddleware
</code></pre>
<h3 id="heading-using-middleware-in-your-routes"><strong>Using Middleware in Your Routes</strong></h3>
<p>Apply the caching middleware to your Express routes. This example assumes you have an Express server setup in <code>app.js</code>, you can use it according to your project.</p>
<pre><code class="lang-javascript">app.get(<span class="hljs-string">'/api/data'</span>, cacheMiddleware, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchData(); 

  <span class="hljs-comment">// Save the fetched data in Redis cache before sending the response</span>
  redisClient.setex(req.path, <span class="hljs-number">60</span>, <span class="hljs-built_in">JSON</span>.stringify(data)); <span class="hljs-comment">// cache for 60sec</span>

  res.send(data);
});
</code></pre>
<p>In this approach, we utilize the API's path, accessed via <code>req.path</code>, as the key for storing data. It's crucial to ensure that each key is unique to avoid data conflicts.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This setup demonstrates a basic but effective pattern for integrating Redis into a Node.js application. By caching responses, you reduce redundant operations, leading to faster response times and a more scalable application. Remember, the effectiveness of your caching strategy heavily depends on your application's specific needs, including the nature of your data and how frequently it changes.</p>
]]></content:encoded></item><item><title><![CDATA[Hoisting in Javascript]]></title><description><![CDATA[One of the most confusing concept in Javascript is hoisting. Understanding hoisting is crucial for writing reliable and maintainable code.
What exactly is hoisting?
When the browser encounters JavaScript code, it creates a special phenomenon known as...]]></description><link>https://blogs.shivangyadav.com/hoisting-in-javascript</link><guid isPermaLink="true">https://blogs.shivangyadav.com/hoisting-in-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[javascript hoisting]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Tue, 12 Mar 2024 11:19:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1710237467123/df599fea-9258-40a4-8ff1-adc64625f389.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the most confusing concept in Javascript is <strong>hoisting</strong>. Understanding hoisting is crucial for writing reliable and maintainable code.</p>
<h2 id="heading-what-exactly-is-hoisting">What exactly is hoisting?</h2>
<p>When the browser encounters JavaScript code, it creates a special phenomenon known as the <a target="_blank" href="https://shivangyadav.hashnode.dev/decoding-javascript-how-javascript-really-works#heading-the-execution-context-deep-dive">Execution Context</a>. During the creation of the Variable Object, all variables declared with the <code>var</code> keyword and function declarations are stored in memory even before the program actually executes, and the value of variables is set to <code>undefined</code>. This means that you can use variables and functions in your code before they are formally declared. This process of storing variables and functions before execution is called <strong>hoisting</strong>.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(name) <span class="hljs-comment">//undefined</span>
<span class="hljs-keyword">var</span> name = <span class="hljs-string">'John'</span>
<span class="hljs-built_in">console</span>.log(name) <span class="hljs-comment">//John</span>
</code></pre>
<p>In the example above, logging the variable <code>name</code> before its initialization doesn't throw an error; instead, it returns <code>undefined</code>.</p>
<h2 id="heading-types-of-hoisting">Types of Hoisting</h2>
<p>There are two main types of hoisting in javascript:</p>
<ol>
<li><p>Variable hoisting</p>
</li>
<li><p>Function hoisting</p>
</li>
<li><p>Class hoisting</p>
</li>
</ol>
<h3 id="heading-variable-hoisting">Variable Hoisting</h3>
<p>Variables declared with <code>var</code>, <code>let</code>, and <code>const</code> are all hoisted in JavaScript, but there are differences in how hoisting works with <code>var</code> versus <code>let</code>/<code>const</code>.</p>
<ul>
<li><p><strong>Hoisting with</strong><code>var</code>: Variables declared with <code>var</code> are hoisted, allowing them to be accessed before initialization without throwing an error, albeit returning <code>undefined</code>. This behavior can be confusing for developers. To address this, ECMAScript 6 (ES6) introduced new keywords, <code>let</code> and <code>const</code>, which provide a more predictable behavior.</p>
</li>
<li><p><strong>Hoisting with</strong><code>let</code> and <code>const</code>: let and const are also hoisted, but unlike var they are not initialized and accessing them before initialization results in a ReferenceError: "Cannot access 'variable' before initialization." This behavior highlights the presence of a <strong>Temporal Dead Zone (TDZ)</strong> for <code>let</code> and <code>const</code> declarations, where the variables exist but cannot be accessed until they are initialized.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(fruit) <span class="hljs-comment">//ReferenceError: Cannot access 'fruit' before initialization</span>
<span class="hljs-keyword">let</span> fruit = <span class="hljs-string">'Apple'</span>
</code></pre>
<p>In the above example we will get ReferenceError: Cannot access 'fruit' before initialization, instead if we have used <code>var</code> here instead of <code>let</code>, than we get the value of fruit undefined.</p>
<p><strong>What is Temporal Dead Zone(TDZ)?</strong></p>
<p>The Temporal Dead Zone refers to the period from the beginning of the scope where the <code>let</code> or <code>const</code> variable is declared until the point where it is initialized. During this time, accessing the variable will result in a ReferenceError, indicating that the variable cannot be accessed before initialization.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> name = <span class="hljs-string">'John'</span>  <span class="hljs-comment">//TDZ for 'fruit' starts here</span>
<span class="hljs-built_in">console</span>.log(name)  <span class="hljs-comment">//John</span>

<span class="hljs-comment">//Temporal dead zone for fruit hence error</span>
<span class="hljs-built_in">console</span>.log(fruit) <span class="hljs-comment">//ReferenceError: Cannot access 'fruit' before initialization</span>

<span class="hljs-keyword">let</span> fruit = <span class="hljs-string">'Apple'</span> <span class="hljs-comment">//TDZ for 'fruit' ends here</span>

<span class="hljs-built_in">console</span>.log(fruit) <span class="hljs-comment">//Apple</span>
</code></pre>
<h3 id="heading-function-hoisting">Function Hoisting</h3>
<p>Function hoisting shares similarities with variable hoisting. Function declarations are hoisted to the top of the scope, allowing them to be invoked before their actual placement in the code.</p>
<pre><code class="lang-javascript">fruits() <span class="hljs-comment">//Bannana</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fruits</span>(<span class="hljs-params"></span>) </span>{
 <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Bannana'</span>)
}
</code></pre>
<p>In the above example we can see, that we call calling fruits function before its declaration and still printing the result</p>
<p><strong>Note that only function</strong><code>declarations</code><strong>are hoisted, not function</strong><code>expressions</code><strong>.</strong></p>
<p>If we try to call the variable that the function expression was assigned to, we will get a <code>TypeError</code> in case of var and <code>ReferenceError</code> in case of let and const.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//Case 1</span>
fruits() <span class="hljs-comment">// TypeError: fruits is not a function</span>
<span class="hljs-keyword">var</span> fruits = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
 <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Bannana'</span>)
}


<span class="hljs-comment">//Case 2</span>
fruits() <span class="hljs-comment">// ReferenceError: Cannot access 'fruits' before initialization</span>
<span class="hljs-keyword">let</span> fruits = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
 <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Bannana'</span>)
}
</code></pre>
<p><strong>Arrow functions</strong>, introduced in ES6, behaves like let, or const give ReferenceError if called before initilization.</p>
<pre><code class="lang-javascript">fruits() <span class="hljs-comment">//ReferenceError: Cannot access 'fruits' before initialization</span>

<span class="hljs-keyword">const</span> fruits = <span class="hljs-function">() =&gt;</span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"apple"</span>)
}
</code></pre>
<h3 id="heading-class-hoisting">Class hoisting</h3>
<p>Just like <code>let</code> and <code>const</code> variables, classes are hoisted to the top of the scope they are defined in, but inaccessible until they are initialized.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> apple = <span class="hljs-keyword">new</span> Fruit(<span class="hljs-string">"apple"</span>) 
<span class="hljs-comment">//ReferenceError: Cannot access 'fruit' before initialization</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Fruit</span> </span>{
  <span class="hljs-keyword">constructor</span>(name) {
    <span class="hljs-built_in">this</span>.name = name
  }
}
</code></pre>
<p>Here, we declare a class called <code>Fruit</code>. We try to access this class before it was declared and get a reference error: <strong>Cannot access 'Fruit' before initialization</strong>, just like in let and const.</p>
<h2 id="heading-summary">Summary</h2>
<p>In conclusion, variable hoisting is a crucial aspect of JavaScript that impacts how variable declarations are processed during the compilation phase. While <code>var</code> exhibits hoisting behavior, it introduces scope-related issues. The introduction of <code>let</code> and <code>const</code> in ES6 addresses these problems by enforcing block-level scoping and introducing the Temporal Dead Zone.</p>
<p>As a best practice, it is advisable to use <code>let</code> and <code>const</code> over <code>var</code> to write more predictable and maintainable code. Understanding these concepts is essential for every JavaScript developer to produce good and bug-free code.</p>
]]></content:encoded></item><item><title><![CDATA[Decoding JavaScript: How JavaScript Really Works?]]></title><description><![CDATA[JavaScript is the requirement of modern web development. It adds interactivity and dynamism to those static HTML pages. But have you wondered how it actually works? What happens when you write a line of JavaScript code and it makes something happen o...]]></description><link>https://blogs.shivangyadav.com/decoding-javascript-how-javascript-really-works</link><guid isPermaLink="true">https://blogs.shivangyadav.com/decoding-javascript-how-javascript-really-works</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Fri, 08 Mar 2024 22:19:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1709936198203/e850943d-44ef-45f2-8032-89492b9ce08b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>JavaScript is the requirement of modern web development. It adds interactivity and dynamism to those static HTML pages. But have you wondered how it actually works? What happens when you write a line of JavaScript code and it makes something happen on your screen? Let's lift the hood and deep dive into the internal working of the javascript.</p>
<p>So Let's start from the beginning, When your browser encounters JavaScript code nestled within your HTML, it hands the code off to a specialised interpreter called the JavaScript engine which converts the code into computer understandable langauge.</p>
<h1 id="heading-the-javascript-engine">The Javascript Engine</h1>
<p>Every web browser comes equipped with a JavaScript engine, a specialized program responsible for interpreting and executing JS code. Some of the popular Javascript engines include Chrome's V8, Firefox's SpiderMonkey, and Safari's JavaScriptCore.</p>
<h2 id="heading-how-javascript-engine-works"><strong>How Javascript engine works?</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709917537625/564d10d5-a0e1-44ad-b13a-d35e4999b0d6.png" alt="Javascript engine" class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Parsing:</strong> The engine starts reading your JavaScript line by line, breaking it down into its core elements like functions, variables, and expressions. This analysis builds an <strong>Abstract Syntax Tree (AST)</strong>, a tree-like data structure that captures the structure and relationships between elements in your code.</p>
</li>
<li><p><strong>Code Generation:</strong> The AST is then used to generate bytecode. Bytecode is a lower-level, machine-independent format that's easier for the engine to optimise.</p>
<p> And now this byte code is ready for execution.</p>
</li>
<li><p><strong>Optimisation:</strong> When executing the bytecodes, JS engine keeps monitoring the codes and start optimising code parallelly by compiling it into machine code. This is called <strong>Just-in-Time compilation</strong>. This compiled machine code runs much faster than interpreted bytecode, giving JavaScript a performance boost.</p>
<p> <strong>But What if the optimisation fails?</strong></p>
<p> If the optimisation fails for any reason, then the compiler de-optimises codes and let the interpreter executes the original bytecodes.</p>
</li>
</ol>
<h2 id="heading-the-execution-context-deep-dive">The Execution Context : Deep Dive</h2>
<p>When ever your browser encounters JavaScript code, the browser's JavaScript engine then creates a special environment to handle execution of this code. This environment is known as the <code>Execution Context</code>.</p>
<p>During the Execution Context run-time, the code gets parsed and, the variables and functions are stored in memory, executable byte-code gets generated, and the code gets executed.</p>
<p>Two types of execution context are there-</p>
<ol>
<li><p><strong>Global Execution Context (GEC) :</strong> When a JavaScript program initiates execution, the browser's JavaScript engine establishes the Global Execution Context (GEC). This GEC serves as the foundation upon which all other contexts are built.</p>
</li>
<li><p><strong>Function Execution Context (FEC):</strong> Every time a function is invoked in JavaScript, a new <strong>Function Execution Context (FEC)</strong> is created. This FEC becomes the active context during the function's execution.</p>
<p> Since every function call gets its own FEC, there can be more than one FEC in the run-time of a script.</p>
</li>
</ol>
<h3 id="heading-creation-of-execution-context">Creation of Execution Context</h3>
<p>The creation of execution context occurs in three steps -&gt;</p>
<ol>
<li><h3 id="heading-creation-of-the-variable-object-vo"><strong>Creation of the Variable Object (VO):</strong></h3>
</li>
</ol>
<p>The VO is a container that stores variables and function declarations within the execution context. In the GEC, variables declared with <code>var</code> are added to the VO and initialised to <code>undefined</code>.</p>
<p>Also, function declaration are stored in memory. This means that all the function declarations will be stored and made accessible inside the VO, even before the code starts running.</p>
<p>FECs, on the other hand, don't have a VO. Instead, they create an argument object containing the arguments passed to the function.</p>
<p>This process of storing variables and functions before execution is called <a target="_blank" href="https://shivangyadav.hashnode.dev/hoisting-in-javascript"><strong>hoisting</strong></a>.</p>
<ol start="2">
<li><h3 id="heading-creation-of-the-scope-chain"><strong>Creation of the Scope Chain:</strong></h3>
</li>
</ol>
<p>Scope determines where variables and functions are accessible in your code.</p>
<p>Each FEC creates its own scope chain, which is a hierarchy of scopes. The function's local scope is at the top, followed by the scopes of its parent functions, all the way up to the GEC.</p>
<p>When a function is defined in another function, the inner function has access to the code defined in that of the outer function, and that of its parents. This behavior is called <strong>lexical scoping</strong>.</p>
<p>However, the outer function does not have access to the code within the inner function.</p>
<p>This concept of scope brings up an associate phenomenon in JavaScript called <strong>closures</strong>.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">outerFunction</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">var</span> outerVar = <span class="hljs-string">"I'm from the outer function!"</span>;

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">innerFunction</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Accessing outerVar from the inner function</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Inner function can access outerVar:"</span>, outerVar);  

    <span class="hljs-keyword">var</span> innerVar = <span class="hljs-string">"I'm from the inner function!"</span>;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Inner variable:"</span>, innerVar);
  }

  innerFunction();  
}

outerFunction();  

<span class="hljs-comment">//Output</span>
<span class="hljs-comment">//Inner function can access outerVar: I'm from the outer function!</span>
<span class="hljs-comment">//Inner variable: I'm from the inner function!</span>
</code></pre>
<p>In above example if we try to access inner var in outer function by console logging inner var, it will give error.</p>
<ol start="3">
<li><h3 id="heading-setting-the-value-of-the-this-keyword"><strong>Setting the Value of the</strong> <code>this</code> Keyword:</h3>
</li>
</ol>
<p>The <code>this</code> keyword refers to the current execution context.</p>
<h5 id="heading-thisin-global-context"><code>"this"</code><strong>in Global Context</strong></h5>
<p>In the GEC, <code>this</code> refers to the global object (usually the <code>window</code> object in browsers).</p>
<h5 id="heading-thisin-functions"><code>"this"</code><strong>in Functions</strong></h5>
<p>In the case of the FEC, it doesn't create the <code>this</code> object. Rather, it get's access to that of the environment it is defined in.</p>
<p>Read more about <a target="_blank" href="https://shivangyadav.hashnode.dev/understanding-the-this-keyword-in-javascript">"this keyword in javascript"</a></p>
<h3 id="heading-the-execution-phase">The Execution Phase</h3>
<p>Once the creation phase is complete, the JavaScript engine moves on to the execution phase. Here, the Javascript engine reads code line by line once more in the current execution context, and the variable which are set to undefined in VO, assigned with actual values, functions are called, and the code gets transpired to executable byte code, and finally gets executed.</p>
<h3 id="heading-the-call-stack-keeping-track-of-function-calls"><strong>The Call Stack: Keeping Track of Function Calls</strong></h3>
<p>The Call Stack is a LIFO (Last-In-First-Out) data structure that manages function calls. As a function is invoked, a new Stack Frame is pushed onto the call stack. This frame holds information about the function's arguments, local variables, and the return address (where to continue after the function finishes). When the function returns, its stack frame is popped off the stack, and execution resumes at the return address.</p>
<p>Let us understand the call stack with an example -</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> name = <span class="hljs-string">"John"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">func1</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">var</span> a = <span class="hljs-string">"Hello"</span>;
  func2();
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${a}</span> <span class="hljs-subst">${name}</span>`</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">func2</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">var</span> b = <span class="hljs-string">"World"</span>;
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${b}</span> <span class="hljs-subst">${name}</span>`</span>);

}

func1();
</code></pre>
<p>Initially as the js code loaded on the browser, the Global execution context is being created and pushed to the bottom of the Call Stack. The name variable is present inside the GEC.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709931703292/4b6b20b4-657c-4e2c-8578-1990ea33179a.png" alt class="image--center mx-auto" /></p>
<p>Now, when js engine encounters func1 call, it creates Function execution context for func1 and this new context is placed on top of the current context, forming the <code>Execution Stack</code>.</p>
<p>The variable 'a' which is inside the func1 is stored in the Function execution context(FEC) not in GEC.</p>
<p>Similary FEC is created for func2 when encounters function call inside the func1.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709931878061/e828a3ba-a5d2-4234-a9f5-07a4f5ab1a80.png" alt class="image--center mx-auto" /></p>
<p>As the functions execution is finished, the function execution context of the function is popped out one by one from the top and at last reaches the Gobal Execution Context remains in the stack.</p>
<p>And lastly, when the execution of the entire code gets completed, the JS engine removes the GEC from the current stack.</p>
<h3 id="heading-the-event-loop-handling-asynchronous-operations"><strong>The Event Loop: Handling Asynchronous Operations</strong></h3>
<p>JavaScript is single-threaded, meaning it can only execute one task at a time. However, it can handle asynchronous operations, through the Event Loop.</p>
<p>Let us understand how it works:</p>
<ol>
<li><p><strong>Main Thread:</strong> Executes the main JS code sequentially.</p>
</li>
<li><p><strong>Callback Queue:</strong> The callback queue includes callback functions that are ready to be executed. The callback queue ensures that callbacks are executed in the First-In-First-Out (FIFO) method and they get passed into the call stack when it’s empty.</p>
</li>
<li><p><strong>Event Loop:</strong> Continuously monitors the main thread and the callback queue. When the main thread becomes idle (after executing a synchronous task or reaching the end of the code), the event loop dequeues a callback from the callback queue and pushes the callback onto the call stack for execution</p>
</li>
</ol>
<p>This approach allows JS to appear responsive while handling asynchronous operations without blocking the main thread.</p>
<h1 id="heading-conclusion"><strong>Conclusion</strong></h1>
<p>By understanding the internal workings of the JavaScript engine, ASTs, the call stack, and the event loop, we gain a deeper knowledge for how the simple code translates into dynamic and interactive web experiences. This understanding empowers us to write more efficient, maintainable, and robust JavaScript applications.</p>
]]></content:encoded></item><item><title><![CDATA[Why Should TypeScript Be Used Instead of JavaScript?]]></title><description><![CDATA[We all know JavaScript has long been the go-to language in development. However, as projects scale in size and complexity, the need for robust features like maintainability and scalability becomes indispensable. This is where TypeScript steps onto th...]]></description><link>https://blogs.shivangyadav.com/why-should-typescript-be-used-instead-of-javascript</link><guid isPermaLink="true">https://blogs.shivangyadav.com/why-should-typescript-be-used-instead-of-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[programming languages]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Tue, 05 Mar 2024 19:27:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1709666823192/8f179501-c2b4-4ede-a4f1-ca6eae790c03.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We all know JavaScript has long been the go-to language in development. However, as projects scale in size and complexity, the need for robust features like maintainability and scalability becomes indispensable. This is where TypeScript steps onto the stage, offering a compelling alternative.</p>
<h3 id="heading-what-is-typescript">What is TypeScript?</h3>
<p>Developed and maintained by Microsoft, TypeScript is an open-source programming language. It is a superset of JavaScript, introducing optional <code>static typing</code> to the language, that brings several advantages:</p>
<ul>
<li><p><strong>Variable Type Declarations:</strong> Developers can explicitly define the data types that variables can hold (e.g., <code>string</code>, <code>number</code>, <code>boolean</code>). This clarity leads to improved code quality and maintainability.</p>
</li>
<li><p><strong>Early Error Detection:</strong> TypeScript's static nature allows the compiler to identify potential type-related errors during development, rather than waiting for runtime execution failures. This proactive approach significantly reduces development time and debugging efforts.</p>
</li>
</ul>
<h3 id="heading-understanding-static-and-dynamic-typing">Understanding Static and Dynamic Typing</h3>
<p>Static typing and dynamic typing refer to how programming languages handle variable types either at compile-time or runtime.  </p>
<p><strong>Static typing:</strong> In a statically typed language(like <code>Typescript</code>), variable types are known and checked at compile-time, before the program is executed. This allows developers to catch type-related errors during the compilation phase.</p>
<p><strong>Dynamic typing:</strong> In a dynamically typed language(like <code>Javascript</code>), variable types are determined and checked at runtime, during program execution. Variables can change their types during the program's execution, and type checking is done as the program runs</p>
<h3 id="heading-why-typescript-for-complex-and-large-projects">Why Typescript for complex and large projects?</h3>
<p>As your projects grow in size and complexity, the following reasons make TypeScript an attractive choice:</p>
<ol>
<li><p><strong>Type Safety</strong>: One of the standout features of TypeScript is its static typing system. In JavaScript, variables can change types dynamically, leading to potential runtime errors that may not surface until a later stage of development. TypeScript's static typing allows developers to catch such errors during the compilation phase, providing an early safety net for code quality.</p>
</li>
<li><p><strong>Easier Scalability</strong>: As projects grow in size, maintaining a clean and organized codebase becomes crucial. TypeScript provides features such as modules, namespaces, and interfaces that facilitate better project organization.</p>
</li>
<li><p><strong>Improved Readability and Maintainability</strong>: TypeScript's explicit typing not only contributes to better code quality but also enhances code readability. When you read a TypeScript file, the types explicitly convey the intentions of the code. This clarity is especially beneficial for developers who are new to a project or for those reviewing code written by others.</p>
</li>
</ol>
<h3 id="heading-beyond-the-basics"><strong>Beyond the Basics</strong></h3>
<p>While TypeScript's core advantages are well-established, it's essential to consider your project's specific requirements and your team's preferences when making a decision. Here are some additional points:</p>
<ul>
<li><p><strong>Learning Curve:</strong> If your team is unfamiliar with statically typed languages, there might be a learning curve associated with adopting TypeScript. However, the long-term benefits in terms of code quality and maintainability often outweigh this initial investment.</p>
</li>
<li><p><strong>Tooling and Community:</strong> TypeScript enjoys a robust ecosystem of tools and a supportive community, offering excellent resources, documentation, and troubleshooting assistance.</p>
</li>
</ul>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>While JavaScript's flexibility made it a foundational web technology, TypeScript's static typing, organization features, and clarity make it the superior choice for managing complex and large-scale projects. By addressing JavaScript's limitations without sacrificing its strengths, TypeScript ensures that projects can grow and evolve without being hampered by the very language they're built on.</p>
]]></content:encoded></item><item><title><![CDATA[Asynchronous Nature of JavaScript]]></title><description><![CDATA[What is the Asynchronous Nature of JavaScript?
In the world of web development, JavaScript stands out as a supreme language with a range of powerful features. One of its most remarkable attributes is its asynchronous nature. Essentially, this means t...]]></description><link>https://blogs.shivangyadav.com/asynchronous-nature-of-javascript</link><guid isPermaLink="true">https://blogs.shivangyadav.com/asynchronous-nature-of-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[asynchronous]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Sun, 03 Mar 2024 22:59:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1709506089991/e0894fc6-76bd-4ff4-9572-ceea7cade2ca.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-the-asynchronous-nature-of-javascript">What is the Asynchronous Nature of JavaScript?</h2>
<p>In the world of web development, JavaScript stands out as a supreme language with a range of powerful features. One of its most remarkable attributes is its asynchronous nature. Essentially, this means that JavaScript doesn't execute code in a strictly sequential, blocking manner.</p>
<p>Imagine you've written a JavaScript program for an application that needs to fetch some data from a server while simultaneously handling other tasks. When you run this code, JavaScript won't halt or block the execution while waiting for the data from the server. Instead, it cleverly carries out the data-fetching process in the background, allowing the program to move on and execute the next line of code without delay. When the server data is ready, JavaScript will then display it.</p>
<p>In essence, JavaScript operates with a non-blocking nature. It doesn't obstruct the flow of code but instead continues executing subsequent lines promptly. This characteristic is particularly advantageous for building responsive and efficient web applications.</p>
<h2 id="heading-asynchronous-nature-vs-synchronous-nature">Asynchronous Nature vs. Synchronous Nature</h2>
<p><strong>Synchronous programming</strong>, also known as blocking or sequential programming, follows a straightforward execution model. In this model, tasks are executed one after the other, and each task must be completed before the next one begins. If a task takes a long time to finish, it can block the entire program, causing it to become unresponsive.</p>
<p><strong>Asynchronous programming</strong>, on the other hand, allows tasks to run concurrently and independently, without blocking the main execution thread. JavaScript achieves this through mechanisms like callbacks, promises, and async/await.</p>
<p><strong>Analogy: The Coffee Shop Scenario</strong></p>
<p>To better understand the concept of asynchronous programming, let's consider a scenario at a coffee shop. Imagine you are a barista, and your job is to serve customers. In a synchronous coffee shop, you take orders from one customer at a time and prepare their drinks in the order they were received. This means that if one customer orders a complicated coffee with several customizations, all other customers have to wait, potentially leading to long queues and frustrated customers.</p>
<p>Now, let's switch to an asynchronous coffee shop. In this setting, you can take orders from multiple customers simultaneously, even if some orders require more time to prepare. You start making one customer's coffee, and while it's brewing, you can take another customer's order and begin preparing their drink. This way, customers don't have to wait as long, and the coffee shop can serve more people efficiently.</p>
<h2 id="heading-handling-asynchronous-nature-in-javascript">Handling Asynchronous Nature in JavaScript</h2>
<h3 id="heading-1-what-are-the-callback-function">1. What are the Callback function?</h3>
<p>Callbacks are functions passed as arguments to other functions. When an asynchronous task finishes, the function that initiated it calls back the provided callback function, often supplying the result (or error, if something went wrong). This mechanism enables your code to react to the completion of an asynchronous task.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Start"</span>);

<span class="hljs-comment">// Asynchronous function to simulate fetching data</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params">callback</span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Inside the function"</span>);

  <span class="hljs-comment">// Simulating an asynchronous operation</span>
  <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Invoke the provided callback after 1 second</span>
    callback();
  }, <span class="hljs-number">1000</span>);
}

<span class="hljs-comment">// Callback function to be executed after fetching data</span>
<span class="hljs-keyword">const</span> callback = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Callback executed.'</span>);
}

<span class="hljs-comment">// Using the fetchData function with the callback</span>
fetchData(callback);

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"End"</span>);

<span class="hljs-comment">//OUTPUT: </span>
<span class="hljs-comment">//Start</span>
<span class="hljs-comment">//Inside the function</span>
<span class="hljs-comment">//End</span>
<span class="hljs-comment">//Callback executed.</span>
</code></pre>
<p>Let's understand the above example -</p>
<ol>
<li><p>"Start" is logged to the console initially.</p>
</li>
<li><p>Upon invoking the <code>fetchData</code> function, "Inside the function" is logged inside it. After that, the <code>setTimeout</code> function is encountered, which is an asynchronous operation, so it is pushed to the background, and the rest of the code is executed until its completion.</p>
</li>
<li><p>"End" is logged to the console.</p>
</li>
<li><p>After a 1-second delay, the callback function is executed, logging "Callback executed."</p>
</li>
</ol>
<p>We can clearly see from the above example that when asynchronous task is encountered, it does not block the rest of the code. Instead, it pushes the asynchronous task to the background and continues executing the rest of the code until its completion.</p>
<p>One more example with error handling for better understanding -&gt;</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">"start"</span>);

<span class="hljs-comment">// Function to fetch data asynchronously using a script element</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params">src, callback</span>) </span>{

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"inside the function"</span>);

  <span class="hljs-comment">// Create a script element and set its source</span>
  <span class="hljs-keyword">let</span> script = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"script"</span>);
  script.src = src;

  <span class="hljs-comment">// Define onload and onerror events for script loading</span>
  script.onload = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Invoke the callback on successful loading</span>
    callback(<span class="hljs-literal">null</span>, src);
  };
  script.onerror = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Invoke the callback with an error on loading failure</span>
    callback(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"src encountered an error"</span>), src);
  };
}

<span class="hljs-comment">// Callback function to handle success or failure after fetching data</span>
<span class="hljs-keyword">const</span> success = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, data</span>) </span>{
  <span class="hljs-keyword">if</span> (err) {
    <span class="hljs-built_in">console</span>.error(err);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"success"</span>, data);
  }
};

<span class="hljs-comment">// Invoking fetchData with a sample URL and the success callback</span>
fetchData(
  <span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/js/bootstrap.min.js"</span>,
  success,
);

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"end"</span>);


<span class="hljs-comment">//Output:</span>
<span class="hljs-comment">//start</span>
<span class="hljs-comment">//inside the function</span>
<span class="hljs-comment">//end</span>
<span class="hljs-comment">//success https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/js/bootstrap.min.js</span>
</code></pre>
<h3 id="heading-callback-hell">Callback hell</h3>
<p>While callbacks are a fundamental tool for handling asynchronous operations, their overuse can lead to a dreaded phenomenon known as <strong>callback hell</strong> also know as <strong>Pyramid of Doom</strong>. This occurs when you have multiple callbacks nested within each other, creating a difficult-to-understand code structure.</p>
<pre><code class="lang-javascript">fetchData(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
  processFirstData(data, <span class="hljs-function">(<span class="hljs-params">processedData</span>) =&gt;</span> {
    processSecondData(processedData, <span class="hljs-function">(<span class="hljs-params">finalResult</span>) =&gt;</span> {
      <span class="hljs-comment">// More nested callbacks...</span>
    });
  });
});
</code></pre>
<p>Here, we have a chain of three asynchronous functions: <code>fetchData</code>, <code>processFirstData</code>, and <code>processSecondData</code>. Each function takes a callback as an argument, and the next operation is nested inside the callback of the previous one. The indentation creates a pyramid-like structure, making the code difficult to follow.</p>
<p>Asynchronous operations in a callback-centric structure can quickly become complex, leading to a lack of readability and code maintainability. This is where <code>Promises</code> and come to the rescue, providing cleaner alternatives to handling asynchronous code.</p>
<h3 id="heading-2-introduction-to-promises">2. Introduction To <strong>Promises</strong></h3>
<p>To address the challenges posed by callback hell, Promises were introduced in ECMAScript 6 (ES6). A Promise represents the eventual completion or failure of an asynchronous operation and its resulting value. It provides a more structured and readable way to handle asynchronous code.</p>
<p>In more easy way, think of a promise as an IOU (I Owe You) note. It represents the eventual delivery of a value (the result of an asynchronous operation) or an error notification in case something goes wrong. A promise object exists in one of three states:</p>
<ul>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709502956741/da39d8ce-68b3-4de4-88a6-ef2c6dfcfb64.png" alt /></p>
<p>  <strong>Pending:</strong> The initial state, signifying the asynchronous operation is still in progress.</p>
</li>
<li><p><strong>Fulfilled:</strong> The operation completed successfully, and the promise holds the resulting value.</p>
</li>
<li><p><strong>Rejected:</strong> The operation encountered an error, and the promise holds the error object.</p>
</li>
</ul>
<p>Basic syntax of promise looks like this -&gt;</p>
<ol>
<li><p><strong>Promise Constructor:</strong> To create a promise, you utilize the <code>Promise</code> constructor. Inside, you provide a function (the executor) that performs the asynchronous operation. This function takes two arguments, <code>resolve</code> and <code>reject</code></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> myPromise = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
     <span class="hljs-comment">//asynchronous operation</span>
     <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
         resolve(<span class="hljs-string">"Operation successful!"</span>); 
         reject(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Operation failed!"</span>)); 
     }, <span class="hljs-number">2000</span>);
 });
</code></pre>
<ul>
<li><p><code>resolve</code> is called when the operation succeeds, and you pass the resulting value to it.</p>
</li>
<li><p><code>reject</code> is called when the operation fails, and you pass the error object to it.</p>
</li>
</ul>
</li>
<li><p><strong>Handling Promise Completion:</strong> Promises provide two key methods to handle their eventual outcome:</p>
<ul>
<li><code>.then()</code>: This method is called when the promise is fulfilled. You provide a callback function that receives the resolved value as an argument. You can chain multiple <code>.then()</code> calls to handle subsequent operations based on the result.</li>
</ul>
</li>
</ol>
<pre><code class="lang-javascript">    myPromise.then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(result); <span class="hljs-comment">// Output: "Operation successful!"</span>
    });
</code></pre>
<ul>
<li><code>.catch()</code>: This method is called when the promise is rejected. You provide a callback function that receives the error object as an argument.</li>
</ul>
<pre><code class="lang-javascript">    myPromise.catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.error(error.message); <span class="hljs-comment">// Output: "Operation failed!" (if rejected)</span>
    });
</code></pre>
<p>    Promises revolutionized asynchronous JavaScript, providing a structured way to handle operations. But sometime chaining multiple <code>.then()</code> calls in a long sequence can still result in a complex and less readable structure, reminds of the callback hell problem. This is where <code>async/await</code> comes into picture.</p>
<h3 id="heading-3-asyncawait-a-step-into-modern-javascript">3. <strong>Async/Await: A Step into modern JavaScript</strong></h3>
<p>While Promises address the challenges of callback hell, ES2017 (ES8) introduced <code>async</code> and <code>await</code> keywords to simplify the syntax further. <code>async</code> is used to declare an asynchronous function, while <code>await</code> is used within the function to wait for the resolution of a Promise.</p>
<p><strong>Core Concepts:</strong></p>
<ul>
<li><p><code>async</code> Functions: Declare functions that can perform asynchronous operations. When you call an <code>async</code> function, it returns a promise.</p>
</li>
<li><p><code>await</code> Keyword: Used within <code>async</code> functions to pause execution until a promise is resolved or rejected. The <code>await</code> keyword can only be used inside <code>async</code> functions.</p>
</li>
</ul>
<p>Let's understand this with an example -&gt;</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> apiUrl = <span class="hljs-string">'https://api.example.com/data'</span>;

<span class="hljs-comment">// Define an asynchronous function to fetchData</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params">url</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url);
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
    <span class="hljs-built_in">console</span>.log(data);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  }
}

fetchData(apiUrl);
</code></pre>
<p>In the above example, the <code>fetchData</code> function is designed to make an asynchronous HTTP request to a specified URL using the <code>fetch</code> function. The <code>await</code> keyword is used to pause the execution of the function until the promise returned by <code>fetch</code> is resolved and then logs the data to the console after converting it to json format. If any error encountered during the asynchronous operation, the <code>catch</code> block is executed and logs the error.</p>
<p><strong>Beyond the Basics -&gt;</strong></p>
<p>While <code>async/await</code> offers a simpler approach, understanding promises remains valuable. Additionally, you might encounter situations where promises are still a better fit. Regardless, <code>async/await</code> has become the preferred way to handle asynchronous operations in modern JavaScript due to its readability and maintainability.</p>
<h2 id="heading-the-benefits-of-asynchronous-programming"><strong>The Benefits of Asynchronous Programming</strong></h2>
<p>By adopting asynchronous practices, you can unlock several advantages for your web applications:</p>
<ul>
<li><p><strong>Enhanced User Experience:</strong> Asynchronous operations prevent your web app from freezing while waiting for long-running tasks. Users can interact with the UI seamlessly, leading to a more fluid and responsive experience.</p>
</li>
<li><p><strong>Improved Performance:</strong> Asynchronous code execution optimizes resource utilization. JavaScript doesn't block other operations, allowing your application to make better use of available processing power.</p>
</li>
<li><p><strong>Scalability:</strong> Asynchronous programming is particularly adept at handling numerous concurrent requests or long-running operations, making your web app more scalable for demanding scenarios.</p>
</li>
</ul>
<h2 id="heading-in-conclusion"><strong>In Conclusion</strong></h2>
<p>Asynchronous programming is foundation of modern JavaScript development. By understanding its concepts and utilizing techniques like callbacks, promises, and <code>async/await</code>, you can craft web applications that are not only performant but also provide a delightful user experience. So, he next time you build a web app, remember to use asynchronous features in JavaScript!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding the 'this' Keyword in JavaScript]]></title><description><![CDATA[What exactly is 'this'?
In JavaScript, this is a keyword that refers to the object it belongs to. The specific object it references depends entirely on how the current function is being called. Its behavior is dynamic, meaning its value changes depen...]]></description><link>https://blogs.shivangyadav.com/understanding-the-this-keyword-in-javascript</link><guid isPermaLink="true">https://blogs.shivangyadav.com/understanding-the-this-keyword-in-javascript</guid><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Fri, 01 Mar 2024 09:40:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1709313988350/b4a79742-2c63-4556-a198-8b651775a08f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-what-exactly-is-this"><strong>What exactly is 'this'?</strong></h3>
<p>In JavaScript, <code>this</code> is a keyword that refers to the object it belongs to. The specific object it references depends entirely on how the current function is being called. Its behavior is dynamic, meaning its value changes depending on the context in which it's used.</p>
<h3 id="heading-common-scenarios-for-this"><strong>Common Scenarios for 'this'</strong></h3>
<p><strong>1. Global Context</strong></p>
<p>In the global execution context (outside of any function), <code>this</code> refers to the global object. In a browser, the global object is <code>window</code>, so <code>this</code> in a global context would refer to <code>window</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>)
<span class="hljs-comment">//output: Window {0: global, window: Window, self: Window, document: document, name: '', location: Location, …}</span>
</code></pre>
<p><strong>2. In a Regular Function</strong></p>
<p>In a regurlar function call, <code>this</code> refers to the global object (in non-strict mode) or <code>undefined</code> (in strict mode).</p>
<p><strong>'strict' mode</strong></p>
<p>In 'strict' mode, <code>this</code> inside regular functions that are not part of an object will be <code>undefined</code>, preventing accidental reference to the global object.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">whatsThis</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>); 
}

whatsThis(); <span class="hljs-comment">//output: Window {0: global, window: Window, self: Window, document: document, name: '', location: Location, …}</span>
</code></pre>
<p><strong>3. In an Object Method</strong></p>
<p>When used inside a method belonging to an object, <code>this</code> refers to the object itself.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> person = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Alice"</span>,
  <span class="hljs-attr">greet</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Hello, "</span> + <span class="hljs-built_in">this</span>.name);
  }
};

person.greet(); <span class="hljs-comment">// Output: "Hello, Alice"</span>
</code></pre>
<p><code>Understanding Function Borrowing</code></p>
<p>When a function is assigned to a variable or another object, <code>this</code> will refer to the object it is called with, not where it was originally defined.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> person = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Bob"</span>,
  <span class="hljs-attr">greet</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Hello, "</span> + <span class="hljs-built_in">this</span>.name);
  }
};

<span class="hljs-keyword">const</span> greetFunc = person.greet;
<span class="hljs-keyword">const</span> person2 = { <span class="hljs-attr">name</span>: <span class="hljs-string">"Charlie"</span>, <span class="hljs-attr">greet</span>: greetFunc };

person2.greet(); <span class="hljs-comment">// Logs "Hello, Charlie"</span>
</code></pre>
<p>In the above example, when <code>greet</code> is called as a method of <code>person2</code>, <code>this</code> within the <code>greet</code> function now refers to <code>person2</code>, because <code>greet</code> is being called with <code>person2</code> as the context. Therefore, <code>this.name</code> is "Charlie", and the function logs "Hello, Charlie" to the console.</p>
<p>The crucial point in this example is understanding that the value of <code>this</code> inside a function depends on the object it is called upon, not where the function was defined or assigned. When <code>greetFunc</code> is called as part of <code>person2</code>, <code>this</code> refers to <code>person2</code>, resulting in "Hello, Charlie" being logged.</p>
<p><strong>3. In a Constructor Function</strong></p>
<p>When a function is used as a constructor (with the <code>new</code> keyword), <code>this</code> refers to the newly created object.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Person</span>(<span class="hljs-params">name</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name;
}

<span class="hljs-keyword">const</span> person = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">'John'</span>);
<span class="hljs-built_in">console</span>.log(person.name); <span class="hljs-comment">//Output: "John"</span>
</code></pre>
<p><strong>4. In a Event Listener</strong></p>
<p>In event listeners, <code>this</code> usually refers to the HTML element that triggered the event.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> button = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"button"</span>);
button.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>); <span class="hljs-comment">// Output: the button element</span>
});
</code></pre>
<h3 id="heading-arrow-functions-and-this"><strong>Arrow Functions and 'this'</strong></h3>
<p>We know that <code>this</code> within a function depends on how the function is called. Traditional functions (declared with the function keyword) have their <code>this</code> value set dynamically at the time they are invoked. This means that the same function can have different <code>this</code> values depending on its calling context.</p>
<p>However, <strong>arrow functions</strong>, behave differently. They do not have their own <code>this</code> binding. Instead, they "inherit" the <code>this</code> value from the lexical scope in which they were defined. This means the value of <code>this</code> inside an arrow function is the same as the value of <code>this</code> in the outer function or global scope (if not defined inside a function) where the arrow function was created.</p>
<p><strong>Example 1 -&gt;</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> obj = {
  <span class="hljs-attr">show</span>: <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>);
  }
};

obj.show(); <span class="hljs-comment">// In a browser, 'this' will log 'window' because it's captured from the global scope</span>
</code></pre>
<p><strong>Example 2 -&gt;</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> person = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Alex'</span>,
  <span class="hljs-attr">activities</span>: [<span class="hljs-string">'run'</span>, <span class="hljs-string">'jump'</span>, <span class="hljs-string">'throw'</span>],
  <span class="hljs-attr">showActivities</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">this</span>.activities.forEach(<span class="hljs-function">(<span class="hljs-params">activity</span>) =&gt;</span> {
      <span class="hljs-comment">// Arrow function inherits 'this' from showActivities method context</span>
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> likes to <span class="hljs-subst">${activity}</span>`</span>);
    });
  }
};

person.showActivities();

<span class="hljs-comment">// Output:</span>
<span class="hljs-comment">// Alex likes to run</span>
<span class="hljs-comment">// Alex likes to jump</span>
<span class="hljs-comment">// Alex likes to throw</span>
</code></pre>
<p>In this example, the arrow function passed to <code>forEach</code> inherits the <code>this</code> value from the <code>showActivities</code> method's context. Therefore, <code>this.name</code> inside the arrow function correctly refers to <code>person.name</code></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Since <code>this</code> is so context-dependent, it's sometimes a source of confusion. Always be mindful of the context in which your functions are being called to understand the value of <code>this</code>. Using <code>console.log(this)</code> is a great debugging tool.</p>
]]></content:encoded></item><item><title><![CDATA[Getting Started with React: A Comprehensive Introduction]]></title><description><![CDATA[Introduction to React
What is React?
React is an open-source JavaScript library for developing interactive user interfaces (UI), commonly used in making single-page applications (SPAs). It was built and is maintained by Facebook
React is based on a c...]]></description><link>https://blogs.shivangyadav.com/getting-started-with-react-a-comprehensive-introduction</link><guid isPermaLink="true">https://blogs.shivangyadav.com/getting-started-with-react-a-comprehensive-introduction</guid><category><![CDATA[React]]></category><category><![CDATA[ReactHooks]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Mon, 02 Oct 2023 17:32:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1696267566683/c17df20b-672d-4714-b83d-0a2f78c07e03.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction-to-react">Introduction to React</h2>
<h3 id="heading-what-is-react">What is React?</h3>
<p>React is an open-source JavaScript library for developing interactive user interfaces (UI), commonly used in making single-page applications (SPAs). It was built and is maintained by Facebook</p>
<p>React is based on a components-based approach to build complex user interfaces. <strong>React components</strong> are self-contained, reusable building blocks for creating user interfaces. These components can be combined to create complex user interfaces while maintaining a clear and structured codebase.</p>
<p><strong>e.g.</strong> Imagine a web page as a collection of small-small blocks. Each small block represents a component, such as a header, a navigation menu, or a content section. React helps you build and assemble these small blocks to create a complete web page.</p>
<h3 id="heading-why-use-react">Why use React?</h3>
<p><img src="https://s3.ap-southeast-1.amazonaws.com/arrowhitech.com/wp-content/uploads/2020/07/01102045/feature-1-1024x568.jpg" alt class="image--center mx-auto" /></p>
<p><strong>What is the need for React when JavaScript already exists?</strong></p>
<p>You may wonder why React was developed when JavaScript already exists. To understand this, it's essential to recognize that React is not a replacement for JavaScript but rather a library built on top of it. JavaScript is the core programming language used for web development, but React addresses specific challenges and needs in the context of building user interfaces.</p>
<h3 id="heading-challenges-in-traditional-javascript-that-react-solved">Challenges in Traditional Javascript that React solved -</h3>
<ul>
<li><p>JavaScript employs an imperative programming approach, where developers specify how to achieve a particular functionality step by step. In contrast, React adopts a declarative approach. In React, developers specify what functionality they want, and React automatically manages the underlying procedures to achieve the desired outcome.</p>
</li>
<li><p>When working with JavaScript, directly interacting with the Document Object Model (DOM) can lead to inefficiencies in website performance. React addresses this issue by introducing the Virtual DOM. Instead of manipulating the Real DOM directly, React updates a Virtual DOM representation first. Then, it compares this Virtual DOM to the Real DOM, using a diffing algorithm to calculate the minimal steps required to update the Real DOM.</p>
</li>
<li><p>React's component-based approach enhances code reusability and promotes structured and readable code. Unlike vanilla JavaScript, where code can become complex and hard to maintain, React allows developers to create modular and reusable components, making it easier to build and maintain large-scale applications.</p>
</li>
</ul>
<h3 id="heading-virtual-dom-vs-real-dom">Virtual DOM vs. Real DOM</h3>
<p><img src="https://s3.ap-southeast-1.amazonaws.com/arrowhitech.com/wp-content/uploads/2020/07/02034639/compare.jpg" alt class="image--center mx-auto" /></p>
<p>The real DOM is a representation of a webpage that you view in your browser. It's a tree-like structure that represents all the elements on a webpage - text, images, buttons, and so on.</p>
<p>In contrast, the virtual DOM serves as a blueprint of the real DOM, but it exists only in the computer's memory, not on the actual webpage you're looking at. It's like a sketch of the webpage.</p>
<p>Here's a simplified analogy to help understand the Virtual DOM:</p>
<ul>
<li><p>Imagine the real DOM as a physical book in a library. If you want to make changes to the book, you need to physically go to the library, make the edits, and then put the book back in its place.</p>
</li>
<li><p>Now, think of the Virtual DOM as a digital PDF of the book. You can make as many changes as you want to the PDF without affecting the original book. When you're done, you can compare the edited PDF with the original book and apply only the necessary changes to the actual book.</p>
</li>
</ul>
<p>In this analogy, the PDF serves as a lightweight, editable representation of the original book, just as the Virtual DOM serves as a lightweight, editable representation of the real DOM.</p>
<h3 id="heading-declarative-nature-of-react">Declarative Nature of React</h3>
<p>React follows a declarative approach to building user interfaces. Instead of manually instructing how the UI should change when data changes, you declare what the UI should look like for a given state, and React takes care of updating it accordingly. You don't need to provide step-by-step instructions on how to render each component or handle every user interaction. You only state, "This is how the UI should look given the current data". This makes the code more predictable and easier to understand.</p>
<p><strong>e.g.</strong> Imagine you're ordering a cake. Imperative programming is like giving a recipe with step-by-step instructions to bake it yourself. You're telling exactly what to do. On the other hand, Declarative programming is like ordering from a bakery. You just say, "I want a delicious cake," and they handle everything, using their expertise to make it happen.</p>
<p>In React, it's similar. You declare what you want your UI to look like, and React figures out how to update it efficiently. This declarative approach simplifies development by focusing on the "what" instead of the "how," making your code more maintainable and scalable.</p>
<h2 id="heading-understanding-components-in-react">Understanding Components in React</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696265613019/6c6917a6-b72a-4cda-a07c-c800f9386649.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-what-are-react-components">What are React Components?</h3>
<p>In React, components are the building blocks of a user interface. They are reusable, self-contained pieces of code that can be composed to create complex UIs.</p>
<p>Think of React components as the basic building blocks for making a website, similar to how bricks are the essential pieces for building a house. Each React component is like a small, self-contained part of a webpage that can be used to create more complex web applications.</p>
<p>Imagine you're building a web application. Instead of trying to make the whole thing in one piece, you use different blocks for different parts – one block for a button, another for a header, and yet another for a form. These blocks (components) can be used in different different parts of the application.</p>
<p>By breaking down your webpage into these reusable components, you make your code more organized and easier to work with. If you want to change something, you can focus on just one component without messing up everything else. It's like rearranging or replacing specific Lego blocks without affecting the entire structure. This makes your code easier to maintain and build upon as your project grows.</p>
<h3 id="heading-functional-components-vs-class-components">Functional Components vs. Class Components?</h3>
<p>React components are of two types functional components and class components.</p>
<ul>
<li><strong>Functional components</strong> are stateless, meaning they don't manage their own internal state. They are simpler and more concise than class components. They consist of a function that takes props as an argument and returns JSX(JavaScript XML) to render.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>But in recent versions of React, functional components are favored and can also manage state using react-hooks, making them more concise and easier to understand.</p>
<ul>
<li><strong>Class components</strong> on the other hand can hold and manage their own internal state. This allows them to store and update data that can affect the component's rendering.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { Component } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">App</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
  render() {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> 
  }
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>Class components have lifecycle methods like <strong><em>componentDidMount</em></strong>, <strong><em>componentDidUpdate</em></strong>, and <strong><em>componentDidUnmount</em></strong> that you can use to manage component behavior throughout its lifecycle. However, with the introduction of React hooks in functional components, many of these lifecycle methods can be replicated using hooks like <strong><em>useEffect</em></strong>.</p>
<p><strong>The Shift to Functional Components with Hooks:</strong></p>
<p>In recent versions of React, functional components have gained significant enhancements through the introduction of hooks. Hooks are functions that allow functional components to manage state, side effects, and other React features that were previously exclusive to class components. This shift has made functional components more powerful and flexible.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {useState, useEffect} <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
     <span class="hljs-comment">//useState hook</span>
     <span class="hljs-keyword">const</span> [state, setState] = useState()
     <span class="hljs-comment">//useEffect hook</span>
     useEffect(<span class="hljs-function">() =&gt;</span> {
       <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {  }
     }, [])
  <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p><strong>Commonly used hooks include:</strong></p>
<ol>
<li><p><strong>useState:</strong> This hook allows functional components to declare and manage component-level state.</p>
</li>
<li><p><strong>useEffect:</strong> It enables functional components to perform side effects, such as data fetching, after the component has rendered.</p>
</li>
<li><p><strong>useContext:</strong> This hook provides access to the context API, allowing components to access global state without the need for prop drilling.  </p>
</li>
</ol>
<h2 id="heading-handling-data-with-props-and-state"><strong>Handling Data with Props and State</strong></h2>
<h3 id="heading-passing-data-with-props"><strong>Passing Data with Props</strong></h3>
<p>Props (short for properties) are a way to pass data from parent components to child components in React. They are read-only and help in creating dynamic and reusable components by allowing you to customize their behavior and appearance.</p>
<p><strong>e.g.</strong> Think of props as parameters you pass to a function. For instance, you can pass a "color" prop to a button component to specify its color.</p>
<h3 id="heading-managing-component-state"><strong>Managing Component State</strong></h3>
<p>State in React is used to store and manage data that can change over time. Stateful components can update their state and trigger re-renders, allowing your UI to react to user interactions and data changes.</p>
<p><strong>e.g.</strong> Consider a weather app. The temperature displayed is a piece of state that updates as new data becomes available. When the temperature changes, React automatically updates the UI to reflect the new value.</p>
<h3 id="heading-state-vs-props-when-to-use-each"><strong>State vs. Props: When to Use Each</strong></h3>
<p>Understanding when to use state and when to use props is crucial in React development. Props are used to pass data from parent to child components, while state is used for managing data that can change within a component.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In conclusion, React is a powerful library for building user interfaces in JavaScript. It simplifies UI development by introducing the concept of components, uses a Virtual DOM for efficient updates, and promotes a declarative approach to building UIs. Understanding components, props, and state is essential for building interactive and dynamic web applications using React.</p>
<p>By mastering React's concepts and principles, you can create scalable, maintainable, and highly performant web applications that provide a great user experience.</p>
]]></content:encoded></item><item><title><![CDATA[Artificial Intelligence: Power Of Machines]]></title><description><![CDATA[Have you ever wondered how machines actually work? In today's advanced world, we see many humanoid robots. They can do everything that a person can do, such as walking, talking, making expressions, and performing various movements. Sometimes I wonder...]]></description><link>https://blogs.shivangyadav.com/artificial-intelligence-power-of-machines</link><guid isPermaLink="true">https://blogs.shivangyadav.com/artificial-intelligence-power-of-machines</guid><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Machine Learning]]></category><dc:creator><![CDATA[Shivang Yadav]]></dc:creator><pubDate>Wed, 07 Jun 2023 04:04:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/OYzbqk2y26c/upload/7be850edfc8b6a3b7148ac1310c3a48d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever wondered how machines actually work? In today's advanced world, we see many humanoid robots. They can do everything that a person can do, such as walking, talking, making expressions, and performing various movements. Sometimes I wonder how this works. I mean, how can a mathematical expression and lines of code make a piece of metal alive? Think about it - sometime you will definitely feel weird.</p>
<p>Nowadays, machines are working on Artificial Intelligence, i.e., the intelligence made by human beings. Today we are operating with narrow AI, but we are not very far from creating a Super AI. As we can see, technology is developing so fast, it seems that the super AI will come into the picture very soon.</p>
<p>Super AI is when machines become conscious and have their own feelings and emotions. It is also known as singularity. They can think on their own, make their own decisions, and do anything they want. Super AI can be very useful for humans because their thinking power is very advanced. They can think very fast and solve complex problems in seconds that the human brain takes years to solve. After the creation of SUPER AI, if they are in our favor, the advancement in technology will become so fast that we can create technology that seems hypothetical in today's world.</p>
<p>But on the other hand, creating a Super Artificial Intelligence can be very dangerous for humans. Some experts also believe that it can be the last invention of humans on earth because when we talk about super AI, it is very extraordinary and advanced. We humans, in front of such advanced robots, become ridiculous. If they develop the thought that humans are pieces of shit and are useless or if we get in their way, then we are finished, and Homo Sapiens will become extinct.</p>
<p>Today's AI language models, such as ChatGPT and Gemini, are very popular among people. These language models are basically based on a mathematical concept called linear algebra that is trained with a lot of data from all around the world. CHATGPT can give you personalized answers, takes feedback, and become more advanced day by day.</p>
<p>Do you think these language models (ChatGPT and Gemini) can become <strong>sentient</strong> one day? Actually, we do not have a very clear idea yet of how the human brain gains consciousness. A newborn child's brain knows nothing about this world, but as the child grows, the brain observes various phenomenon happening in the surroundings. The brain observes how humans interact with each other, how humans talk, walk, sing, etc. According to all these observations, brain learn many new things, such as how to deal with new situations, etc. Similarly, it can be possible that AI language models also observe human thoughts, activities, behavior, etc., and become conscious slowly, gaining sentience. What are your thoughts on this?</p>
<p>I am not a professional on this topic, so the above information may not be up to the point.</p>
]]></content:encoded></item></channel></rss>