<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Ashutosh Krishna - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Ashutosh Krishna - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 15 May 2026 22:29:18 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/ashutoshkrris/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ From Symptoms to Root Cause: How to Use the 5 Whys Technique ]]>
                </title>
                <description>
                    <![CDATA[ Most teams don't struggle because they can't fix problems. They struggle because they fix the wrong thing. An API fails in production. You restart the service, errors go away, and it feels resolved. U ]]>
                </description>
                <link>https://www.freecodecamp.org/news/from-symptoms-to-root-cause-how-to-use-the-5-whys-technique/</link>
                <guid isPermaLink="false">69ea4d69904b915438990f19</guid>
                
                    <category>
                        <![CDATA[ problem solving skills ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ debugging ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Thu, 23 Apr 2026 16:48:41 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/b5dbd964-9a03-448d-92a5-92e3b4a47fef.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Most teams don't struggle because they can't fix problems. They struggle because they fix the wrong thing.</p>
<p>An API fails in production. You restart the service, errors go away, and it feels resolved. Until it happens again. And again. What's happening here is simple: you're treating symptoms, not the underlying cause.</p>
<p>The <strong>5 Whys technique</strong> is a straightforward way to deal with this. It comes from the Toyota Production System and was designed to help teams dig deeper into problems instead of settling for quick fixes.</p>
<p>The idea is simple. Ask "why" repeatedly until you reach the real cause.</p>
<p>But in practice, this is where things go wrong.</p>
<p>Teams often:</p>
<ul>
<li><p>Stop too early</p>
</li>
<li><p>Assume answers without checking data</p>
</li>
<li><p>Focus on people instead of systems</p>
</li>
<li><p>Treat "five" as a rule instead of a guideline</p>
</li>
</ul>
<p>So even though the process looks structured, the outcome is still shallow.</p>
<p>In this article, we'll focus on how to actually use the 5 Whys in real situations. Not just the theory, but what it looks like when you apply it to an engineering problem.</p>
<h3 id="heading-heres-what-well-cover">Here's What We'll Cover:</h3>
<ul>
<li><p><a href="#heading-what-is-the-5-whys-technique">What is the 5 Whys Technique?</a></p>
</li>
<li><p><a href="#heading-origins-of-the-5-whys-method">Origins of the 5 Whys Method</a></p>
</li>
<li><p><a href="#heading-how-to-conduct-an-effective-5-whys-analysis">How to Conduct an Effective 5 Whys Analysis</a></p>
</li>
<li><p><a href="#heading-real-world-example-applying-5-whys-in-an-engineering-scenario">Real-World Example: Applying 5 Whys in an Engineering Scenario</a></p>
</li>
<li><p><a href="#heading-when-to-use-and-when-not-to-use-5-whys">When to Use (and When Not to Use) 5 Whys</a></p>
</li>
<li><p><a href="#heading-benefits-of-the-5-whys-technique">Benefits of the 5 Whys Technique</a></p>
</li>
<li><p><a href="#heading-common-pitfalls-and-limitations">Common Pitfalls and Limitations</a></p>
</li>
<li><p><a href="#heading-tips-for-using-5-whys-effectively">Tips for Using 5 Whys Effectively</a></p>
</li>
<li><p><a href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-what-is-the-5-whys-technique">What is the 5 Whys Technique?</h2>
<p>The 5 Whys technique is a way to break down a problem by repeatedly asking why it happened, with the goal of reaching a cause that actually explains the issue and can be addressed.</p>
<p>At its core, it's not about the number five. The name can be misleading. What matters is the process of following a chain of cause and effect until the explanation stops being superficial and starts becoming useful.</p>
<p>Each answer you uncover should move you one level deeper. You start with what went wrong, then explore what led to it, and continue until you reach something that is both believable and actionable. In most real situations, that final answer is not a single event but a gap in a system, a missing check, or an assumption that was never validated.</p>
<p>The technique became widely known through the Toyota Production System, where it was used to improve processes by focusing on causes rather than quick fixes.</p>
<p>That context is important because it highlights the original intent. The goal was not just to explain problems, but to prevent them from happening again.</p>
<p>A simple example makes this clearer. Imagine a mobile app suddenly starts crashing after a release. Asking "Why?" might look like this:</p>
<ol>
<li><p>Why is the app crashing? → Because a null value is being accessed in the code.</p>
</li>
<li><p>Why is there a null value? → Because the API response is missing a required field</p>
</li>
<li><p>Why is the field missing? → Because a recent backend change made the field optional.</p>
</li>
<li><p>Why was this change not handled in the app? → Because the app assumes the field is always present.</p>
</li>
<li><p>Why was this assumption not caught earlier? → Because there are no contract tests validating API responses.</p>
</li>
</ol>
<p>At this point, the issue is no longer just "fix the null check". The deeper problem is the lack of validation between systems, which allows breaking changes to slip through.</p>
<p>A useful way to think about the 5 Whys is that it forces you to stay with the problem a little longer than you normally would. Most of the time, the first explanation feels sufficient, so it's easy to stop there. This method pushes you to go one step further, and then another, until the explanation holds up under scrutiny.</p>
<p>At the same time, it's not a rigid formula. You might reach a solid root cause in three steps, or it might take more than five. The quality of the reasoning matters more than the count.</p>
<h2 id="heading-origins-of-the-5-whys-method">Origins of the 5 Whys Method</h2>
<p>The 5 Whys method comes from the Toyota Production System, a manufacturing approach focused on continuous improvement and problem solving at the source.</p>
<p>It's often associated with Sakichi Toyoda, whose philosophy was simple: don’t just fix a problem. Understand why it happened so it doesn't happen again.</p>
<p>Inside Toyota, this wasn't treated as a formal tool or checklist. It was part of the day-to-day way of working. When something went wrong on the production line, the goal wasn't to get things running quickly and move on. The goal was to stop, investigate, and make sure the same issue wouldn't repeat.</p>
<p>That mindset is important to understand. The 5 Whys was never meant to be a rigid exercise where you ask five questions and stop. It was a way to encourage deeper thinking and accountability in processes.</p>
<p>Another key idea in the Toyota system is that problems are usually caused by processes, not people. Instead of asking "who made the mistake", the focus is on "what allowed this mistake to happen". The 5 Whys fits naturally into this approach because it pushes you toward system level causes rather than individual blame.</p>
<p>Over time, the method spread beyond manufacturing and is now used in software engineering, product teams, operations, and many other fields. The context has changed, but the core idea remains the same: if you don't understand the cause, you're likely to see the same problem again.</p>
<p>This origin story is useful not just as background, but as a reminder of intent. The value of the 5 Whys doesn't come from the questions themselves. It comes from the discipline of not settling for the first answer.</p>
<h2 id="heading-how-to-conduct-an-effective-5-whys-analysis">How to Conduct an Effective 5 Whys Analysis</h2>
<p>A 5 Whys analysis works best when it is treated as a structured way of thinking, not a checklist to rush through. The quality of the outcome depends less on how many times you ask "why" and more on how carefully you reason through each step.</p>
<p>It helps to approach it in stages, each with a clear purpose.</p>
<h3 id="heading-step-1-define-the-problem-clearly">Step 1: Define the Problem Clearly</h3>
<p>Start with a problem statement that is specific and observable. Avoid vague descriptions like "the system is slow" or "things are failing". Instead, describe what actually happened in a way that can be verified.</p>
<p>For example, "API response time exceeded 5 seconds for 30 percent of requests between 2 PM and 3 PM" is much more useful than "API is slow".</p>
<p>A clear problem statement keeps the analysis grounded. If the starting point is fuzzy, the entire chain of reasoning will drift.</p>
<h3 id="heading-step-2-ask-why-iteratively">Step 2: Ask "Why" Iteratively</h3>
<p>Once the problem is defined, begin asking why it happened. Each answer should directly address the question before it and naturally lead to the next one.</p>
<p>The key here is continuity. Every step should feel like a logical extension of the previous one. If you find yourself jumping topics or introducing unrelated explanations, it's a sign that the chain is breaking.</p>
<p>Keep going until the answers stop being immediate symptoms and start pointing toward underlying conditions or decisions.</p>
<p>Also, don't force the process to stop at five. Some problems may need fewer steps, while others may need more. What matters is reaching a point where the explanation is meaningful and actionable.</p>
<h3 id="heading-step-3-validate-each-answer-with-evidence">Step 3: Validate Each Answer with Evidence</h3>
<p>This is where many analyses go wrong. It's easy to come up with plausible answers, but plausibility is not enough.</p>
<p>Each "why" should be backed by some form of evidence. This could be logs, metrics, recent changes, or direct observation. If an answer can't be verified, treat it as a hypothesis and confirm it before moving forward.</p>
<p>Without validation, the entire analysis becomes a chain of assumptions. Even if the final answer sounds reasonable, it may not reflect reality.</p>
<h3 id="heading-step-4-identify-the-root-cause">Step 4: Identify the Root Cause</h3>
<p>A good root cause is one that explains the sequence of events and can be acted upon to prevent the issue in the future.</p>
<p>In many cases, this turns out to be a gap in a process rather than a single technical failure. It could be a missing validation step, an incomplete test, or an assumption that was never challenged.</p>
<p>If the final answer still feels like a symptom, you probably need to go one level deeper. On the other hand, if the answer points to something you can change in your system or workflow, you are likely in the right place.</p>
<h3 id="heading-step-5-define-corrective-actions">Step 5: Define Corrective Actions</h3>
<p>The analysis is only useful if it leads to meaningful action.</p>
<p>Once you've identified the root cause, the next step is to define changes that prevent the problem from happening again. These should go beyond quick fixes and address the underlying issue.</p>
<p>For example, instead of just fixing a bug, you might introduce better testing, add monitoring, or improve review processes.</p>
<p>Good corrective actions share a few traits: they're specific, practical to implement, and they directly address the root cause identified in the analysis.</p>
<h2 id="heading-real-world-example-applying-5-whys-in-an-engineering-scenario">Real-World Example: Applying 5 Whys in an Engineering Scenario</h2>
<p>To see how this works in practice, let’s walk through a realistic backend issue. The goal here is not just to reach an answer, but to show how each step builds on evidence and leads to something actionable.</p>
<h3 id="heading-the-problem">The Problem:</h3>
<p>Users report intermittent failures while fetching order details:</p>
<pre><code class="language-bash">GET /api/orders/{id}
→ HTTP 500 Internal Server Error
</code></pre>
<p>Application logs show:</p>
<pre><code class="language-plaintext">// Java 21 example (Spring Boot style logging)
logger.error("Database connection timeout while fetching order", ex);
</code></pre>
<p>At this point, it's tempting to conclude that the database is the problem. But that's only what we can see on the surface.</p>
<h3 id="heading-applying-the-5-whys">Applying the 5 Whys</h3>
<h4 id="heading-1-why-did-the-api-return-a-500-error">1. Why did the API return a 500 error?</h4>
<p>Because the database query timed out.</p>
<p>This is directly supported by the error logs, so we can treat it as a confirmed fact.</p>
<h4 id="heading-2-why-did-the-query-time-out">2. Why did the query time out?</h4>
<p>Because the database connection pool was exhausted.</p>
<p>Metrics show that all available connections were in use during peak traffic.</p>
<h4 id="heading-3-why-was-the-connection-pool-exhausted">3. Why was the connection pool exhausted?</h4>
<p>Because some requests were holding database connections for too long.</p>
<p>Slow query logs confirm that a subset of queries had unusually high execution times.</p>
<h4 id="heading-4-why-were-some-queries-slow">4. Why were some queries slow?</h4>
<p>Because a recently introduced feature added a query on a non-indexed column.</p>
<p>Looking at recent deployments reveals a change that introduced filtering without proper indexing.</p>
<h4 id="heading-5-why-was-an-unoptimized-query-deployed-to-production">5. Why was an unoptimized query deployed to production?</h4>
<p>Because there is no performance validation step in the development or release process.</p>
<p>There are no checks in code review or CI/CD to catch inefficient database queries before deployment.</p>
<h3 id="heading-root-cause">Root Cause</h3>
<p>The issue is not the timeout itself.</p>
<p>It's this:</p>
<blockquote>
<p>The system allows inefficient database queries to reach production without any safeguards.</p>
</blockquote>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/f93fb121-d5ac-45bc-8b3b-cc4f915c48a3.png" alt="f93fb121-d5ac-45bc-8b3b-cc4f915c48a3" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-what-a-shallow-fix-would-look-like">What a Shallow Fix Would Look Like</h3>
<p>If we stopped early, we might:</p>
<ul>
<li><p>Increase the database timeout</p>
</li>
<li><p>Increase the connection pool size</p>
</li>
</ul>
<p>These might reduce the frequency of failures, but they don't solve the underlying problem.</p>
<h3 id="heading-what-a-strong-fix-looks-like">What a Strong Fix Looks Like</h3>
<p>A proper 5 Whys analysis leads to changes that improve the system:</p>
<ul>
<li><p>Add appropriate indexing for frequently queried fields</p>
</li>
<li><p>Introduce query performance checks in CI/CD pipelines</p>
</li>
<li><p>Add monitoring and alerts for slow queries</p>
</li>
<li><p>Include database considerations in code reviews</p>
</li>
</ul>
<h3 id="heading-why-this-example-matters">Why This Example Matters</h3>
<p>The difference between a shallow fix and a real solution is depth.</p>
<p>The first explanation often feels sufficient, especially under pressure. But stopping there means the issue is likely to return in a different form.</p>
<p>The value of the 5 Whys comes from following the chain all the way to something you can change in your system.</p>
<h2 id="heading-when-to-use-and-when-not-to-use-5-whys">When to Use (and When Not to Use) 5 Whys</h2>
<p>Like any problem-solving method, the 5 Whys is useful in the right context and less effective in others. Knowing when to apply it is just as important as knowing how to use it.</p>
<p>If used appropriately, it can uncover meaningful insights. If used in the wrong situation, it can lead to oversimplified or misleading conclusions</p>
<h3 id="heading-when-to-use-5-whys">When to Use 5 Whys</h3>
<p>The 5 Whys is most useful when your goal is to understand <strong>why something happened</strong>, not just to fix it and move on.</p>
<p>It works well in situations where problems are recurring or not fully explained by the first answer. For example, production incidents, repeated bugs, or issues that reappear after a quick fix are strong signals that you need deeper analysis. In these cases, the technique helps uncover what is happening beneath the surface.</p>
<p>It's also effective during retrospectives and postmortems. When a release doesn't go as expected or a sprint runs into issues, the 5 Whys helps teams move beyond observations like "this failed" and get to "why did this fail in the first place".</p>
<p>In general, use it when:</p>
<ul>
<li><p>The problem is not obvious</p>
</li>
<li><p>The issue has occurred more than once</p>
</li>
<li><p>You want to prevent recurrence, not just resolve the current instance</p>
</li>
</ul>
<h3 id="heading-when-not-to-use-5-whys">When Not to Use 5 Whys</h3>
<p>The 5 Whys has its limits, and using it in the wrong context can lead to oversimplified conclusions.</p>
<p>If a problem involves multiple interacting factors, a single chain of "why" questions may not capture the full picture. Complex systems often have several contributing causes, and forcing them into one linear explanation can hide important details. In such cases, the 5 Whys should be combined with other approaches.</p>
<p>It's also less effective when there's not enough data. If each answer is based on assumptions rather than evidence, the analysis quickly becomes unreliable. The method depends on validation at every step.</p>
<p>Another limitation is in time-critical situations. During an active incident, the priority is to restore the system. The deeper analysis should happen later, once things are stable.</p>
<p>Finally, if your goal is quantitative analysis or optimization, the 5 Whys alone isn't enough. You'll need more data-driven methods to support decision making.</p>
<p>A simple rule of thumb is this. If you are trying to <strong>learn from a problem</strong>, use the 5 Whys. If you are trying to <strong>fix something immediately or analyze complex data</strong>, use it carefully or alongside other techniques.</p>
<h2 id="heading-benefits-of-the-5-whys-technique">Benefits of the 5 Whys Technique</h2>
<p>The 5 Whys technique is simple, but it offers several powerful benefits that can help you solve problems more effectively and make lasting improvements. Here are the key advantages:</p>
<h3 id="heading-simple-and-easy-to-apply">Simple and Easy to Apply</h3>
<p>One of the biggest strengths of the 5 Whys is how easy it is to start using. You don't need special tools, training, or complex frameworks. It can be applied in a quick discussion, during debugging, or as part of a formal postmortem.</p>
<p>This low barrier makes it accessible across teams, regardless of experience level.</p>
<h3 id="heading-encourages-deeper-thinking">Encourages Deeper Thinking</h3>
<p>The method naturally pushes you to go beyond the first explanation. Instead of reacting to what's visible, it encourages you to question why the problem occurred in the first place.</p>
<p>This shift from surface-level fixes to deeper understanding often leads to better decisions.</p>
<h3 id="heading-promotes-system-level-improvements">Promotes System-Level Improvements</h3>
<p>When used correctly, the focus moves away from individual people and toward systems. Instead of asking who made a mistake, the analysis asks what allowed the mistake to happen.</p>
<p>This leads to improvements in processes, safeguards, and overall system design rather than one-off fixes.</p>
<h3 id="heading-works-well-in-team-settings">Works Well in Team Settings</h3>
<p>Because the approach is simple, it's easy for multiple people to contribute. Different perspectives help uncover gaps that might otherwise be missed.</p>
<p>It also creates a shared understanding of the problem, which is valuable during retrospectives and incident reviews.</p>
<h3 id="heading-helps-prevent-recurring-issues">Helps Prevent Recurring Issues</h3>
<p>Quick fixes often solve the immediate problem but don't stop it from happening again. The 5 Whys helps identify underlying causes, which makes it easier to prevent similar issues in the future.</p>
<p>Over time, this leads to more stable systems and fewer repeated incidents.</p>
<h2 id="heading-common-pitfalls-and-limitations">Common Pitfalls and Limitations</h2>
<p>While the 5 Whys technique is useful, it’s not always perfect. There are some limitations to keep in mind, so you can use it effectively and know when it might not be enough.</p>
<h3 id="heading-stopping-too-early">Stopping Too Early</h3>
<p>One of the most common mistakes is ending the analysis after the first or second answer. These early answers usually describe symptoms, not causes.</p>
<p>Stopping too soon leads to fixes that address the surface but leave the underlying issue unresolved.</p>
<h3 id="heading-treating-assumptions-as-facts">Treating Assumptions as Facts</h3>
<p>It's easy to come up with explanations that sound reasonable. But without evidence, they're just assumptions.</p>
<p>If each step isn't validated with logs, metrics, or observations, the entire analysis can drift away from reality.</p>
<h3 id="heading-focusing-on-individuals-instead-of-systems">Focusing on Individuals Instead of Systems</h3>
<p>Answers like "someone made a mistake" don't add much value. While they may be true, they don't explain why the system allowed that mistake to have an impact.</p>
<p>Focusing on processes and safeguards leads to more meaningful improvements.</p>
<h3 id="heading-oversimplifying-complex-problems">Oversimplifying Complex Problems</h3>
<p>The 5 Whys follows a linear chain of reasoning, but real-world systems often have multiple contributing factors.</p>
<p>Relying on a single chain can hide important interactions. In such cases, the method should be combined with other approaches.</p>
<h3 id="heading-treating-it-as-a-rigid-formula">Treating It as a Rigid Formula</h3>
<p>The name suggests asking "why" five times, but this shouldn't be taken literally. Some problems require fewer steps, while others need more.</p>
<p>Forcing the structure can lead to artificial or weak conclusions.</p>
<h3 id="heading-not-a-replacement-for-deeper-analysis">Not a Replacement for Deeper Analysis</h3>
<p>The 5 Whys isn't designed for every type of problem. For complex system failures, performance optimization, or data-heavy investigations, additional tools and methods are often required.</p>
<p>It works best as a starting point or a complement to other techniques, not a complete solution on its own.</p>
<h2 id="heading-tips-for-using-5-whys-effectively">Tips for Using 5 Whys Effectively</h2>
<p>To get the most out of the 5 Whys technique, there are a few tips that can help you use it effectively. These will guide you to ask the right questions and reach useful, actionable insights.</p>
<h3 id="heading-start-with-a-clear-specific-problem">Start with a Clear, Specific Problem</h3>
<p>A vague problem leads to vague answers. Spend a little extra time making sure the problem statement is precise and based on observable facts. This keeps the analysis grounded and avoids unnecessary detours.</p>
<h3 id="heading-base-every-step-on-evidence">Base Every Step on Evidence</h3>
<p>Treat each answer as something that needs to be verified. Use logs, metrics, recent changes, or direct observations to support your reasoning. If something can't be validated, call it out as a hypothesis and confirm it before moving forward.</p>
<h3 id="heading-keep-the-chain-logical-and-connected">Keep the Chain Logical and Connected</h3>
<p>Each "why" should naturally follow from the previous answer. If the reasoning starts to jump between unrelated ideas, pause and re-evaluate. A clean, logical chain is a strong indicator that you're on the right track.</p>
<h3 id="heading-focus-on-systems-not-individuals">Focus on Systems, Not Individuals</h3>
<p>Avoid stopping at explanations that point to human error. Instead, ask what allowed that error to have an impact. This shift in thinking leads to improvements that actually reduce the chances of similar issues in the future.</p>
<h3 id="heading-do-not-force-exactly-five-steps">Do Not Force Exactly Five Steps</h3>
<p>The number five is a guideline, not a rule. Some problems become clear in three steps, while others need more exploration. Stop when you reach a cause that's both convincing and actionable.</p>
<h3 id="heading-involve-the-right-people">Involve the Right People</h3>
<p>If possible, do the analysis as a group. People from different parts of the system bring different perspectives, which helps uncover details that might otherwise be missed. It also creates shared ownership of both the problem and the solution.</p>
<h3 id="heading-turn-insights-into-actions">Turn Insights into Actions</h3>
<p>The analysis only matters if it leads to change. Make sure the final outcome includes clear, practical steps that address the root cause. Without this, even a well-done analysis has limited impact.</p>
<h2 id="heading-summary">Summary</h2>
<p>The 5 Whys is a simple technique, but using it well takes some discipline.</p>
<p>At its core, it's about resisting the urge to stop at the first explanation. By following the chain of cause and effect, you move from symptoms to something you can actually fix. In many cases, that turns out to be a gap in a process rather than a one-off failure.</p>
<p>When applied thoughtfully, it helps teams learn from problems instead of just reacting to them. Over time, this leads to better systems, fewer recurring issues, and more confidence in how problems are handled.</p>
<p>The key is to treat it as a way of thinking, not just a set of steps.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Build a Website Screenshot Generator with Python and Flask ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever needed to take screenshots of websites automatically – maybe to track visual changes, include them in reports, or generate previews? Doing this manually can be time-consuming, especially if you need to capture multiple pages regularly. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-website-screenshot-generator-with-python-and-flask/</link>
                <guid isPermaLink="false">690245c804c1e198e965b3ef</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Wed, 29 Oct 2025 16:50:16 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761756575904/17a940c5-352e-47a2-992e-a1973c030c05.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever needed to take screenshots of websites automatically – maybe to track visual changes, include them in reports, or generate previews? Doing this manually can be time-consuming, especially if you need to capture multiple pages regularly.</p>
<p>In this tutorial, you’ll learn how to build a simple website screenshot generator using Python and Flask. The app will let users enter any website URL and instantly get a screenshot of that page – all powered by a screenshot API.</p>
<p>You’ll use <a target="_blank" href="https://blog.ashutoshkrris.in/getting-started-with-flask"><strong>Flask</strong></a>, a lightweight web framework, to create a simple web interface and handle requests. Then, you’ll integrate an external API to capture website screenshots programmatically.</p>
<p>By the end of this tutorial, you’ll have learned how to:</p>
<ul>
<li><p>Build a basic Flask web app</p>
</li>
<li><p>Accept user input through an HTML form</p>
</li>
<li><p>Make HTTP requests to an external API</p>
</li>
<li><p>Display images dynamically on a web page</p>
</li>
</ul>
<p>This project is a great way to learn how APIs can extend the capabilities of your web applications, and how Python can easily handle tasks like image generation and display.</p>
<h3 id="heading-what-well-cover">What we’ll cover:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-setting-up-the-project">Setting Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-integrating-the-screenshotbase-api">Integrating the ScreenshotBase API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-adding-customization-options">Adding Customization Options</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we start building the app, make sure you have a few basics covered:</p>
<h3 id="heading-1-python-installed">1. Python Installed</h3>
<p>You’ll need Python 3.9 or higher installed on your machine. You can check your version by running:</p>
<pre><code class="lang-bash">python --version
</code></pre>
<p>If you don’t have it, you can download it from <a target="_blank" href="https://www.python.org/downloads/">python.org/downloads</a>.</p>
<h3 id="heading-2-basic-knowledge-of-python-and-flask">2. Basic Knowledge of Python and Flask</h3>
<p>You don’t need to be a Flask expert. Just have some familiarity with how to create routes and templates, and how to handle form data in Flask.</p>
<p>If you’re new to Flask, don’t worry – we’ll go step-by-step.</p>
<h3 id="heading-3-screenshot-api-key">3. Screenshot API Key</h3>
<p>We’ll be using the <a target="_blank" href="https://screenshotbase.com/"><strong>ScreenshotBase API</strong></a> to capture website screenshots. It provides a simple REST endpoint that takes a URL and returns a screenshot image.</p>
<p>You can get a free API key by signing up on their website. Once you have the key, keep it handy, as we’ll use it when we integrate the API in the later steps.</p>
<h3 id="heading-4-a-code-editor-and-terminal">4. A Code Editor and Terminal</h3>
<p>You can use any editor you prefer, like VS Code, PyCharm, or even a simple text editor. Make sure your terminal or command prompt can run Python commands and install packages using <code>pip</code>.</p>
<h2 id="heading-setting-up-the-project">Setting Up the Project</h2>
<p>Let’s start by setting up a new Flask project from scratch.</p>
<h3 id="heading-step-1-create-a-new-folder">Step 1: Create a New Folder</h3>
<p>Create a new folder for your project. You can name it <code>screenshot-generator</code>:</p>
<pre><code class="lang-bash">mkdir screenshot-generator
<span class="hljs-built_in">cd</span> screenshot-generator
</code></pre>
<h3 id="heading-step-2-create-a-virtual-environment">Step 2: Create a Virtual Environment</h3>
<p>A virtual environment helps keep your project dependencies isolated from other Python projects.</p>
<p>Run the following commands:</p>
<pre><code class="lang-bash">python -m venv venv
</code></pre>
<p>Then activate it:</p>
<ul>
<li><p>On macOS/Linux:</p>
<pre><code class="lang-bash">  <span class="hljs-built_in">source</span> venv/bin/activate
</code></pre>
</li>
<li><p>On Windows:</p>
<pre><code class="lang-bash">  venv\Scripts\activate
</code></pre>
</li>
</ul>
<p>Once activated, you should see <code>(venv)</code> at the beginning of your terminal prompt.</p>
<h3 id="heading-step-3-install-dependencies">Step 3: Install Dependencies</h3>
<p>We’ll need two packages for this project:</p>
<ul>
<li><p><strong>Flask</strong> for building the web app</p>
</li>
<li><p><strong>Requests</strong> for making API calls to ScreenshotBase</p>
</li>
</ul>
<p>Install them using pip:</p>
<pre><code class="lang-bash">pip install flask requests
</code></pre>
<h3 id="heading-step-4-set-up-the-project-structure">Step 4: Set Up the Project Structure</h3>
<p>Inside your project folder, create the following files and folders:</p>
<pre><code class="lang-bash">screenshot-generator/
├── app.py
├── templates/
│   └── index.html
└── static/
</code></pre>
<p>Here’s what each part does:</p>
<ul>
<li><p><code>app.py</code>: main Python file that runs your Flask app</p>
</li>
<li><p><code>templates/</code>: stores HTML templates</p>
</li>
<li><p><code>static/</code>: stores images, CSS, and JavaScript files</p>
</li>
</ul>
<h3 id="heading-step-5-add-a-basic-flask-app">Step 5: Add a Basic Flask App</h3>
<p>Open <code>app.py</code> and add the following starter code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, render_template, request
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> os

app = Flask(__name__)
API_KEY = os.getenv(<span class="hljs-string">"SCREENSHOTBASE_API_KEY"</span>)
SCREENSHOTBASE_BASE_ENDPOINT = <span class="hljs-string">"https://api.screenshotbase.com/v1/take"</span>

<span class="hljs-meta">@app.route('/', methods=['GET', 'POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">home</span>():</span>
    <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">'POST'</span>:
        url = request.form.get(<span class="hljs-string">'url'</span>)
        <span class="hljs-comment"># Placeholder: We’ll add the API call here in the next section</span>
        <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>, url=url)
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<p>This sets up a minimal Flask application with one route (<code>/</code>). We’ll add the ScreenshotBase API call in the next section.</p>
<h3 id="heading-step-6-create-a-simple-html-template">Step 6: Create a Simple HTML Template</h3>
<p>Now that we’ve written the Flask backend to handle the screenshot request, let’s create the frontend for our app.</p>
<p>Inside your project folder, create a new directory named <code>templates</code>, and within it, add a file called <code>index.html</code>. Flask will automatically look for templates in this folder.</p>
<p>Here’s how the template should look:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Website Screenshot Generator<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
      <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB"</span>
      <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-tag">body</span> {
            <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">2rem</span>;
        }
        <span class="hljs-selector-class">.screenshot-container</span> {
            <span class="hljs-attribute">max-height</span>: <span class="hljs-number">80vh</span>;
            <span class="hljs-attribute">overflow-y</span>: auto;
            <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ddd</span>;
            <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
            <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
            <span class="hljs-attribute">background</span>: <span class="hljs-number">#f8f9fa</span>;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container text-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>Website Screenshot Generator<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex justify-content-center mb-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> 
                <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> 
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter website URL"</span> 
                <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control w-50 me-2"</span>
                <span class="hljs-attr">required</span>
            &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>Capture Screenshot<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

        {% if screenshot %}
            <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>Screenshot Preview:<span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"screenshot-container mx-auto"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"{{ screenshot }}"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Website Screenshot"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"img-fluid rounded shadow"</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {% elif request.method == 'POST' %}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger mt-3"</span>&gt;</span>
                Sorry, something went wrong while capturing the screenshot. Please try again.
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {% endif %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This HTML template uses Bootstrap to keep the design clean and responsive without much custom styling. The form at the top allows users to enter any website URL and submit it to the Flask app using the <code>POST</code> method. Once the app retrieves the screenshot URL from the API, it dynamically renders the image on the page.</p>
<p>The <code>img-fluid</code> class from Bootstrap ensures the screenshot scales properly across all screen sizes while maintaining its aspect ratio. Also, the <code>.screenshot-container</code> provides a scrollable area, which helps display full-page screenshots without shrinking them too much or breaking the layout.</p>
<p>Now your project is set up and ready to capture real screenshots using the ScreenshotBase API.</p>
<p>In the next section, we’ll write the logic to call the ScreenshotBase API and display the resulting screenshot dynamically in the browser.</p>
<h2 id="heading-integrating-the-screenshotbase-api">Integrating the ScreenshotBase API</h2>
<p>Now that our Flask app is set up, let’s connect it to the ScreenshotBase API so we can generate real screenshots from any URL.</p>
<h3 id="heading-step-1-understanding-the-api-endpoint">Step 1: Understanding the API Endpoint</h3>
<p>The ScreenshotBase API provides a simple endpoint that takes a website URL and returns a screenshot image.</p>
<p>A typical API call looks like this:</p>
<pre><code class="lang-bash">GET https://api.screenshotbase.com/v1/take
</code></pre>
<p>You send the target website URL as a query parameter (<code>url</code>) and include your API key in the request header as <code>apikey</code>.</p>
<p>Here’s the cURL example from their documentation:</p>
<pre><code class="lang-bash">curl -G https://api.screenshotbase.com/v1/take?url=https%3A%2F%2Fbbc.com \
    -H <span class="hljs-string">"apikey: YOUR-API-KEY"</span>
</code></pre>
<p>This request captures a screenshot of <code>https://bbc.com</code> and returns the screenshot image as the response.</p>
<h3 id="heading-step-2-add-the-api-call-in-flask">Step 2: Add the API Call in Flask</h3>
<p>Let’s update our <code>home</code> route in <code>app.py</code> to send a request to the ScreenshotBase API when a user submits a URL.</p>
<p>Here’s the updated version of <code>app.py</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, render_template, request
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> os

app = Flask(__name__)
API_KEY = os.getenv(<span class="hljs-string">"SCREENSHOTBASE_API_KEY"</span>)
SCREENSHOTBASE_BASE_ENDPOINT = <span class="hljs-string">"https://api.screenshotbase.com/v1/take"</span>

<span class="hljs-meta">@app.route('/', methods=['GET', 'POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">home</span>():</span>
    screenshot_url = <span class="hljs-literal">None</span>

    <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">'POST'</span>:
        target_url = request.form.get(<span class="hljs-string">'url'</span>)

        params = {<span class="hljs-string">"url"</span>: target_url}
        headers = {<span class="hljs-string">"apikey"</span>: API_KEY}

        <span class="hljs-keyword">try</span>:
            <span class="hljs-comment"># Send GET request to ScreenshotBase API</span>
            response = requests.get(SCREENSHOTBASE_BASE_ENDPOINT, params=params, headers=headers, timeout=<span class="hljs-number">30</span>)
            response.raise_for_status()

            <span class="hljs-comment"># Save the returned image</span>
            image_path = os.path.join(<span class="hljs-string">'static'</span>, <span class="hljs-string">'screenshot.png'</span>)
            <span class="hljs-keyword">with</span> open(image_path, <span class="hljs-string">'wb'</span>) <span class="hljs-keyword">as</span> f:
                f.write(response.content)

            screenshot_url = image_path

        <span class="hljs-keyword">except</span> requests.exceptions.RequestException <span class="hljs-keyword">as</span> e:
            print(<span class="hljs-string">f"Error capturing screenshot: <span class="hljs-subst">{e}</span>"</span>)

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>, screenshot=screenshot_url)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<p>Here’s what this code does:</p>
<ol>
<li><p>Captures the user input (URL).</p>
</li>
<li><p>Sends a GET request to the <code>/v1/take</code> endpoint.</p>
</li>
<li><p>Passes your API key in the request header (<code>apikey</code>).</p>
</li>
<li><p>Saves the returned image to the <code>static</code> folder.</p>
</li>
<li><p>Displays the screenshot on the page.</p>
</li>
</ol>
<h3 id="heading-step-3-test-your-app">Step 3: Test Your App</h3>
<p>Run the app again:</p>
<pre><code class="lang-python">python app.py
</code></pre>
<p>Then open <a target="_blank" href="http://127.0.0.1:5000">http://127.0.0.1:5000</a> in your browser.</p>
<p>Enter a URL like:</p>
<pre><code class="lang-python">https://github.com/ashutoshkrris
</code></pre>
<p>After submitting, you should see the screenshot of that website displayed below the form.</p>
<p>Your Flask app is now fully functional! It takes a URL, sends it to the ScreenshotBase API, and displays the resulting screenshot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761133080971/d0feb78c-09cb-4f01-b254-a56fca3a58c8.png" alt="d0feb78c-09cb-4f01-b254-a56fca3a58c8" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>In the next section, we’ll enhance the app by adding customization options like full-page screenshots, viewport settings, and delays. Later, we’ll explore the ScreenshotBase SDKs for popular languages like Python, Node.js, and PHP.</p>
<h2 id="heading-adding-customization-options">Adding Customization Options</h2>
<p>Right now, our app simply takes a screenshot of the given website URL using the default settings. However, most screenshot APIs (including the one we’re using) allow you to customize the output by passing additional parameters in the request.</p>
<p>The ScreenshotBase API offers several powerful customization options to help you tailor each screenshot to your needs:</p>
<ul>
<li><p><strong>Image format</strong>: Choose from <code>png</code>, <code>jpg</code>, <code>gif</code>, or <code>webp</code>, depending on your image quality or compression requirements.</p>
</li>
<li><p><strong>Full page capture</strong>: Capture the entire scrollable webpage (<code>full_page=1</code>) or just the visible viewport (<code>full_page=0</code>).</p>
</li>
<li><p><strong>Viewport dimensions</strong>: Set the browser window size with <code>viewport_width</code> and <code>viewport_height</code> to simulate screenshots from desktop, tablet, or mobile screens.</p>
</li>
</ul>
<p>These options make ScreenshotBase ideal for building automation tools, thumbnail generators, testing dashboards, and visual documentation systems. Let’s add these options to make our screenshot generator more flexible.</p>
<h3 id="heading-updating-the-flask-code">Updating the Flask Code</h3>
<p>Open your <code>app.py</code> file and update the route that handles form submissions to include these optional parameters:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, render_template, request
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> os

app = Flask(__name__)
API_KEY = os.getenv(<span class="hljs-string">"SCREENSHOTBASE_API_KEY"</span>, <span class="hljs-string">"scr_live_9Qkn1gs01rivZqrFk7lusXPiqAUg85J86aU6bHvG"</span>)
SCREENSHOTBASE_BASE_ENDPOINT = <span class="hljs-string">"https://api.screenshotbase.com/v1/take"</span>


<span class="hljs-meta">@app.route('/', methods=['GET', 'POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">home</span>():</span>
    screenshot_url = <span class="hljs-literal">None</span>

    <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">'POST'</span>:
        target_url = request.form.get(<span class="hljs-string">'url'</span>)
        format_ = request.form.get(<span class="hljs-string">'format'</span>, <span class="hljs-string">'png'</span>)
        full_page = request.form.get(<span class="hljs-string">'full_page'</span>) == <span class="hljs-string">'on'</span>

        params = {
            <span class="hljs-string">"url"</span>: target_url,
            <span class="hljs-string">"format"</span>: format_,
            <span class="hljs-string">"full_page"</span>: int(full_page)
        }
        headers = {<span class="hljs-string">"apikey"</span>: API_KEY}

        <span class="hljs-keyword">try</span>:
            <span class="hljs-comment"># Send GET request to ScreenshotBase API</span>
            response = requests.get(SCREENSHOTBASE_BASE_ENDPOINT, params=params, headers=headers, timeout=<span class="hljs-number">30</span>)
            response.raise_for_status()

            <span class="hljs-comment"># Save the returned image</span>
            image_extension = format_ <span class="hljs-keyword">if</span> format_ != <span class="hljs-string">'jpeg'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'jpg'</span>
            image_path = os.path.join(<span class="hljs-string">'static'</span>, <span class="hljs-string">f'screenshot.<span class="hljs-subst">{image_extension}</span>'</span>)
            <span class="hljs-keyword">with</span> open(image_path, <span class="hljs-string">'wb'</span>) <span class="hljs-keyword">as</span> f:
                f.write(response.content)

            screenshot_url = image_path

        <span class="hljs-keyword">except</span> requests.exceptions.RequestException <span class="hljs-keyword">as</span> e:
            print(<span class="hljs-string">f"Error capturing screenshot: <span class="hljs-subst">{e}</span>"</span>)

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>, screenshot=screenshot_url)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<h3 id="heading-updating-the-html-template">Updating the HTML Template</h3>
<p>Next, let’s modify the form in our <code>index.html</code> to include the customization options:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex flex-column justify-content-center mb-4"</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- URL and Submit Button in One Row --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input-group mb-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
      <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span>
      <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter website URL"</span>
      <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control w-50 me-2"</span>
      <span class="hljs-attr">required</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>Capture Screenshot<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Options in Two Columns --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row g-3"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Full Page Checkbox --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-6"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-check"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"full_page"</span>
          <span class="hljs-attr">id</span>=<span class="hljs-string">"full_page"</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"form-check-input"</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-check-label"</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"full_page"</span>&gt;</span>
          Capture Full Page Screenshot
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Format Dropdown --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-6"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"format"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-label"</span>&gt;</span>Screenshot Format<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-select"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"format"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"format"</span> <span class="hljs-attr">required</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"png"</span>&gt;</span>PNG<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"jpg"</span>&gt;</span>JPG<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"gif"</span>&gt;</span>GIF<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"webp"</span>&gt;</span>WEBP<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Viewport Width --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-6"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"viewport_width"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-label"</span>&gt;</span>Viewport Width<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport_width"</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"viewport_width"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">"1280"</span>
        <span class="hljs-attr">min</span>=<span class="hljs-string">"320"</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Viewport Height --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-6"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"viewport_height"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-label"</span>&gt;</span>Viewport Height<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport_height"</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"viewport_height"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">"720"</span>
        <span class="hljs-attr">min</span>=<span class="hljs-string">"320"</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>The updated form gives users control over how the screenshot is generated. The format dropdown lets them choose between PNG, JPG, GIF, or WEBP. The Full Page checkbox toggles whether the API captures the entire scrollable webpage or just the visible viewport. The viewport width and height fields define the browser window dimensions, which is useful if you want to simulate different device sizes or responsive layouts.</p>
<p>When the form is submitted, Flask reads these values and sends them as query parameters in the API request.</p>
<p>For example, a request to capture a full-page, 1920×1080 PNG screenshot of your site would look like this:</p>
<pre><code class="lang-xml">https://api.screenshotbase.com/v1/take?url=https%3A%2F%2Fgithub.com%2Fashutoshkrris&amp;format=png&amp;full_page=1&amp;viewport_width=1920&amp;viewport_height=1080
</code></pre>
<p>This flexibility makes it easy to fine-tune screenshots for different use cases – whether you’re generating thumbnails, testing responsiveness, or automating visual reports.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761134646387/b9145271-303f-408e-ab53-444ea125849e.gif" alt="b9145271-303f-408e-ab53-444ea125849e" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Note: If you prefer working with SDKs instead of direct API calls, ScreenshotBase also offers official SDKs for popular languages like Python, JavaScript, Ruby, PHP, and Go.</p>
<p>These SDKs provide a simpler and more convenient way to interact with the API, handling authentication and request formatting behind the scenes.</p>
<p>You can explore them in the <a target="_blank" href="https://screenshotbase.com/docs/sdks">ScreenshotBase SDK documentation</a>.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this tutorial, you learned how to build a simple Flask application that captures website screenshots using a third-party API. We explored how to send requests, handle image responses, and add customization options like image format, full-page capture, and viewport size – all while keeping the project lightweight and easy to extend.</p>
<p>This small project demonstrates how web automation tasks, such as generating previews or visual reports, can be simplified using modern APIs. You can build upon this foundation to create batch screenshot tools, visual monitoring systems, or even integrate screenshots into larger web applications.</p>
<p>The key takeaway is understanding how to interact with external APIs, process responses, and design a clean interface for users. These are skills that are essential for backend and full-stack developers alike.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Work with SQLite in Python – A Handbook for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ SQLite is one of the most popular relational database management systems (RDBMS). It’s lightweight, meaning that it doesn’t take up much space on your system. One of its best features is that it’s serverless, so you don’t need to install or manage a ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/work-with-sqlite-in-python-handbook/</link>
                <guid isPermaLink="false">66fd1605986ae3c9e56b8ba4</guid>
                
                    <category>
                        <![CDATA[ SQLite ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Wed, 02 Oct 2024 09:44:37 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727862097228/24433377-ebb8-49b5-b0ee-5736f629399d.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>SQLite is one of the most popular relational database management systems (RDBMS). It’s lightweight, meaning that it doesn’t take up much space on your system. One of its best features is that it’s serverless, so you don’t need to install or manage a separate server to use it.</p>
<p>Instead, it stores everything in a simple file on your computer. It also requires zero configuration, so there’s no complicated setup process, making it perfect for beginners and small projects.</p>
<p>SQLite is a great choice for small to medium applications because it’s easy to use, fast, and can handle most tasks that bigger databases can do, but without the hassle of managing extra software. Whether you're building a personal project or prototyping a new app, SQLite is a solid option to get things up and running quickly.</p>
<p>In this tutorial, you'll learn how to work with SQLite using Python. Here’s what we’re going to cover in this tutorial:</p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-your-python-environment">How to Set Up Your Python Environment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-an-sqlite-database">How to Create an SQLite Database</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-database-tables">How to Create Database Tables</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-insert-data-into-a-table">How to Insert Data into a Table</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-query-data">How to Query Data</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-update-and-delete-data">How to Update and Delete Data</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-transactions">How to Use Transactions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-optimize-sqlite-query-performance-with-indexing">How to Optimize SQLite Query Performance with Indexing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-handle-errors-and-exceptions">How to Handle Errors and Exceptions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-export-and-import-data-bonus-section">How to Export and Import Data [Bonus Section]</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<p>This tutorial is perfect for anyone who wants to get started with databases without diving into complex setups.</p>
<h2 id="heading-how-to-set-up-your-python-environment">How to Set Up Your Python Environment</h2>
<p>Before working with SQLite, let’s ensure your Python environment is ready. Here’s how to set everything up.</p>
<h3 id="heading-installing-python">Installing Python</h3>
<p>If you don’t have Python installed on your system yet, you can download it from the official <a target="_blank" href="https://www.python.org/downloads/">Python website</a>. Follow the installation instructions for your operating system (Windows, macOS, or Linux).</p>
<p>To check if Python is installed, open your terminal (or command prompt) and type:</p>
<pre><code class="lang-bash">python --version
</code></pre>
<p>This should show the current version of Python installed. If it’s not installed, follow the instructions on the Python website.</p>
<h3 id="heading-installing-sqlite3-module">Installing SQLite3 Module</h3>
<p>The good news is that SQLite3 comes built-in with Python! You don’t need to install it separately because it’s included in the standard Python library. This means you can start using it right away without any additional setup.</p>
<h3 id="heading-how-to-create-a-virtual-environment-optional-but-recommended">How to Create a Virtual Environment (Optional but Recommended)</h3>
<p>It’s a good idea to create a virtual environment for each project to keep your dependencies organized. A virtual environment is like a clean slate where you can install packages without affecting your global Python installation.</p>
<p>To create a virtual environment, follow these steps:</p>
<ol>
<li><p>First, open your terminal or command prompt and navigate to the directory where you want to create your project.</p>
</li>
<li><p>Run the following command to create a virtual environment:</p>
</li>
</ol>
<pre><code class="lang-bash">python -m venv env
</code></pre>
<p>Here, <code>env</code> is the name of the virtual environment. You can name it anything you like.</p>
<ol start="3">
<li>Activate the virtual environment:</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-comment"># Use the command for Windows</span>
env\Scripts\activate

<span class="hljs-comment"># Use the command for macOS/Linux:</span>
env/bin/activate
</code></pre>
<p>After activating the virtual environment, you’ll notice that your terminal prompt changes, showing the name of the virtual environment. This means you’re now working inside it.</p>
<h3 id="heading-installing-necessary-libraries">Installing Necessary Libraries</h3>
<p>We’ll need a few additional libraries for this project. Specifically, we’ll use:</p>
<ul>
<li><p><code>pandas</code>: This is an optional library for handling and displaying data in tabular format, useful for advanced use cases.</p>
</li>
<li><p><code>faker</code>: This library will help us generate fake data, like random names and addresses, which we can insert into our database for testing.</p>
</li>
</ul>
<p>To install <code>pandas</code> and <code>faker</code>, simply run the following commands:</p>
<pre><code class="lang-bash">pip install pandas faker
</code></pre>
<p>This installs both <code>pandas</code> and <code>faker</code> into your virtual environment. With this, your environment is set up, and you’re ready to start creating and managing your SQLite database in Python!</p>
<h2 id="heading-how-to-create-an-sqlite-database">How to Create an SQLite Database</h2>
<p>A database is a structured way to store and manage data so that it can be easily accessed, updated, and organized. It’s like a digital filing system that allows you to efficiently store large amounts of data, whether it’s for a simple app or a more complex system. Databases use tables to organize data, with rows and columns representing individual records and their attributes.</p>
<h3 id="heading-how-sqlite-databases-work">How SQLite Databases Work</h3>
<p>Unlike most other database systems, SQLite is a serverless database. This means that it doesn’t require setting up or managing a server, making it lightweight and easy to use. All the data is stored in a single file on your computer, which you can easily move, share, or back up. Despite its simplicity, SQLite is powerful enough to handle many common database tasks and is widely used in mobile apps, embedded systems, and small to medium-sized projects.</p>
<h3 id="heading-how-to-create-a-new-sqlite-database">How to Create a New SQLite Database</h3>
<p>Let’s create a new SQLite database and learn how to interact with it using Python’s <code>sqlite3</code> library.</p>
<h4 id="heading-connecting-to-the-database">Connecting to the Database</h4>
<p>Since <code>sqlite3</code> is pre-installed, you just need to import it in your Python script. To create a new database or connect to an existing one, we use the <code>sqlite3.connect()</code> method. This method takes the name of the database file as an argument. If the file doesn’t exist, SQLite will automatically create it.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Connect to the SQLite database (or create it if it doesn't exist)</span>
connection = sqlite3.connect(<span class="hljs-string">'my_database.db'</span>)
</code></pre>
<p>In this example, a file named <code>my_database.db</code> is created in the same directory as your script. If the file already exists, SQLite will just open the connection to it.</p>
<h4 id="heading-creating-a-cursor">Creating a Cursor</h4>
<p>Once you have a connection, the next step is to create a cursor object. The cursor is responsible for executing SQL commands and queries on the database.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create a cursor object</span>
cursor = connection.cursor()
</code></pre>
<h4 id="heading-closing-the-connection">Closing the Connection</h4>
<p>After you’ve finished working with the database, it’s important to close the connection to free up any resources. You can close the connection with the following command:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Close the database connection</span>
connection.close()
</code></pre>
<p>However, you should only close the connection once you’re done with all your operations.</p>
<p>When you run your Python script, a file named <code>my_database.db</code> will be created in your current working directory. You’ve now successfully created your first SQLite database!</p>
<h3 id="heading-how-to-use-context-manager-to-open-and-close-connections">How to Use Context Manager to Open and Close Connections</h3>
<p>Python provides a more efficient and cleaner way to handle database connections using the <code>with</code> statement, also known as a context manager. The <code>with</code> statement automatically opens and closes the connection, ensuring that the connection is properly closed even if an error occurs during the database operations. This eliminates the need to manually call <code>connection.close()</code>.</p>
<p>Here’s how you can use the <code>with</code> statement to handle database connections:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Step 1: Use 'with' to connect to the database (or create one) and automatically close it when done</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:

    <span class="hljs-comment"># Step 2: Create a cursor object to interact with the database</span>
    cursor = connection.cursor()

    print(<span class="hljs-string">"Database created and connected successfully!"</span>)

<span class="hljs-comment"># No need to call connection.close(); it's done automatically!</span>
</code></pre>
<p>From now on, we’ll use the <code>with</code> statement in our upcoming code examples to manage database connections efficiently. This will make the code more concise and easier to maintain.</p>
<h2 id="heading-how-to-create-database-tables">How to Create Database Tables</h2>
<p>Now that we’ve created an SQLite database and connected to it, the next step is to create tables inside the database. A table is where we’ll store our data, organized in rows (records) and columns (attributes). For this example, we’ll create a table called <code>Students</code> to store information about students, which we’ll reuse in upcoming sections.</p>
<p>To create a table, we use SQL's <code>CREATE TABLE</code> statement. This command defines the table structure, including the column names and the data types for each column.</p>
<p>Here’s a simple SQL command to create a <code>Students</code> table with the following fields:</p>
<ul>
<li><p><code>id</code>: A unique identifier for each student (an integer).</p>
</li>
<li><p><strong>name</strong>: The student's name (text).</p>
</li>
<li><p><strong>age</strong>: The student's age (an integer).</p>
</li>
<li><p><strong>email</strong>: The student's email address (text).</p>
</li>
</ul>
<p>The SQL command to create this table would look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> Students (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">INTEGER</span> PRIMARY <span class="hljs-keyword">KEY</span> AUTOINCREMENT,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    age <span class="hljs-built_in">INTEGER</span>,
    email <span class="hljs-built_in">TEXT</span>
);
</code></pre>
<p>We can execute this <code>CREATE TABLE</code> SQL command in Python using the <code>sqlite3</code> library. Let’s see how to do that.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database and automatically close the connection when done</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:

    <span class="hljs-comment"># Create a cursor object</span>
    cursor = connection.cursor()

    <span class="hljs-comment"># Write the SQL command to create the Students table</span>
    create_table_query = <span class="hljs-string">'''
    CREATE TABLE IF NOT EXISTS Students (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        age INTEGER,
        email TEXT
    );
    '''</span>

    <span class="hljs-comment"># Execute the SQL command</span>
    cursor.execute(create_table_query)

    <span class="hljs-comment"># Commit the changes</span>
    connection.commit()

    <span class="hljs-comment"># Print a confirmation message</span>
    print(<span class="hljs-string">"Table 'Students' created successfully!"</span>)
</code></pre>
<ul>
<li><p><code>IF NOT EXISTS</code>: This ensures that the table is only created if it doesn’t already exist, preventing errors if the table has been created before.</p>
</li>
<li><p><code>connection.commit()</code>: This saves (commits) the changes to the database.</p>
</li>
</ul>
<p>When you run the Python code above, it will create the <code>Students</code> table in the <code>my_database.db</code> database file. You’ll also see a message in the terminal confirming that the table has been created successfully.</p>
<p>If you’re using Visual Studio Code, you can install the <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=qwtel.sqlite-viewer">SQLite Viewer</a> extension to view SQLite databases.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727514353100/522fc6f1-0363-41ca-a76a-b730470cb64a.png" alt="SQLite Viewer - VS Code Extension" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-data-types-in-sqlite-and-their-mapping-to-python">Data Types in SQLite and Their Mapping to Python</h3>
<p>SQLite supports several data types, which we need to understand when defining our tables. Here’s a quick overview of common SQLite data types and how they map to Python types:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>SQLite Data Type</td><td>Description</td><td>Python Equivalent</td></tr>
</thead>
<tbody>
<tr>
<td><strong>INTEGER</strong></td><td>Whole numbers</td><td><code>int</code></td></tr>
<tr>
<td><strong>TEXT</strong></td><td>Text strings</td><td><code>str</code></td></tr>
<tr>
<td><strong>REAL</strong></td><td>Floating-point numbers</td><td><code>float</code></td></tr>
<tr>
<td><strong>BLOB</strong></td><td>Binary data (e.g., images, files)</td><td><code>bytes</code></td></tr>
<tr>
<td><strong>NULL</strong></td><td>Represents no value or missing data</td><td><code>None</code></td></tr>
</tbody>
</table>
</div><p>In our <code>Students</code> table:</p>
<ul>
<li><p><code>id</code> is of type <code>INTEGER</code>, which maps to Python’s <code>int</code>.</p>
</li>
<li><p><code>name</code> and <code>email</code> are of type <code>TEXT</code>, which map to Python’s <code>str</code>.</p>
</li>
<li><p><code>age</code> is also of type <code>INTEGER</code>, mapping to Python’s <code>int</code>.</p>
</li>
</ul>
<h2 id="heading-how-to-insert-data-into-a-table">How to Insert Data into a Table</h2>
<p>Now that we have our <code>Students</code> table created, it’s time to start inserting data into the database. In this section, we’ll cover how to insert both single and multiple records using Python and SQLite, and how to avoid common security issues like SQL injection by using parameterized queries.</p>
<h3 id="heading-how-to-insert-a-single-record">How to Insert a Single Record</h3>
<p>To insert data into the database, we use the <code>INSERT INTO</code> SQL command. Let’s start by inserting a single record into our <code>Students</code> table.</p>
<p>Here’s the basic SQL syntax for inserting a single record:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> Students (<span class="hljs-keyword">name</span>, age, email) 
<span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'John Doe'</span>, <span class="hljs-number">20</span>, <span class="hljs-string">'johndoe@example.com'</span>);
</code></pre>
<p>However, instead of writing SQL directly in our Python script with hardcoded values, we’ll use parameterized queries to make our code more secure and flexible. Parameterized queries help prevent SQL injection, a common attack where malicious users can manipulate the SQL query by passing harmful input.</p>
<p>Here’s how we can insert a single record into the <code>Students</code> table using a parameterized query:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to open and close the connection automatically</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    cursor = connection.cursor()

    <span class="hljs-comment"># Insert a record into the Students table</span>
    insert_query = <span class="hljs-string">'''
    INSERT INTO Students (name, age, email) 
    VALUES (?, ?, ?);
    '''</span>
    student_data = (<span class="hljs-string">'Jane Doe'</span>, <span class="hljs-number">23</span>, <span class="hljs-string">'jane@example.com'</span>)

    cursor.execute(insert_query, student_data)

    <span class="hljs-comment"># Commit the changes automatically</span>
    connection.commit()

    <span class="hljs-comment"># No need to call connection.close(); it's done automatically!</span>
    print(<span class="hljs-string">"Record inserted successfully!"</span>)
</code></pre>
<p>The <code>?</code> placeholders represent the values to be inserted into the table. The actual values are passed as a tuple (<code>student_data</code>) in the <code>cursor.execute()</code> method.</p>
<h3 id="heading-how-to-insert-multiple-records">How to Insert Multiple Records</h3>
<p>If you want to insert multiple records at once, you can use the <code>executemany()</code> method in Python. This method takes a list of tuples, where each tuple represents one record.</p>
<p>To make our example more dynamic, we can use the <code>Faker</code> library to generate random student data. This is useful for testing and simulating real-world scenarios.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> faker <span class="hljs-keyword">import</span> Faker
<span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Initialize Faker</span>
fake = Faker([<span class="hljs-string">'en_IN'</span>])

<span class="hljs-comment"># Use 'with' to open and close the connection automatically</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    cursor = connection.cursor()

    <span class="hljs-comment"># Insert a record into the Students table</span>
    insert_query = <span class="hljs-string">'''
    INSERT INTO Students (name, age, email) 
    VALUES (?, ?, ?);
    '''</span>
    students_data = [(fake.name(), fake.random_int(
        min=<span class="hljs-number">18</span>, max=<span class="hljs-number">25</span>), fake.email()) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">5</span>)]

    <span class="hljs-comment"># Execute the query for multiple records</span>
    cursor.executemany(insert_query, students_data)

    <span class="hljs-comment"># Commit the changes</span>
    connection.commit()

    <span class="hljs-comment"># Print confirmation message</span>
    print(<span class="hljs-string">"Fake student records inserted successfully!"</span>)
</code></pre>
<p>In this code:</p>
<ul>
<li><p><code>Faker()</code> generates random names, ages, and emails for students. Passing the locale(<code>[‘en_IN’]</code>) is optional.</p>
</li>
<li><p><code>cursor.executemany()</code>: This method allows us to insert multiple records at once, making the code more efficient.</p>
</li>
<li><p><code>students_data</code>: A list of tuples where each tuple represents one student’s data.</p>
</li>
</ul>
<h3 id="heading-how-to-handle-common-issues-sql-injection">How to Handle Common Issues: SQL Injection</h3>
<p>SQL injection is a security vulnerability where attackers can insert or manipulate SQL queries by providing harmful input. For example, an attacker might try to inject code like <code>'; DROP TABLE Students; --</code> to delete the table.</p>
<p>By using parameterized queries (as demonstrated above), we avoid this issue. The <code>?</code> placeholders in parameterized queries ensure that input values are treated as data, not as part of the SQL command. This makes it impossible for malicious code to be executed.</p>
<h2 id="heading-how-to-query-data">How to Query Data</h2>
<p>Now that we’ve inserted some data into our <code>Students</code> table, let’s learn how to retrieve the data from the table. We'll explore different methods for fetching data in Python, including <code>fetchone()</code>, <code>fetchall()</code>, and <code>fetchmany()</code>.</p>
<p>To query data from a table, we use the <code>SELECT</code> statement. Here’s a simple SQL command to select all columns from the <code>Students</code> table:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> Students;
</code></pre>
<p>This command retrieves all records and columns from the <code>Students</code> table. We can execute this <code>SELECT</code> query in Python and fetch the results.</p>
<h3 id="heading-how-to-fetch-all-records">How to Fetch All Records</h3>
<p>Here’s how we can fetch all records from the <code>Students</code> table:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:

    <span class="hljs-comment"># Create a cursor object</span>
    cursor = connection.cursor()

    <span class="hljs-comment"># Write the SQL command to select all records from the Students table</span>
    select_query = <span class="hljs-string">"SELECT * FROM Students;"</span>

    <span class="hljs-comment"># Execute the SQL command</span>
    cursor.execute(select_query)

    <span class="hljs-comment"># Fetch all records</span>
    all_students = cursor.fetchall()

    <span class="hljs-comment"># Display results in the terminal</span>
    print(<span class="hljs-string">"All Students:"</span>)
    <span class="hljs-keyword">for</span> student <span class="hljs-keyword">in</span> all_students:
        print(student)
</code></pre>
<p>In this example, the <code>fetchall()</code> method retrieves all rows returned by the query as a list of tuples.</p>
<pre><code class="lang-bash">All Students:
(1, <span class="hljs-string">'Jane Doe'</span>, 23, <span class="hljs-string">'jane@example.com'</span>)
(2, <span class="hljs-string">'Bahadurjit Sabharwal'</span>, 18, <span class="hljs-string">'tristanupadhyay@example.net'</span>)
(3, <span class="hljs-string">'Zayyan Arya'</span>, 20, <span class="hljs-string">'yashawinibhakta@example.org'</span>)
(4, <span class="hljs-string">'Hemani Shukla'</span>, 18, <span class="hljs-string">'gaurikanarula@example.com'</span>)
(5, <span class="hljs-string">'Warda Kara'</span>, 20, <span class="hljs-string">'npatil@example.net'</span>)
(6, <span class="hljs-string">'Mitali Nazareth'</span>, 19, <span class="hljs-string">'sparekh@example.org'</span>)
</code></pre>
<h3 id="heading-how-to-fetch-a-single-record">How to Fetch a Single Record</h3>
<p>If you want to retrieve only one record, you can use the <code>fetchone()</code> method:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:

    <span class="hljs-comment"># Create a cursor object</span>
    cursor = connection.cursor()

    <span class="hljs-comment"># Write the SQL command to select all records from the Students table</span>
    select_query = <span class="hljs-string">"SELECT * FROM Students;"</span>

    <span class="hljs-comment"># Execute the SQL command</span>
    cursor.execute(select_query)

    <span class="hljs-comment"># Fetch one record</span>
    student = cursor.fetchone()

    <span class="hljs-comment"># Display the result</span>
    print(<span class="hljs-string">"First Student:"</span>)
    print(student)
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">First Student:
(1, <span class="hljs-string">'Jane Doe'</span>, 23, <span class="hljs-string">'jane@example.com'</span>)
</code></pre>
<h3 id="heading-how-to-fetch-multiple-records">How to Fetch Multiple Records</h3>
<p>To fetch a specific number of records, you can use <code>fetchmany(size)</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:

    <span class="hljs-comment"># Create a cursor object</span>
    cursor = connection.cursor()

    <span class="hljs-comment"># Write the SQL command to select all records from the Students table</span>
    select_query = <span class="hljs-string">"SELECT * FROM Students;"</span>

    <span class="hljs-comment"># Execute the SQL command</span>
    cursor.execute(select_query)

    <span class="hljs-comment"># Fetch three records</span>
    three_students = cursor.fetchmany(<span class="hljs-number">3</span>)

    <span class="hljs-comment"># Display results</span>
    print(<span class="hljs-string">"Three Students:"</span>)
    <span class="hljs-keyword">for</span> student <span class="hljs-keyword">in</span> three_students:
        print(student)
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Three Students:
(1, <span class="hljs-string">'Jane Doe'</span>, 23, <span class="hljs-string">'jane@example.com'</span>)
(2, <span class="hljs-string">'Bahadurjit Sabharwal'</span>, 18, <span class="hljs-string">'tristanupadhyay@example.net'</span>)
(3, <span class="hljs-string">'Zayyan Arya'</span>, 20, <span class="hljs-string">'yashawinibhakta@example.org'</span>)
</code></pre>
<h3 id="heading-how-to-use-pandas-for-better-data-presentation">How to Use <code>pandas</code> for Better Data Presentation</h3>
<p>For better data presentation, we can use the <code>pandas</code> library to create a <code>DataFrame</code> from our query results. This makes it easier to manipulate and visualize the data.</p>
<p>Here’s how to fetch all records and display them as a pandas DataFrame:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    <span class="hljs-comment"># Write the SQL command to select all records from the Students table</span>
    select_query = <span class="hljs-string">"SELECT * FROM Students;"</span>

    <span class="hljs-comment"># Use pandas to read SQL query directly into a DataFrame</span>
    df = pd.read_sql_query(select_query, connection)

<span class="hljs-comment"># Display the DataFrame</span>
print(<span class="hljs-string">"All Students as DataFrame:"</span>)
print(df)
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">All Students as DataFrame:
   id                  name  age                        email
0   1              Jane Doe   23             jane@example.com
1   2  Bahadurjit Sabharwal   18  tristanupadhyay@example.net
2   3           Zayyan Arya   20  yashawinibhakta@example.org
3   4         Hemani Shukla   18    gaurikanarula@example.com
4   5            Warda Kara   20           npatil@example.net
5   6       Mitali Nazareth   19          sparekh@example.org
</code></pre>
<p>The <code>pd.read_sql_query()</code> function executes the SQL query and directly returns the results as a pandas DataFrame.</p>
<h2 id="heading-how-to-update-and-delete-data">How to Update and Delete Data</h2>
<p>In this section, we’ll learn how to update existing records and delete records from our <code>Students</code> table using SQL commands in Python. This is essential for managing and maintaining your data effectively.</p>
<h3 id="heading-updating-existing-records">Updating Existing Records</h3>
<p>To modify existing records in a database, we use the SQL <code>UPDATE</code> command. This command allows us to change the values of specific columns in one or more rows based on a specified condition.</p>
<p>For example, if we want to update a student's age, the SQL command would look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">UPDATE</span> Students 
<span class="hljs-keyword">SET</span> age = <span class="hljs-number">21</span> 
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'Jane Doe'</span>;
</code></pre>
<p>Now, let’s write Python code to update a specific student's age in our <code>Students</code> table.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    cursor = connection.cursor()

    <span class="hljs-comment"># SQL command to update a student's age</span>
    update_query = <span class="hljs-string">'''
    UPDATE Students 
    SET age = ? 
    WHERE name = ?;
    '''</span>

    <span class="hljs-comment"># Data for the update</span>
    new_age = <span class="hljs-number">21</span>
    student_name = <span class="hljs-string">'Jane Doe'</span>

    <span class="hljs-comment"># Execute the SQL command with the data</span>
    cursor.execute(update_query, (new_age, student_name))

    <span class="hljs-comment"># Commit the changes to save the update</span>
    connection.commit()

    <span class="hljs-comment"># Print a confirmation message</span>
    print(<span class="hljs-string">f"Updated age for <span class="hljs-subst">{student_name}</span> to <span class="hljs-subst">{new_age}</span>."</span>)
</code></pre>
<p>In this example, we used parameterized queries to prevent SQL injection.</p>
<h3 id="heading-how-to-delete-records-from-the-table">How to Delete Records from the Table</h3>
<p>To remove records from a database, we use the SQL <code>DELETE</code> command. This command allows us to delete one or more rows based on a specified condition.</p>
<p>For example, if we want to delete a student named 'Jane Doe', the SQL command would look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> Students 
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'Jane Doe'</span>;
</code></pre>
<p>Let’s write Python code to delete a specific student from our <code>Students</code> table using the <code>with</code> statement.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    cursor = connection.cursor()

    <span class="hljs-comment"># SQL command to delete a student</span>
    delete_query = <span class="hljs-string">'''
    DELETE FROM Students 
    WHERE name = ?;
    '''</span>

    <span class="hljs-comment"># Name of the student to be deleted</span>
    student_name = <span class="hljs-string">'Jane Doe'</span>

    <span class="hljs-comment"># Execute the SQL command with the data</span>
    cursor.execute(delete_query, (student_name,))

    <span class="hljs-comment"># Commit the changes to save the deletion</span>
    connection.commit()

    <span class="hljs-comment"># Print a confirmation message</span>
    print(<span class="hljs-string">f"Deleted student record for <span class="hljs-subst">{student_name}</span>."</span>)
</code></pre>
<h4 id="heading-important-considerations">Important Considerations</h4>
<ul>
<li><p><strong>Conditions</strong>: Always use the <code>WHERE</code> clause when updating or deleting records to avoid modifying or removing all rows in the table. Without a <code>WHERE</code> clause, the command affects every row in the table.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727519069500/f22be4cc-e75f-4492-af01-ed08f31361f3.jpeg" alt="357089 rows affected Meme" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
</li>
<li><p><strong>Backup</strong>: It’s good practice to back up your database before performing updates or deletions, especially in production environments.</p>
</li>
</ul>
<h2 id="heading-how-to-use-transactions">How to Use Transactions</h2>
<p>A transaction is a sequence of one or more SQL operations that are treated as a single unit of work. In the context of a database, a transaction allows you to perform multiple operations that either all succeed or none at all. This ensures that your database remains in a consistent state, even in the face of errors or unexpected issues.</p>
<p>For example, if you are transferring money between two bank accounts, you would want both the debit from one account and the credit to the other to succeed or fail together. If one operation fails, the other should not be executed to maintain consistency.</p>
<h3 id="heading-why-use-transactions">Why Use Transactions?</h3>
<ol>
<li><p><strong>Atomicity</strong>: Transactions ensure that a series of operations are treated as a single unit. If one operation fails, none of the operations will be applied to the database.</p>
</li>
<li><p><strong>Consistency</strong>: Transactions help maintain the integrity of the database by ensuring that all rules and constraints are followed.</p>
</li>
<li><p><strong>Isolation</strong>: Each transaction operates independently of others, preventing unintended interference.</p>
</li>
<li><p><strong>Durability</strong>: Once a transaction is committed, the changes are permanent, even in the event of a system failure.</p>
</li>
</ol>
<h3 id="heading-when-to-use-transactions">When to Use Transactions?</h3>
<p>You should use transactions when:</p>
<ul>
<li><p>Performing multiple related operations that must succeed or fail together.</p>
</li>
<li><p>Modifying critical data that requires consistency and integrity.</p>
</li>
<li><p>Working with operations that can potentially fail, such as financial transactions or data migrations.</p>
</li>
</ul>
<h3 id="heading-how-to-manage-transactions-in-python">How to Manage Transactions in Python</h3>
<p>In SQLite, transactions are managed using the <code>BEGIN</code>, <code>COMMIT</code>, and <code>ROLLBACK</code> commands. However, when using the <code>sqlite3</code> module in Python, you typically manage transactions through the connection object.</p>
<h5 id="heading-starting-a-transaction">Starting a Transaction</h5>
<p>A transaction begins implicitly when you execute any SQL statement. To start a transaction explicitly, you can use the <code>BEGIN</code> command:</p>
<pre><code class="lang-python">cursor.execute(<span class="hljs-string">"BEGIN;"</span>)
</code></pre>
<p>However, it’s usually unnecessary to start a transaction manually, as SQLite starts a transaction automatically when you execute an SQL statement.</p>
<h5 id="heading-how-to-commit-a-transaction">How to Commit a Transaction</h5>
<p>To save all changes made during a transaction, you use the <code>commit()</code> method. This makes all modifications permanent in the database.</p>
<pre><code class="lang-python">connection.commit()
</code></pre>
<p>We have already used the <code>commit()</code> method in the above provided examples.</p>
<h5 id="heading-rolling-back-a-transaction">Rolling Back a Transaction</h5>
<p>If something goes wrong and you want to revert the changes made during a transaction, you can use the <code>rollback()</code> method. This will undo all changes made since the transaction started.</p>
<pre><code class="lang-python">connection.rollback()
</code></pre>
<h3 id="heading-example-of-using-transactions-in-python">Example of Using Transactions in Python</h3>
<p>To illustrate the use of transactions in a real-world scenario, we’ll create a new table called <code>Customers</code> to manage customer accounts. In this example, we’ll assume each customer has a <code>balance</code>. We will add two customers to this table and perform a funds transfer operation between them.</p>
<p>First, let's create the <code>Customers</code> table and insert two customers:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Create the Customers table and add two customers</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    cursor = connection.cursor()

    <span class="hljs-comment"># Create Customers table</span>
    create_customers_table = <span class="hljs-string">'''
    CREATE TABLE IF NOT EXISTS Customers (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL UNIQUE,
        balance REAL NOT NULL
    );
    '''</span>
    cursor.execute(create_customers_table)

    <span class="hljs-comment"># Insert two customers</span>
    cursor.execute(
        <span class="hljs-string">"INSERT INTO Customers (name, balance) VALUES (?, ?);"</span>, (<span class="hljs-string">'Ashutosh'</span>, <span class="hljs-number">100.0</span>))
    cursor.execute(
        <span class="hljs-string">"INSERT INTO Customers (name, balance) VALUES (?, ?);"</span>, (<span class="hljs-string">'Krishna'</span>, <span class="hljs-number">50.0</span>))

    connection.commit()
</code></pre>
<p>Now, let’s perform the funds transfer operation between Ashutosh and Krishna:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">transfer_funds</span>(<span class="hljs-params">from_customer, to_customer, amount</span>):</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-keyword">try</span>:
            <span class="hljs-comment"># Start a transaction</span>
            cursor.execute(<span class="hljs-string">"BEGIN;"</span>)

            <span class="hljs-comment"># Deduct amount from the sender</span>
            cursor.execute(
                <span class="hljs-string">"UPDATE Customers SET balance = balance - ? WHERE name = ?;"</span>, (amount, from_customer))
            <span class="hljs-comment"># Add amount to the receiver</span>
            cursor.execute(
                <span class="hljs-string">"UPDATE Customers SET balance = balance + ? WHERE name = ?;"</span>, (amount, to_customer))

            <span class="hljs-comment"># Commit the changes</span>
            connection.commit()
            print(
                <span class="hljs-string">f"Transferred <span class="hljs-subst">{amount}</span> from <span class="hljs-subst">{from_customer}</span> to <span class="hljs-subst">{to_customer}</span>."</span>)

        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            <span class="hljs-comment"># If an error occurs, rollback the transaction</span>
            connection.rollback()
            print(<span class="hljs-string">f"Transaction failed: <span class="hljs-subst">{e}</span>"</span>)


<span class="hljs-comment"># Example usage</span>
transfer_funds(<span class="hljs-string">'Ashutosh'</span>, <span class="hljs-string">'Krishna'</span>, <span class="hljs-number">80.0</span>)
</code></pre>
<p>In this example, we first created a <code>Customers</code> table and inserted two customers, Ashutosh with a balance of ₹100, and Krishna with a balance of ₹50. We then performed a funds transfer of ₹80 from Ashutosh to Krishna. By using transactions, we ensure that both the debit from Ashutosh's account and the credit to Krishna's account are executed as a single atomic operation, maintaining data integrity in the event of any errors. If the transfer fails (for example, due to insufficient funds), the transaction will roll back, leaving both accounts unchanged.</p>
<h2 id="heading-how-to-optimize-sqlite-query-performance-with-indexing">How to Optimize SQLite Query Performance with Indexing</h2>
<p>Indexing is a powerful technique used in databases to improve query performance. An index is essentially a data structure that stores the location of rows based on specific column values, much like an index at the back of a book helps you quickly locate a topic.</p>
<p>Without an index, SQLite has to scan the entire table row by row to find the relevant data, which becomes inefficient as the dataset grows. By using an index, SQLite can jump directly to the rows you need, significantly speeding up query execution.</p>
<h3 id="heading-how-to-populate-the-database-with-fake-data">How to Populate the Database with Fake Data</h3>
<p>To effectively test the impact of indexing, we need a sizable dataset. Instead of manually adding records, we can use the <code>faker</code> library to quickly generate fake data. In this section, we’ll generate 10,000 fake records and insert them into our <code>Students</code> table. This will simulate a real-world scenario where databases grow large, and query performance becomes important.</p>
<p>We will use the <code>executemany()</code> method to insert the records as below:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">from</span> faker <span class="hljs-keyword">import</span> Faker

<span class="hljs-comment"># Initialize the Faker library</span>
fake = Faker([<span class="hljs-string">'en_IN'</span>])


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">insert_fake_students</span>(<span class="hljs-params">num_records</span>):</span>
    <span class="hljs-string">"""Generate and insert fake student data into the Students table."""</span>
    fake_data = [(fake.name(), fake.random_int(min=<span class="hljs-number">18</span>, max=<span class="hljs-number">25</span>),
                  fake.email()) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(num_records)]

    <span class="hljs-comment"># Use 'with' to handle the database connection</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Insert fake data into the Students table</span>
        cursor.executemany(<span class="hljs-string">'''
        INSERT INTO Students (name, age, email) 
        VALUES (?, ?, ?);
        '''</span>, fake_data)

        connection.commit()

    print(<span class="hljs-string">f"<span class="hljs-subst">{num_records}</span> fake student records inserted successfully."</span>)


<span class="hljs-comment"># Insert 10,000 fake records into the Students table</span>
insert_fake_students(<span class="hljs-number">10000</span>)
</code></pre>
<p>By running this script, 10,000 fake student records will be added to the <code>Students</code> table. In the next section, we'll query the database and compare the performance of queries with and without indexing.</p>
<h3 id="heading-how-to-query-without-indexes">How to Query Without Indexes</h3>
<p>In this section, we’ll query the <code>Students</code> table without any indexes to observe how SQLite performs when there are no optimizations in place. This will serve as a baseline to compare the performance when we add indexes later.</p>
<p>Without indexes, SQLite performs a full table scan, which means that it must check every row in the table to find matching results. For small datasets, this is manageable, but as the number of records grows, the time taken to search increases dramatically. Let’s see this in action by running a basic <code>SELECT</code> query to search for a specific student by name and measure how long it takes.</p>
<p>First, we’ll query the <code>Students</code> table by looking for a student with a specific name. We’ll log the time taken to execute the query using Python’s <code>time</code> module to measure the performance.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">import</span> time


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">query_without_index</span>(<span class="hljs-params">search_name</span>):</span>
    <span class="hljs-string">"""Query the Students table by name without an index and measure the time taken."""</span>

    <span class="hljs-comment"># Connect to the database using 'with'</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Measure the start time</span>
        start_time = time.perf_counter_ns()

        <span class="hljs-comment"># Perform a SELECT query to find a student by name</span>
        cursor.execute(<span class="hljs-string">'''
        SELECT * FROM Students WHERE name = ?;
        '''</span>, (search_name,))

        <span class="hljs-comment"># Fetch all results (there should be only one or a few in practice)</span>
        results = cursor.fetchall()

        <span class="hljs-comment"># Measure the end time</span>
        end_time = time.perf_counter_ns()

        <span class="hljs-comment"># Calculate the total time taken</span>
        elapsed_time = (end_time - start_time) / <span class="hljs-number">1000</span>

        <span class="hljs-comment"># Display the results and the time taken</span>
        print(<span class="hljs-string">f"Query completed in <span class="hljs-subst">{elapsed_time:<span class="hljs-number">.5</span>f}</span> microseconds."</span>)
        print(<span class="hljs-string">"Results:"</span>, results)


<span class="hljs-comment"># Example: Searching for a student by name</span>
query_without_index(<span class="hljs-string">'Ojasvi Dhawan'</span>)
</code></pre>
<p>Here’s the output:</p>
<pre><code class="lang-bash">Query completed <span class="hljs-keyword">in</span> 1578.10000 microseconds.
Results: [(104, <span class="hljs-string">'Ojasvi Dhawan'</span>, 21, <span class="hljs-string">'lavanya26@example.com'</span>)]
</code></pre>
<p>By running the above script, you'll see how long it takes to search the <code>Students</code> table without any indexes. For example, if there are 10,000 records in the table, the query might take 1000-2000 microseconds depending on the size of the table and your hardware. This may not seem too slow for a small dataset, but the performance will degrade as more records are added.</p>
<p>We use <code>time.perf_counter_ns()</code> to measure the time taken for the query execution in nanoseconds. This method is highly accurate for benchmarking small time intervals. We convert the time to microseconds(<code>us</code>) for easier readability.</p>
<h3 id="heading-introducing-the-query-plan">Introducing the Query Plan</h3>
<p>When working with databases, understanding how queries are executed can help you identify performance bottlenecks and optimize your code. SQLite provides a helpful tool for this called <code>EXPLAIN QUERY PLAN</code>, which allows you to analyze the steps SQLite takes to retrieve data.</p>
<p>In this section, we’ll introduce how to use <code>EXPLAIN QUERY PLAN</code> to visualize and understand the inner workings of a query—specifically, how SQLite performs a full table scan when no index is present.</p>
<p>Let’s use <code>EXPLAIN QUERY PLAN</code> to see how SQLite retrieves data from the <code>Students</code> table without any indexes. We’ll search for a student by name, and the query plan will reveal the steps SQLite takes to find the matching rows.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">explain_query</span>(<span class="hljs-params">search_name</span>):</span>
    <span class="hljs-string">"""Explain the query execution plan for a SELECT query without an index."""</span>

    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Use EXPLAIN QUERY PLAN to analyze how the query is executed</span>
        cursor.execute(<span class="hljs-string">'''
        EXPLAIN QUERY PLAN
        SELECT * FROM Students WHERE name = ?;
        '''</span>, (search_name,))

        <span class="hljs-comment"># Fetch and display the query plan</span>
        query_plan = cursor.fetchall()

        print(<span class="hljs-string">"Query Plan:"</span>)
        <span class="hljs-keyword">for</span> step <span class="hljs-keyword">in</span> query_plan:
            print(step)


<span class="hljs-comment"># Example: Analyzing the query plan for searching by name</span>
explain_query(<span class="hljs-string">'Ojasvi Dhawan'</span>)
</code></pre>
<p>When you run this code, SQLite will return a breakdown of how it plans to execute the query. Here’s an example of what the output might look like:</p>
<pre><code class="lang-bash">Query Plan:
(2, 0, 0, <span class="hljs-string">'SCAN Students'</span>)
</code></pre>
<p>This indicates that SQLite is scanning the entire <code>Students</code> table (a full table scan) to find the rows where the <code>name</code> column matches the provided value (<code>Ojasvi Dhawan</code>). Since there is no index on the <code>name</code> column, SQLite must examine each row in the table.</p>
<h3 id="heading-how-to-create-an-index">How to Create an Index</h3>
<p>Creating an index on a column allows SQLite to find rows more quickly during query operations. Instead of scanning the entire table, SQLite can use the index to jump directly to the relevant rows, significantly speeding up queries—especially those involving large datasets.</p>
<p>To create an index, use the following SQL command:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-keyword">index</span>-<span class="hljs-keyword">name</span> <span class="hljs-keyword">ON</span> <span class="hljs-keyword">table</span> (<span class="hljs-keyword">column</span>(s));
</code></pre>
<p>In this example, we will create an index on the <code>name</code> column of the <code>Students</code> table. Here’s how you can do it using Python:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">import</span> time


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_index</span>():</span>
    <span class="hljs-string">"""Create an index on the name column of the Students table."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># SQL command to create an index on the name column</span>
        create_index_query = <span class="hljs-string">'''
        CREATE INDEX IF NOT EXISTS idx_name ON Students (name);
        '''</span>

        <span class="hljs-comment"># Measure the start time</span>
        start_time = time.perf_counter_ns()

        <span class="hljs-comment"># Execute the SQL command to create the index</span>
        cursor.execute(create_index_query)

        <span class="hljs-comment"># Measure the start time</span>
        end_time = time.perf_counter_ns()

        <span class="hljs-comment"># Commit the changes</span>
        connection.commit()

        print(<span class="hljs-string">"Index on 'name' column created successfully!"</span>)

        <span class="hljs-comment"># Calculate the total time taken</span>
        elapsed_time = (end_time - start_time) / <span class="hljs-number">1000</span>

        <span class="hljs-comment"># Display the results and the time taken</span>
        print(<span class="hljs-string">f"Query completed in <span class="hljs-subst">{elapsed_time:<span class="hljs-number">.5</span>f}</span> microseconds."</span>)


<span class="hljs-comment"># Call the function to create the index</span>
create_index()
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Index on <span class="hljs-string">'name'</span> column created successfully!
Query completed <span class="hljs-keyword">in</span> 102768.60000 microseconds.
</code></pre>
<p>Even though creating the index takes this long (102768.6 microseconds), it's a one-time operation. You will still get substantial speed-up when running multiple queries. In the following sections, we will query the database again to observe the performance improvements made possible by this index.</p>
<h3 id="heading-how-to-query-with-indexes">How to Query with Indexes</h3>
<p>In this section, we will perform the same <code>SELECT</code> query we executed earlier, but this time we will take advantage of the index we created on the <code>name</code> column of the <code>Students</code> table. We'll measure and log the execution time to observe the performance improvements provided by the index.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">import</span> time


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">query_with_index</span>(<span class="hljs-params">student_name</span>):</span>
    <span class="hljs-string">"""Query the Students table using an index on the name column."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># SQL command to select a student by name</span>
        select_query = <span class="hljs-string">'SELECT * FROM Students WHERE name = ?;'</span>

        <span class="hljs-comment"># Measure the execution time</span>
        start_time = time.perf_counter_ns()  <span class="hljs-comment"># Start the timer</span>

        <span class="hljs-comment"># Execute the query with the provided student name</span>
        cursor.execute(select_query, (student_name,))
        result = cursor.fetchall()  <span class="hljs-comment"># Fetch all results</span>

        end_time = time.perf_counter_ns()  <span class="hljs-comment"># End the timer</span>

        <span class="hljs-comment"># Calculate the elapsed time in microseconds</span>
        execution_time = (end_time - start_time) / <span class="hljs-number">1000</span>

        <span class="hljs-comment"># Display results and execution time</span>
        print(<span class="hljs-string">f"Query result: <span class="hljs-subst">{result}</span>"</span>)
        print(<span class="hljs-string">f"Execution time with index: <span class="hljs-subst">{execution_time:<span class="hljs-number">.5</span>f}</span> microseconds"</span>)


<span class="hljs-comment"># Example: Searching for a student by name</span>
query_with_index(<span class="hljs-string">'Ojasvi Dhawan'</span>)
</code></pre>
<p>Here’s what we get in the output:</p>
<pre><code class="lang-bash">Query result: [(104, <span class="hljs-string">'Ojasvi Dhawan'</span>, 21, <span class="hljs-string">'lavanya26@example.com'</span>)]
Execution time with index: 390.70000 microseconds
</code></pre>
<p>We can observe a significant reduction in execution time compared to when the query was performed without an index.</p>
<p>Let’s analyze the query execution plan for the query with the index on the <code>name</code> column of the <code>Students</code> table. If you execute the same script again to explain the query, you’ll get the below output:</p>
<pre><code class="lang-bash">Query Plan:
(3, 0, 0, <span class="hljs-string">'SEARCH Students USING INDEX idx_name (name=?)'</span>)
</code></pre>
<p>The plan now shows that the query uses the index <code>idx_name</code>, significantly reducing the number of rows that need to be scanned, which leads to faster query execution.</p>
<h3 id="heading-comparing-performance-results">Comparing Performance Results</h3>
<p>Now, let's summarize the performance results we obtained when querying with and without indexes.</p>
<h4 id="heading-execution-time-comparison">Execution Time Comparison</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Query Type</td><td>Execution Time (microseconds)</td></tr>
</thead>
<tbody>
<tr>
<td>Without Index</td><td>1578.1</td></tr>
<tr>
<td>With Index</td><td>390.7</td></tr>
</tbody>
</table>
</div><h4 id="heading-performance-improvement-summary">Performance Improvement Summary</h4>
<ul>
<li><p>The query with the index is approximately 4.04 times faster than the query without the index.</p>
</li>
<li><p>The execution time improved by about 75.24% after adding the index.</p>
</li>
</ul>
<h3 id="heading-best-practices-for-using-indexes">Best Practices for Using Indexes</h3>
<p>Indexes can significantly enhance the performance of your SQLite database, but they should be used judiciously. Here are some best practices to consider when working with indexes:</p>
<h4 id="heading-when-and-why-to-use-indexes">When and Why to Use Indexes</h4>
<ol>
<li><p><strong>Frequent Query Columns</strong>: Use indexes on columns that are frequently used in <code>SELECT</code> queries, especially those used in <code>WHERE</code>, <code>JOIN</code>, and <code>ORDER BY</code> clauses. This is because indexing these columns can drastically reduce query execution time.</p>
</li>
<li><p><strong>Uniqueness Constraints</strong>: When you have columns that must hold unique values (like usernames or email addresses), creating an index can enforce this constraint efficiently.</p>
</li>
<li><p><strong>Large Datasets</strong>: For tables with a large number of records, indexes become increasingly beneficial. They enable quick lookups, which is essential for maintaining performance as your data grows.</p>
</li>
<li><p><strong>Composite Indexes</strong>: Consider creating composite indexes for queries that filter or sort by multiple columns. For example, if you often search for students by both <code>name</code> and <code>age</code>, an index on both columns can optimize such queries.</p>
</li>
</ol>
<h4 id="heading-potential-downsides-of-indexes">Potential Downsides of Indexes</h4>
<p>While indexes provide significant advantages, there are some potential downsides:</p>
<ol>
<li><p><strong>Slower Insert/Update Operations</strong>: When you insert or update records in a table with indexes, SQLite must also update the index, which can slow down these operations. This is because each insert or update requires additional overhead to maintain the index structure.</p>
</li>
<li><p><strong>Increased Storage Requirements</strong>: Indexes consume additional disk space. For large tables, the storage cost can be substantial. Consider this when designing your database schema, especially for systems with limited storage resources.</p>
</li>
<li><p><strong>Complex Index Management</strong>: Having too many indexes can complicate database management. It may lead to situations where you have redundant indexes, which can degrade performance rather than enhance it. Regularly reviewing and optimizing your indexes is a good practice.</p>
</li>
</ol>
<p>Indexes are powerful tools for optimizing database queries, but they require careful consideration. Striking a balance between improved read performance and the potential overhead on write operations is key. Here are some strategies for achieving this balance:</p>
<ul>
<li><p><strong>Monitor Query Performance</strong>: Use SQLite’s <code>EXPLAIN QUERY PLAN</code> to analyze how your queries perform with and without indexes. This can help identify which indexes are beneficial and which may be unnecessary.</p>
</li>
<li><p><strong>Regular Maintenance</strong>: Periodically review your indexes and assess whether they are still needed. Remove redundant or rarely used indexes to streamline your database operations.</p>
</li>
<li><p><strong>Test and Evaluate</strong>: Before implementing indexes in a production environment, conduct thorough testing to understand their impact on both read and write operations.</p>
</li>
</ul>
<p>By following these best practices, you can leverage the benefits of indexing while minimizing potential drawbacks, ultimately enhancing the performance and efficiency of your SQLite database.</p>
<h2 id="heading-how-to-handle-errors-and-exceptions">How to Handle Errors and Exceptions</h2>
<p>In this section, we’ll discuss how to handle errors and exceptions when working with SQLite in Python. Proper error handling is crucial for maintaining the integrity of your database and ensuring that your application behaves predictably.</p>
<h3 id="heading-common-errors-in-sqlite-operations">Common Errors in SQLite Operations</h3>
<p>When interacting with an SQLite database, several common errors may arise:</p>
<ol>
<li><p><strong>Constraint Violations</strong>: This occurs when you try to insert or update data that violates a database constraint, such as primary key uniqueness or foreign key constraints. For example, trying to insert a duplicate primary key will trigger an error.</p>
</li>
<li><p><strong>Data Type Mismatches</strong>: Attempting to insert data of the wrong type (for example, inserting a string where a number is expected) can lead to an error.</p>
</li>
<li><p><strong>Database Locked Errors</strong>: If a database is being written to by another process or connection, trying to access it can result in a "database is locked" error.</p>
</li>
<li><p><strong>Syntax Errors</strong>: Mistakes in your SQL syntax will result in errors when you try to execute your commands.</p>
</li>
</ol>
<h3 id="heading-how-to-use-pythons-exception-handling">How to Use Python's Exception Handling</h3>
<p>Python’s built-in <a target="_blank" href="https://blog.ashutoshkrris.in/exception-handling-in-python">exception handling</a> mechanisms (<code>try</code> and <code>except</code>) are essential for managing errors in SQLite operations. By using these constructs, you can catch exceptions and respond appropriately without crashing your program.</p>
<p>Here’s a basic example of how to handle errors when inserting data into the database:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_customer_with_error_handling</span>(<span class="hljs-params">name, balance</span>):</span>
    <span class="hljs-string">"""Add a new customer with error handling."""</span>
    <span class="hljs-keyword">try</span>:
        <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
            cursor = connection.cursor()
            cursor.execute(
                <span class="hljs-string">"INSERT INTO Customers (name, balance) VALUES (?, ?);"</span>, (name, balance))
            connection.commit()
            print(<span class="hljs-string">f"Added customer: <span class="hljs-subst">{name}</span> with balance: <span class="hljs-subst">{balance}</span>"</span>)

    <span class="hljs-keyword">except</span> sqlite3.IntegrityError <span class="hljs-keyword">as</span> e:
        print(<span class="hljs-string">f"Error: Integrity constraint violated - <span class="hljs-subst">{e}</span>"</span>)

    <span class="hljs-keyword">except</span> sqlite3.OperationalError <span class="hljs-keyword">as</span> e:
        print(<span class="hljs-string">f"Error: Operational issue - <span class="hljs-subst">{e}</span>"</span>)

    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        print(<span class="hljs-string">f"An unexpected error occurred: <span class="hljs-subst">{e}</span>"</span>)


<span class="hljs-comment"># Example usage</span>
add_customer_with_error_handling(<span class="hljs-string">'Vishakha'</span>, <span class="hljs-number">100.0</span>)  <span class="hljs-comment"># Valid</span>
add_customer_with_error_handling(<span class="hljs-string">'Vishakha'</span>, <span class="hljs-number">150.0</span>)  <span class="hljs-comment"># Duplicate entry</span>
</code></pre>
<p>In this example:</p>
<ul>
<li><p>We catch <code>IntegrityError</code>, which is raised for violations like unique constraints.</p>
</li>
<li><p>We catch <code>OperationalError</code> for general database-related issues (like database locked errors).</p>
</li>
<li><p>We also have a generic <code>except</code> block to handle any unexpected exceptions.</p>
</li>
</ul>
<p>Output:</p>
<pre><code class="lang-bash">Added customer: Vishakha with balance: 100.0
Error: Integrity constraint violated - UNIQUE constraint failed: Customers.name
</code></pre>
<h3 id="heading-best-practices-for-ensuring-database-integrity">Best Practices for Ensuring Database Integrity</h3>
<ol>
<li><p><strong>Use Transactions</strong>: Always use transactions (as discussed in the previous section) when performing multiple related operations. This helps ensure that either all operations succeed or none do, maintaining consistency.</p>
</li>
<li><p><strong>Validate Input Data</strong>: Before executing SQL commands, validate the input data to ensure it meets the expected criteria (for example, correct types, within allowable ranges).</p>
</li>
<li><p><strong>Catch Specific Exceptions</strong>: Always catch specific exceptions to handle different types of errors appropriately. This allows for clearer error handling and debugging.</p>
</li>
<li><p><strong>Log Errors</strong>: Instead of just printing errors to the console, consider logging them to a file or monitoring system. This will help you track issues in production.</p>
</li>
<li><p><strong>Graceful Degradation</strong>: Design your application to handle errors gracefully. If an operation fails, provide meaningful feedback to the user rather than crashing the application.</p>
</li>
<li><p><strong>Regularly Backup Data</strong>: Regularly back up your database to prevent data loss in case of critical failures or corruption.</p>
</li>
<li><p><strong>Use Prepared Statements</strong>: Prepared statements help prevent SQL injection attacks and can also provide better performance for repeated queries.</p>
</li>
</ol>
<h2 id="heading-how-to-export-and-import-data-bonus-section">How to Export and Import Data [Bonus Section]</h2>
<p>In this section, we will learn how to export data from an SQLite database to common formats like CSV and JSON, as well as how to import data into SQLite from these formats using Python. This is useful for data sharing, backup, and integration with other applications.</p>
<h3 id="heading-exporting-data-from-sqlite-to-csv">Exporting Data from SQLite to CSV</h3>
<p>Exporting data to a CSV (Comma-Separated Values) file is straightforward with Python’s built-in libraries. CSV files are widely used for data storage and exchange, making them a convenient format for exporting data.</p>
<p>Here’s how to export data from an SQLite table to a CSV file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">import</span> csv

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">export_to_csv</span>(<span class="hljs-params">file_name</span>):</span>
    <span class="hljs-string">"""Export data from the Customers table to a CSV file."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Execute a query to fetch all customer data</span>
        cursor.execute(<span class="hljs-string">"SELECT * FROM Customers;"</span>)
        customers = cursor.fetchall()

        <span class="hljs-comment"># Write data to CSV</span>
        <span class="hljs-keyword">with</span> open(file_name, <span class="hljs-string">'w'</span>, newline=<span class="hljs-string">''</span>) <span class="hljs-keyword">as</span> csv_file:
            csv_writer = csv.writer(csv_file)
            csv_writer.writerow([<span class="hljs-string">'ID'</span>, <span class="hljs-string">'Name'</span>, <span class="hljs-string">'Balance'</span>])  <span class="hljs-comment"># Writing header</span>
            csv_writer.writerows(customers)  <span class="hljs-comment"># Writing data rows</span>

        print(<span class="hljs-string">f"Data exported successfully to <span class="hljs-subst">{file_name}</span>."</span>)

<span class="hljs-comment"># Example usage</span>
export_to_csv(<span class="hljs-string">'customers.csv'</span>)
</code></pre>
<h3 id="heading-how-to-export-data-to-json">How to Export Data to JSON</h3>
<p>Similarly, you can export data to a <a target="_blank" href="https://blog.ashutoshkrris.in/a-beginners-guide-to-the-json-module-in-python">JSON</a> (JavaScript Object Notation) file, which is a popular format for data interchange, especially in web applications.</p>
<p>Here’s an example of how to export data to JSON:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">export_to_json</span>(<span class="hljs-params">file_name</span>):</span>
    <span class="hljs-string">"""Export data from the Customers table to a JSON file."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Execute a query to fetch all customer data</span>
        cursor.execute(<span class="hljs-string">"SELECT * FROM Customers;"</span>)
        customers = cursor.fetchall()

        <span class="hljs-comment"># Convert data to a list of dictionaries</span>
        customers_list = [{<span class="hljs-string">'ID'</span>: customer[<span class="hljs-number">0</span>], <span class="hljs-string">'Name'</span>: customer[<span class="hljs-number">1</span>],
                           <span class="hljs-string">'Balance'</span>: customer[<span class="hljs-number">2</span>]} <span class="hljs-keyword">for</span> customer <span class="hljs-keyword">in</span> customers]

        <span class="hljs-comment"># Write data to JSON</span>
        <span class="hljs-keyword">with</span> open(file_name, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> json_file:
            json.dump(customers_list, json_file, indent=<span class="hljs-number">4</span>)

        print(<span class="hljs-string">f"Data exported successfully to <span class="hljs-subst">{file_name}</span>."</span>)


<span class="hljs-comment"># Example usage</span>
export_to_json(<span class="hljs-string">'customers.json'</span>)
</code></pre>
<h3 id="heading-how-to-import-data-into-sqlite-from-csv">How to Import Data into SQLite from CSV</h3>
<p>You can also import data from a CSV file into an SQLite database. This is useful for populating your database with existing datasets.</p>
<p>Here's how to import data from a CSV file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> csv
<span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">import_from_csv</span>(<span class="hljs-params">file_name</span>):</span>
    <span class="hljs-string">"""Import data from a CSV file into the Customers table."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Open the CSV file for reading</span>
        <span class="hljs-keyword">with</span> open(file_name, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> csv_file:
            csv_reader = csv.reader(csv_file)
            next(csv_reader)  <span class="hljs-comment"># Skip the header row</span>

            <span class="hljs-comment"># Insert each row into the Customers table</span>
            <span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> csv_reader:
                cursor.execute(
                    <span class="hljs-string">"INSERT INTO Customers (name, balance) VALUES (?, ?);"</span>, (row[<span class="hljs-number">1</span>], row[<span class="hljs-number">2</span>]))

        connection.commit()
        print(<span class="hljs-string">f"Data imported successfully from <span class="hljs-subst">{file_name}</span>."</span>)


<span class="hljs-comment"># Example usage</span>
import_from_csv(<span class="hljs-string">'customer_data.csv'</span>)
</code></pre>
<h3 id="heading-how-to-import-data-into-sqlite-from-json">How to Import Data into SQLite from JSON</h3>
<p>Similarly, importing data from a JSON file is simple. You can read the JSON file and insert the data into your SQLite table.</p>
<p>Here's how to do it:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">import_from_json</span>(<span class="hljs-params">file_name</span>):</span>
    <span class="hljs-string">"""Import data from a JSON file into the Customers table."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Open the JSON file for reading</span>
        <span class="hljs-keyword">with</span> open(file_name, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> json_file:
            customers_list = json.load(json_file)

            <span class="hljs-comment"># Insert each customer into the Customers table</span>
            <span class="hljs-keyword">for</span> customer <span class="hljs-keyword">in</span> customers_list:
                cursor.execute(<span class="hljs-string">"INSERT INTO Customers (name, balance) VALUES (?, ?);"</span>, (customer[<span class="hljs-string">'Name'</span>], customer[<span class="hljs-string">'Balance'</span>]))

        connection.commit()
        print(<span class="hljs-string">f"Data imported successfully from <span class="hljs-subst">{file_name}</span>."</span>)


<span class="hljs-comment"># Example usage</span>
import_from_json(<span class="hljs-string">'customer_data.json'</span>)
</code></pre>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>And that’s a wrap! This guide has introduced you to the fundamentals of working with SQLite in Python, covering everything from setting up your environment to querying and manipulating data, as well as exporting and importing information. I hope you found it helpful and that it has sparked your interest in using SQLite for your projects.</p>
<p>Now it's time to put your newfound knowledge into practice! I encourage you to create your project using SQLite and Python. Whether it’s a simple application for managing your library, a budgeting tool, or something unique, the possibilities are endless.</p>
<p>Once you’ve completed your project, share it on Twitter and tag me! I’d love to see what you’ve created and celebrate your accomplishments.</p>
<p>You can find all the code from this tutorial on <a target="_blank" href="https://github.com/ashutoshkrris/sqlite-tutorial">GitHub</a>. Thank you for following along, and happy coding!</p>
<blockquote>
<p>Generate Table of Contents for your freeCodeCamp articles for free using the <a target="_blank" href="https://toc-generator.ashutoshkrris.in/freecodecamp">TOC Generator</a> tool.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Read and Write Files with Node.js ]]>
                </title>
                <description>
                    <![CDATA[ Node.js is a powerful JavaScript runtime environment that lets you run JS code outside the browser. And a fundamental part of many Node.js applications involves reading and writing files – whether that's text, JSON, HTML, or other file formats. So yo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-read-and-write-files-with-nodejs/</link>
                <guid isPermaLink="false">66c34b90a7aea9fc97bdfb33</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 19 Aug 2024 13:41:36 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1723804956795/2dbd964a-00c3-4489-819a-393b058ed1fd.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Node.js is a powerful JavaScript runtime environment that lets you run JS code outside the browser. And a fundamental part of many Node.js applications involves reading and writing files – whether that's text, JSON, HTML, or other file formats. So you should understand how to read and write files. </p>
<p>Files are the backbone of data storage. Node.js provides a powerful 'fs' (file system) module to interact with these files seamlessly. Let's assume I want to read a JSON file in Node.js. The fs module can help me with that.</p>
<p>In this tutorial, I'll explain the core functionalities of this module, explore various techniques to read different file types, and discover some best practices to make your file-handling operations smoother and more efficient.</p>
<p>Throughout this tutorial, we'll cover everything from importing the package to using it to work with files asynchronously. Let's get started on this journey of learning file operations with Node.js!</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-nodejs-fs-module">Node.js fs Module</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-read-and-write-files-with-nodejs">How to Read And Write Files With Node.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-ways-to-read-files-in-nodejs">Ways to Read Files in Node.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<h2 id="heading-nodejs-fs-module">Node.js <code>fs</code> Module</h2>
<p>The Node.js File System (fs) module is an essential component of the Node.js runtime environment. It provides a variety of features for interacting with your computer's file system.</p>
<p>The fs module allows you to read, write, update, delete, and manage files and directories. This module is especially useful for handling file-related operations in both synchronous and asynchronous modes.</p>
<p>Let’s break down the key aspects of the module:</p>
<ol>
<li><p>The fs module, at its core, provides a collection of APIs for interacting with the file system. It provides ways to perform basic activities such as reading file contents, writing data to files, creating directories, deleting files, and so on.</p>
</li>
<li><p>The module includes both synchronous and asynchronous methods for interacting with files. The synchronous methods block the execution of the program until the operation completes. But the asynchronous methods are ideal for scenarios where we need to perform concurrent tasks without halting the execution of the entire program.</p>
</li>
<li><p>The module also supports handling directories, such as creating directories, removing directories, and listing directory contents.</p>
</li>
<li><p>The module also supports working with file streams, allowing efficient handling of large files by reading or writing data in chunks without loading the entire content into memory. It also facilitates the use of buffers for handling binary data, which helps with activities like data transformation and manipulation.</p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To continue with the tutorial, I recommend having the following prerequisites:</p>
<ol>
<li><p><strong>Basic Understanding of JavaScript</strong>: It is essential to be familiar with JavaScript, as Node.js uses JavaScript.</p>
</li>
<li><p><strong>Node.js Installed</strong>: Ensure that Node.js is installed on your system. You can download and install Node.js from its <a target="_blank" href="https://nodejs.org">official website</a>. </p>
</li>
<li><p><strong>Text Editor/IDE</strong>: Have a text editor or an Integrated Development Environment (IDE) installed and ready to use.</p>
</li>
</ol>
<h2 id="heading-how-to-read-and-write-files-with-nodejs">How to Read And Write Files With Node.js</h2>
<p>Let's look at an example to understand the process of reading and writing files in Node.js. We'll assume a scenario where we have two files – name.json and address.json.</p>
<p>The content inside the name.json looks like this:</p>
<pre><code class="lang-json">[
  { <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Alice"</span> },
  { <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Bob"</span> },
  { <span class="hljs-attr">"id"</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Charlie"</span> }
]
</code></pre>
<p>The content inside address.json looks like this:</p>
<pre><code class="lang-json">[
  { <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">"address"</span>: <span class="hljs-string">"123 Main St"</span> },
  { <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">"address"</span>: <span class="hljs-string">"456 Elm St"</span> },
  { <span class="hljs-attr">"id"</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">"address"</span>: <span class="hljs-string">"789 Oak St"</span> }
]
</code></pre>
<p>Our objective is to create a bio.json file that merges the id, name, and address information, creating a structure as follows:</p>
<pre><code class="lang-json">[
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Alice"</span>,
    <span class="hljs-attr">"address"</span>: <span class="hljs-string">"123 Main St"</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Bob"</span>,
    <span class="hljs-attr">"address"</span>: <span class="hljs-string">"456 Elm St"</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Charlie"</span>,
    <span class="hljs-attr">"address"</span>: <span class="hljs-string">"789 Oak St"</span>
  }
]
</code></pre>
<p>Let's build the application!</p>
<h3 id="heading-step-1-import-nodejs-packages-path-and-fs">Step 1: Import Node.js Packages <code>path</code> and <code>fs</code></h3>
<p>Let us start with creating an app.js file. The first thing we will do is import the fs library:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);
</code></pre>
<h3 id="heading-step-2-read-from-files">Step 2: Read From Files</h3>
<p>Next, let's read data from the two files using Node.js. We'll make a utility function that helps us read these files easily in our Node.js environment.</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">readJSONFile</span>(<span class="hljs-params">filename</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fs.readFile(filename, <span class="hljs-string">"utf8"</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">JSON</span>.parse(data);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Error reading <span class="hljs-subst">${filename}</span>: <span class="hljs-subst">${error}</span>`</span>);
    <span class="hljs-keyword">return</span> [];
  }
}
</code></pre>
<p>Since we are using JSON files in our example, we have defined a readJSONFile method in our code. It's an asynchronous JavaScript function that takes a filename as input and aims to return the parsed JSON contents of that file.</p>
<p>Inside a try block, we attempt to read the file using fs.readFile in Node with the specified filename and "utf8" encoding. If successful, the function then parses the file content as JSON using JSON.parse and returns it.</p>
<p>If any error occurs during reading or parsing, the catch block takes over. It logs the error with the filename and details and then returns an empty array instead of the expected JSON object.</p>
<h3 id="heading-step-3-implement-the-main-function">Step 3: Implement the Main Function</h3>
<p>The next step is to create a main function where we make use of the above-defined method and combine the data of the two files to create a bio.json file.</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">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> names = <span class="hljs-keyword">await</span> readJSONFile(<span class="hljs-string">"names.json"</span>);
    <span class="hljs-keyword">const</span> addresses = <span class="hljs-keyword">await</span> readJSONFile(<span class="hljs-string">"address.json"</span>);

    <span class="hljs-keyword">const</span> bioData = names.map(<span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> matchingAddress = addresses.find(
        <span class="hljs-function">(<span class="hljs-params">address</span>) =&gt;</span> address.id === name.id
      );
      <span class="hljs-keyword">return</span> { ...name, ...matchingAddress };
    });

    <span class="hljs-keyword">await</span> fs.writeFile(<span class="hljs-string">"bio.json"</span>, <span class="hljs-built_in">JSON</span>.stringify(bioData, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>));
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"bio.json created successfully!"</span>);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error combining data:"</span>, error);
  }
}
</code></pre>
<p>In the main function, we first read the two JSON files named <code>names.json</code> and <code>address.json</code> using the readJSONFile function. Both readJSONFile calls use await, so the function waits for both files to be read before moving on.</p>
<p>Next, we iterate through each <code>name</code> using a map, creating a new <code>bioData</code> for each. Inside the loop, it searches for a matching <code>address</code> from the addresses collection based on the index using find. </p>
<p>The search compares <code>name.id</code> with each <code>address.id</code> until it finds a match. If a match is found, the function combines the information from both files. It uses the spread operator (...) to merge all properties from both objects into a single new <code>bioData</code> object. If no matching address is found, the <code>bioData</code> object will only have the name information.</p>
<p>Once all <code>bioData</code> objects are prepared, the function writes them as a new JSON file named <code>bio.json</code> using <code>fs.writeFile</code>. This writing process also uses await, ensuring the file is created before moving on. </p>
<p>The try block ensures smooth execution, while the catch block takes care of any errors like missing files or incorrect data. If any error occurs, a generic error message and the specific error details are logged for debugging.</p>
<h3 id="heading-complete-code">Complete Code</h3>
<p>Our completed code looks like below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>).promises;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readJSONFile</span>(<span class="hljs-params">filename</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fs.readFile(filename, <span class="hljs-string">"utf8"</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">JSON</span>.parse(data);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Error reading <span class="hljs-subst">${filename}</span>: <span class="hljs-subst">${error}</span>`</span>);
    <span class="hljs-keyword">return</span> [];
  }
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> names = <span class="hljs-keyword">await</span> readJSONFile(<span class="hljs-string">"names.json"</span>);
    <span class="hljs-keyword">const</span> addresses = <span class="hljs-keyword">await</span> readJSONFile(<span class="hljs-string">"address.json"</span>);

    <span class="hljs-keyword">const</span> bioData = names.map(<span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> matchingAddress = addresses.find(
        <span class="hljs-function">(<span class="hljs-params">address</span>) =&gt;</span> address.id === name.id
      );
      <span class="hljs-keyword">return</span> { ...name, ...matchingAddress };
    });

    <span class="hljs-keyword">await</span> fs.writeFile(<span class="hljs-string">"bio.json"</span>, <span class="hljs-built_in">JSON</span>.stringify(bioData, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>));
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"bio.json created successfully!"</span>);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error combining data:"</span>, error);
  }
}

<span class="hljs-comment">// Execute the main method</span>
main();
</code></pre>
<p>We can run the application using the following command:</p>
<pre><code class="lang-bash">node app.js
</code></pre>
<p>Once the application runs, we get to see the following logs in the terminal if everything goes well:</p>
<pre><code class="lang-bash">bio.json created successfully!
</code></pre>
<p>This indicates that the bio.json file was created successfully. The content inside the file should look like below:</p>
<pre><code class="lang-json">[
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Alice"</span>,
    <span class="hljs-attr">"address"</span>: <span class="hljs-string">"123 Main St"</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Bob"</span>,
    <span class="hljs-attr">"address"</span>: <span class="hljs-string">"456 Elm St"</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Charlie"</span>,
    <span class="hljs-attr">"address"</span>: <span class="hljs-string">"789 Oak St"</span>
  }
]
</code></pre>
<h2 id="heading-ways-to-read-files-in-nodejs">Ways to Read Files in Node.js</h2>
<p>To read files in Node.js, we mostly use two primary methods: <code>fs.readFile()</code> and <code>fs.readFileSync()</code>. The difference lies in their synchronous and asynchronous nature.</p>
<h3 id="heading-fsreadfile-method"><code>fs.readFile()</code> Method</h3>
<p>The <code>fs.readFile()</code> method in Node.js is asynchronous. It reads the content of the entire file without blocking other operations. This makes it suitable for scenarios where non-blocking I/O operations are essential.</p>
<p>In simple terms, the function allows other operations to continue while the reading takes place. It accepts the following three parameters:</p>
<ol>
<li><p>path: the path to the file to be read.</p>
</li>
<li><p>encoding: optional, specifies the encoding of the file (for example, "utf8"). Defaults to "utf8" if not provided.</p>
</li>
<li><p>callback function: optional, a function to be called when the file is read. The function receives three arguments: error, data, and buffer.</p>
</li>
</ol>
<p>Let’s look at an example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

fs.readFile(<span class="hljs-string">"data.txt"</span>, <span class="hljs-string">"utf8"</span>, <span class="hljs-function">(<span class="hljs-params">err, data</span>) =&gt;</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(data); <span class="hljs-comment">// data will be a string containing the content of the file</span>
  }
});
</code></pre>
<h3 id="heading-fsreadfilesync-method"><code>fs.readFileSync()</code> Method</h3>
<p>The <code>fs.readFileSync()</code> method is synchronous. It reads the file content synchronously, stopping further execution until the file is completely read. This method is beneficial in scenarios where we require synchronous processing.</p>
<p>It takes only two parameters:</p>
<ol>
<li><p>path: the path to the file to be read</p>
</li>
<li><p>encoding: optional, specifies the encoding of the file (for example, "utf8"). Defaults to "utf8" if not provided.</p>
</li>
</ol>
<p>Let’s look at an example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

<span class="hljs-keyword">try</span> {
  <span class="hljs-keyword">const</span> data = fs.readFileSync(<span class="hljs-string">"data.txt"</span>, <span class="hljs-string">"utf8"</span>);
  <span class="hljs-built_in">console</span>.log(data); <span class="hljs-comment">// data will be a string containing the content of the file</span>
} <span class="hljs-keyword">catch</span> (err) {
  <span class="hljs-built_in">console</span>.error(err);
}
</code></pre>
<h3 id="heading-fsreadfile-vs-fsreadfilesync"><code>fs.readFile()</code> vs <code>fs.readFileSync()</code></h3>
<p>To understand the difference between the Nodejs <code>readFile</code> and <code>readFileSync</code> methods, we will write two programs and monitor their execution flow.</p>
<p>Let's start with the <code>fs.readFile()</code> method.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

fs.readFile(<span class="hljs-string">"example.txt"</span>, <span class="hljs-string">"utf8"</span>, <span class="hljs-function">(<span class="hljs-params">err, data</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Content from readFile:"</span>, data);
});

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Completed reading file content asynchronously"</span>);
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Completed reading file content asynchronously
Content from readFile: freeCodeCamp is awesome!
</code></pre>
<p>Because of <code>fs.readFile()</code>'s asynchronous nature, the code after <code>fs.readFile()</code> doesn't wait for the file reading operation to finish. So the "Completed reading file content synchronously" message is immediately logged to the console, showing that the subsequent code continues executing without waiting for the file read to complete.</p>
<p>Eventually, when the file reading operation finishes, the callback function executes and logs the file content.</p>
<p>Next, let's see the execution of the <code>fs.readFileSync()</code> method.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

<span class="hljs-keyword">const</span> data = fs.readFileSync(<span class="hljs-string">"data.txt"</span>, <span class="hljs-string">"utf8"</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Content from readFileSync:"</span>, data);

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Completed reading file content synchronously"</span>);
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Content from readFileSync: freeCodeCamp is awesome!
Completed reading file content synchronously
</code></pre>
<p>In contrast, <code>fs.readFileSync()</code> reads the data.txt file synchronously, blocking further code execution until the file is completely read. Consequently, the code continues execution only after the file reading operation is finished.</p>
<p>Because of this, the message "Completed reading file content synchronously" is logged after successfully reading the file content.</p>
<p>Now, we know the difference between the two methods. Understanding this difference is important as it impacts the program flow, especially in scenarios where timing and blocking operations are critical considerations in Node.js applications.</p>
<h3 id="heading-how-to-read-a-text-file">How to Read a Text File</h3>
<p>It's pretty straightforward to read a text file in Node.js, and we have been doing this throughout the tutorial. Let’s consider that we have a file called message.txt with the following content:</p>
<pre><code class="lang-plaintext">Learn Node.js with freeCodeCamp
</code></pre>
<p>Now, we want to read the contents of this file. We can do it like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

fs.readFile(<span class="hljs-string">"message.txt"</span>, <span class="hljs-string">"utf8"</span>, <span class="hljs-function">(<span class="hljs-params">err, data</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (err) {
    <span class="hljs-built_in">console</span>.log(err);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(data);
  }
});
</code></pre>
<p>The callback function returns the content of the file in a data variable. Since we set the encoding to “utf8”, the value of data is a string. So we can perform string operations on the data variable.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

fs.readFile(<span class="hljs-string">"message.txt"</span>, <span class="hljs-string">"utf8"</span>, <span class="hljs-function">(<span class="hljs-params">err, data</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (err) {
    <span class="hljs-built_in">console</span>.log(err);
  } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">let</span> splittedWords = data.split(<span class="hljs-string">" "</span>);
      <span class="hljs-built_in">console</span>.log(splittedWords);
  }
});
</code></pre>
<p>In the above code, we split the data variable using a space. So the splittedWords will be a string array containing the following value:</p>
<pre><code class="lang-javascript">[ <span class="hljs-string">'Learn'</span>, <span class="hljs-string">'Node.js'</span>, <span class="hljs-string">'with'</span>, <span class="hljs-string">'freeCodeCamp'</span> ]
</code></pre>
<h3 id="heading-how-to-read-html-files">How to Read HTML Files</h3>
<p>Reading HTML files follows a similar approach to reading text files in Node.js. We can use the <code>fs</code> module to read HTML files:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

fs.readFile(<span class="hljs-string">"index.html"</span>, <span class="hljs-string">"utf8"</span>, <span class="hljs-function">(<span class="hljs-params">err, data</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (err) {
    <span class="hljs-built_in">console</span>.log(err);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(data);
  }
});
</code></pre>
<p>We can then use the HTML content for further processing, such as rendering it with the Node.js <code>http</code> package.</p>
<h3 id="heading-how-to-read-files-by-url">How to Read Files by URL</h3>
<p>Reading files by URL in Node.js involves additional steps beyond the native fs module. Typically, we’ll need to use additional modules like <code>http</code> or <code>axios</code> to fetch file content from a URL.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);
<span class="hljs-keyword">const</span> https = <span class="hljs-built_in">require</span>(<span class="hljs-string">"https"</span>);

<span class="hljs-keyword">const</span> file = fs.createWriteStream(<span class="hljs-string">"data.txt"</span>);

https.get(
  <span class="hljs-string">"https://example-files.online-convert.com/document/txt/example.txt"</span>,
  <span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
    <span class="hljs-keyword">var</span> stream = response.pipe(file);

    stream.on(<span class="hljs-string">"finish"</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">"done"</span>);
    });
  }
);
</code></pre>
<p>First, we set up a writable stream named file, associated with the local file data.txt. We then use Node.js's <code>https</code> module to perform an HTTP GET request to the specified URL. The get method triggers a callback function when we receive a response from the server. </p>
<p>Inside the callback, the script pipes the response directly into the writable stream. This operation efficiently directs the data received from the remote server to the local file data.txt, essentially downloading and writing the content concurrently. </p>
<p>Finally, we set up an event listener for the "finish" event on the stream. This event fires when all the data has been successfully written to the file. Upon completion, the script logs "done" to the console, indicating the successful download and writing of the file.</p>
<h3 id="heading-how-to-read-a-json-file">How to Read a JSON File</h3>
<p>We have already seen how we can read a JSON file using the fs module. Let's say that we want to read our previously created bio.json file. Its data looks like the below:</p>
<pre><code class="lang-json">[
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Alice"</span>,
    <span class="hljs-attr">"address"</span>: <span class="hljs-string">"123 Main St"</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Bob"</span>,
    <span class="hljs-attr">"address"</span>: <span class="hljs-string">"456 Elm St"</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Charlie"</span>,
    <span class="hljs-attr">"address"</span>: <span class="hljs-string">"789 Oak St"</span>
  }
]
</code></pre>
<p>In Node.js, we read JSON like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

fs.readFile(<span class="hljs-string">"bio.json"</span>, <span class="hljs-string">"utf8"</span>, <span class="hljs-function">(<span class="hljs-params">err, data</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (err) {
    <span class="hljs-built_in">console</span>.log(err);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(data);
  }
});
</code></pre>
<p>With this, our JSON data is stored within the data variable as a string. If we want, we can use it for further processing. Let’s say, we want to print the details of the user:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

fs.readFile(<span class="hljs-string">"bio.json"</span>, <span class="hljs-string">"utf8"</span>, <span class="hljs-function">(<span class="hljs-params">err, data</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (err) {
    <span class="hljs-built_in">console</span>.log(err);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">const</span> users = <span class="hljs-built_in">JSON</span>.parse(data);
    users.forEach(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${user.name}</span> with ID <span class="hljs-subst">${user.id}</span> lives at <span class="hljs-subst">${user.address}</span>`</span>);
    });
  }
});
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Alice with ID 1 lives at 123 Main St
Bob with ID 2 lives at 456 Elm St
Charlie with ID 3 lives at 789 Oak St
</code></pre>
<p>In the above code, we first parse the string data variable to JSON and store it in a <code>users</code> variable. We then loop over the <code>users</code> variable to log the required message.</p>
<h3 id="heading-fspromises"><code>fs.promises</code></h3>
<p><code>fs.promises</code> provides a set of asynchronous functions for interacting with the file system in Node.js. These functions are based on promises and offer a more readable and efficient way to handle asynchronous operations compared to callbacks.</p>
<p>With <code>fs.promises</code>, we don't need to add nested callbacks – which means that we can avoid callback hell.</p>
<p>A basic readFile operation with <code>fs.promises</code> looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>).promises;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readTextFile</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fs.readFile(<span class="hljs-string">"data.txt"</span>, <span class="hljs-string">"utf8"</span>);
    <span class="hljs-built_in">console</span>.log(data);
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err);
  }
}

readTextFile();
</code></pre>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this tutorial, we've explored the essential techniques for handling files in Node.js with the help of the fs module.</p>
<p>From understanding synchronous and asynchronous file reading with methods like <code>fs.readFile()</code> and <code>fs.readFileSync()</code> to processing various file formats such as text, HTML, JSON, and even reading files from URLs, we've covered a bunch of functionalities. We also learned about fs.promises, which is a more elegant way to handle file operations using asynchronous functions.</p>
<h3 id="heading-frequently-asked-questions-faqs">Frequently Asked Questions (FAQs)</h3>
<h4 id="heading-1-how-do-i-read-a-file-asynchronously-in-nodejs">1. How do I read a file asynchronously in Node.js?</h4>
<p>There are mainly two ways to read a file asynchronously in Node.js: using <code>fs.readFile()</code> and using <code>fs.promises</code>.</p>
<p>The <code>fs.readFile()</code> method uses callbacks to handle the operation. We provide a callback function that will be called with the file data (or an error) when the reading is complete.</p>
<p>But <code>fs.promises</code> offers a promise-based approach. We can use the <code>readFile</code> function with await to wait for the reading to finish and then access the data directly.</p>
<h4 id="heading-2-how-can-i-check-if-a-file-exists-before-reading-or-writing-in-nodejs">2. How can I check if a file exists before reading or writing in Node.js?</h4>
<p>There are two methods to check if a file exist: using <code>fs.stat</code> and using <code>fs.promises.access</code>.</p>
<p>The <code>fs.stat</code> method synchronously checks if a file exists and returns information about it like size and access time. The <code>fs.promises.access</code> method asynchronously checks if a file exists and returns a promise that resolves or rejects based on the existence of the file.</p>
<h4 id="heading-3-how-can-i-handle-errors-when-reading-or-writing-files-in-nodejs">3. How can I handle errors when reading or writing files in Node.js?</h4>
<p>To handle errors while reading or writing files in Node.js, we can utilize error-first callbacks or promises along with try-catch blocks.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Comparable vs Comparator Interfaces in Java – Which Should You Use and When? ]]>
                </title>
                <description>
                    <![CDATA[ Sorting is a fundamental operation in programming, essential for organizing data in a specific order. In Java, built-in sorting methods provide efficient ways to sort primitive data types and arrays, making it easy to manage and manipulate collection... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/comparable-vs-comparator-explained-in-java/</link>
                <guid isPermaLink="false">66ba0e6e79b7f411df58dea3</guid>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Tue, 23 Jul 2024 13:13:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/comparable-comparator.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Sorting is a fundamental operation in programming, essential for organizing data in a specific order. In Java, built-in sorting methods provide efficient ways to sort primitive data types and arrays, making it easy to manage and manipulate collections of data. For instance, you can quickly sort an array of integers or a list of strings using methods like <code>Arrays.sort()</code> and <code>Collections.sort()</code>. </p>
<p>However, when it comes to sorting custom objects, such as instances of user-defined classes, the built-in sorting methods fall short. These methods don't know how to order objects based on custom criteria. This is where Java's <code>Comparable</code> and <code>Comparator</code> interfaces come into play, allowing developers to define and implement custom sorting logic tailored to specific requirements.</p>
<p>In this blog post, we'll explore how to use the <code>Comparable</code> and <code>Comparator</code> interfaces to sort custom objects in Java. I'll provide examples to illustrate the differences and use cases for each approach, helping you master custom sorting in your Java applications.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-sorting-methods-for-primitive-types">Sorting Methods for Primitive Types</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-the-comparable-interface">How to Use the Comparable Interface</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-the-comparator-interface">How to Use the Comparator Interface</a></li>
<li><a class="post-section-overview" href="#heading-comparable-vs-comparator">Comparable vs Comparator</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ul>
<h2 id="heading-sorting-methods-for-primitive-types">Sorting Methods for Primitive Types</h2>
<p>Java provides a variety of built-in sorting methods that make it easy to sort primitive data types. These methods are highly optimized and efficient, allowing you to sort arrays and collections with minimal code. For primitive types, such as integers, floating-point numbers, and characters, the <code>Arrays.sort()</code> method is commonly used.</p>
<h3 id="heading-how-to-use-the-arrayssort-method">How to Use the Arrays.sort() Method</h3>
<p>The <code>Arrays.sort()</code> method sorts the specified array into ascending numerical order. This method uses a dual-pivot quicksort algorithm, which is faster and more efficient for most data sets.</p>
<p>Let's look at an example of sorting an array of integers and characters using <code>Arrays.sort()</code>:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial;

<span class="hljs-keyword">import</span> java.util.Arrays;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PrimitiveSorting</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        <span class="hljs-keyword">int</span>[] numbers = { <span class="hljs-number">5</span>, <span class="hljs-number">3</span>, <span class="hljs-number">8</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span> };
        System.out.println(<span class="hljs-string">"Original array: "</span> + Arrays.toString(numbers));

        Arrays.sort(numbers);
        System.out.println(<span class="hljs-string">"Sorted array: "</span> + Arrays.toString(numbers));

        <span class="hljs-keyword">char</span>[] characters = { <span class="hljs-string">'o'</span>, <span class="hljs-string">'i'</span>, <span class="hljs-string">'e'</span>, <span class="hljs-string">'u'</span>, <span class="hljs-string">'a'</span> };
        System.out.println(<span class="hljs-string">"Original array: "</span> + Arrays.toString(characters));

        Arrays.sort(characters);
        System.out.println(<span class="hljs-string">"Sorted array: "</span> + Arrays.toString(characters));
    }
}
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Original array: [5, 3, 8, 2, 1]
Sorted array: [1, 2, 3, 5, 8]
Original array: [o, i, e, u, a]
Sorted array: [a, e, i, o, u]
</code></pre>
<h3 id="heading-how-to-use-the-collectionssort-method">How to Use the Collections.sort() Method</h3>
<p>The <code>Collections.sort()</code> method is used to sort collections such as <code>ArrayList</code>. This method is also based on the natural ordering of the elements or a custom comparator.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial;

<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.Collections;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CollectionsSorting</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        ArrayList&lt;String&gt; wordsList = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();
        wordsList.add(<span class="hljs-string">"banana"</span>);
        wordsList.add(<span class="hljs-string">"apple"</span>);
        wordsList.add(<span class="hljs-string">"cherry"</span>);
        wordsList.add(<span class="hljs-string">"date"</span>);
        System.out.println(<span class="hljs-string">"Original list: "</span> + wordsList);

        Collections.sort(wordsList);
        System.out.println(<span class="hljs-string">"Sorted list: "</span> + wordsList);
    }
}
</code></pre>
<p>Output:</p>
<pre><code class="lang-plaintext">Original list: [banana, apple, cherry, date]
Sorted list: [apple, banana, cherry, date]
</code></pre>
<h3 id="heading-limitations-with-custom-classes">Limitations with Custom Classes</h3>
<p>While Java's built-in sorting methods, such as <code>Arrays.sort()</code> and <code>Collections.sort()</code>, are powerful and efficient for sorting primitive types and objects with natural ordering (like <code>String</code>), they fall short when it comes to sorting custom objects. These methods do not inherently know how to order user-defined objects because there is no natural way for them to compare these objects.</p>
<p>For example, consider a simple <code>Person</code> class that has <code>name</code>, <code>age</code>, and <code>weight</code> attributes:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
    String name;
    <span class="hljs-keyword">int</span> age;
    <span class="hljs-keyword">double</span> weight;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Person</span><span class="hljs-params">(String name, <span class="hljs-keyword">int</span> age, <span class="hljs-keyword">double</span> weight)</span> </span>{
        <span class="hljs-keyword">this</span>.name = name;
        <span class="hljs-keyword">this</span>.age = age;
        <span class="hljs-keyword">this</span>.weight = weight;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Person [name="</span> + name + <span class="hljs-string">", age="</span> + age + <span class="hljs-string">", weight="</span> + weight + <span class="hljs-string">" kgs]"</span>;
    }
}
</code></pre>
<p>If we try to sort a list of <code>Person</code> objects using <code>Arrays.sort()</code> or <code>Collections.sort()</code>, we will encounter a compilation error because these methods do not know how to compare <code>Person</code> objects:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial;

<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.Arrays;
<span class="hljs-keyword">import</span> java.util.Collections;
<span class="hljs-keyword">import</span> java.util.List;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomClassSorting</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        List&lt;Person&gt; people = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;(Arrays.asList(
                <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Alice"</span>, <span class="hljs-number">30</span>, <span class="hljs-number">65.5</span>),
                <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Bob"</span>, <span class="hljs-number">25</span>, <span class="hljs-number">75.0</span>),
                <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Charlie"</span>, <span class="hljs-number">35</span>, <span class="hljs-number">80.0</span>)
        ));
        System.out.println(<span class="hljs-string">"Original people list: "</span> + people);

        Collections.sort(people);
        System.out.println(<span class="hljs-string">"Sorted people list: "</span> + people);
    }
}
</code></pre>
<p>Compilation Error:</p>
<pre><code class="lang-bash">java: no suitable method found <span class="hljs-keyword">for</span> sort(java.util.List&lt;tutorial.Person&gt;)
    method java.util.Collections.&lt;T&gt;sort(java.util.List&lt;T&gt;) is not applicable
      (inference variable T has incompatible bounds
        equality constraints: tutorial.Person
        lower bounds: java.lang.Comparable&lt;? super T&gt;)
    method java.util.Collections.&lt;T&gt;sort(java.util.List&lt;T&gt;,java.util.Comparator&lt;? super T&gt;) is not applicable
      (cannot infer type-variable(s) T
        (actual and formal argument lists differ <span class="hljs-keyword">in</span> length))
</code></pre>
<p>The error occurs because the <code>Person</code> class does not implement the <code>Comparable</code> interface, and there is no way for the sorting method to know how to compare two <code>Person</code> objects.</p>
<p>To sort custom objects like <code>Person</code>, we need to provide a way to compare these objects. Java offers two main approaches to achieve this:</p>
<ol>
<li>Implementing the <code>Comparable</code> Interface: This allows a class to define its natural ordering by implementing the <code>compareTo</code> method.</li>
<li>Using the <code>Comparator</code> Interface: This allows us to create separate classes or lambda expressions to define multiple ways of comparing objects.</li>
</ol>
<p>We will explore both approaches in the upcoming sections, starting with the <code>Comparable</code> interface.</p>
<h2 id="heading-how-to-use-the-comparable-interface">How to Use the Comparable Interface</h2>
<p>Java provides a <code>Comparable</code> interface to define a natural ordering for objects of a user-defined class. By implementing the <code>Comparable</code> interface, a class can provide a single natural ordering that can be used to sort its instances. This is particularly useful when you need a default way to compare and sort objects.</p>
<h3 id="heading-overview">Overview</h3>
<p>The <code>Comparable</code> interface contains a single method, <code>compareTo()</code>, which compares the current object with the specified object for order. The method returns:</p>
<ul>
<li>A negative integer if the current object is less than the specified object.</li>
<li>Zero if the current object is equal to the specified object.</li>
<li>A positive integer if the current object is greater than the specified object.</li>
</ul>
<h3 id="heading-how-comparable-allows-for-a-single-natural-ordering-of-objects">How Comparable Allows for a Single Natural Ordering of Objects</h3>
<p>By implementing the <code>Comparable</code> interface, a class can ensure that its objects have a natural ordering. This allows the objects to be sorted using methods like <code>Arrays.sort()</code> or <code>Collections.sort()</code> without the need for a separate comparator.</p>
<p>Let's implement the <code>Comparable</code> interface in a new <code>PersonV2</code> class, comparing by age.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PersonV2</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Comparable</span>&lt;<span class="hljs-title">PersonV2</span>&gt; </span>{
    String name;
    <span class="hljs-keyword">int</span> age;
    <span class="hljs-keyword">double</span> weight;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PersonV2</span><span class="hljs-params">(String name, <span class="hljs-keyword">int</span> age, <span class="hljs-keyword">double</span> weight)</span> </span>{
        <span class="hljs-keyword">this</span>.name = name;
        <span class="hljs-keyword">this</span>.age = age;
        <span class="hljs-keyword">this</span>.weight = weight;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"PersonV2 [name="</span> + name + <span class="hljs-string">", age="</span> + age + <span class="hljs-string">", weight="</span> + weight + <span class="hljs-string">" kgs]"</span>;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">compareTo</span><span class="hljs-params">(PersonV2 other)</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.age - other.age;
    }
}
</code></pre>
<p>In this implementation, the <code>compareTo()</code> method compares the <code>age</code> attribute of the current <code>PersonV2</code> object with the <code>age</code> attribute of the specified <code>PersonV2</code> object by subtracting one age from the other. By using the expression <code>this.age - other.age</code>, we’re effectively implementing this logic as follows:</p>
<ul>
<li>If <code>this.age</code> is less than <code>other.age</code>, the result will be negative.</li>
<li>If <code>this.age</code> is equal to <code>other.age</code>, the result will be zero.</li>
<li>If <code>this.age</code> is greater than <code>other.age</code>, the result will be positive.</li>
</ul>
<p><strong>Note</strong>: We can also use <code>Integer.compare(this.age, other.age)</code> instead of performing the arithmetic operation manually.</p>
<p>Now that the <code>PersonV2</code> class implements the <code>Comparable</code> interface, we can sort a list of <code>PersonV2</code> objects using <code>Collections.sort()</code>:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial;

<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.Arrays;
<span class="hljs-keyword">import</span> java.util.Collections;
<span class="hljs-keyword">import</span> java.util.List;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomClassSortingV2</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        List&lt;PersonV2&gt; people = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;(Arrays.asList(
                <span class="hljs-keyword">new</span> PersonV2(<span class="hljs-string">"Alice"</span>, <span class="hljs-number">30</span>, <span class="hljs-number">65.5</span>),
                <span class="hljs-keyword">new</span> PersonV2(<span class="hljs-string">"Bob"</span>, <span class="hljs-number">25</span>, <span class="hljs-number">75.0</span>),
                <span class="hljs-keyword">new</span> PersonV2(<span class="hljs-string">"Charlie"</span>, <span class="hljs-number">35</span>, <span class="hljs-number">80.0</span>)
        ));
        System.out.println(<span class="hljs-string">"Original people list: "</span> + people);

        Collections.sort(people);
        System.out.println(<span class="hljs-string">"Sorted people list: "</span> + people);
    }
}
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Original people list: [PersonV2 [name=Alice, age=30, weight=65.5 kgs], PersonV2 [name=Bob, age=25, weight=75.0 kgs], PersonV2 [name=Charlie, age=35, weight=80.0 kgs]]
Sorted people list: [PersonV2 [name=Bob, age=25, weight=75.0 kgs], PersonV2 [name=Alice, age=30, weight=65.5 kgs], PersonV2 [name=Charlie, age=35, weight=80.0 kgs]]
</code></pre>
<p>In this example, the <code>PersonV2</code> objects are sorted in ascending order of age using the <code>Collections.sort()</code> method, which relies on the natural ordering defined by the <code>compareTo()</code> method in the <code>PersonV2</code> class.</p>
<h3 id="heading-limitations-of-comparable">Limitations of Comparable</h3>
<p>While the <code>Comparable</code> interface provides a way to define a natural ordering for objects, it has several limitations that can restrict its use in practical applications. Understanding these limitations can help us determine when to use other mechanisms, such as the <code>Comparator</code> interface, to achieve more flexible sorting.</p>
<ul>
<li><strong>Single Natural Ordering</strong>: The primary limitation of <code>Comparable</code> is that it allows only one natural ordering for the objects of a class. When you implement <code>Comparable</code>, you define a single way to compare objects, which is used whenever the objects are sorted or compared. This can be restrictive if you need to sort objects in multiple ways.</li>
<li><strong>Inflexibility</strong>: If you need to sort objects by different attributes or in different orders, you will have to modify the class or create new implementations of <code>Comparable</code>. This inflexibility can lead to a proliferation of comparison methods and can make the code harder to maintain.</li>
<li><strong>Non-Adaptable</strong>: Once a class implements <code>Comparable</code>, the natural ordering is fixed and cannot be easily changed. For instance, if your <code>PersonV2</code> class initially sorts by age but later you need to sort by weight or name, you have to either change the <code>compareTo()</code> method or create a new version of the class.</li>
</ul>
<p>This is where the <code>Comparator</code> interface comes into play. To define multiple ways of comparing objects, we can use the <code>Comparator</code> interface, which we will explore in the next section.</p>
<h2 id="heading-how-to-use-the-comparator-interface">How to Use the Comparator Interface</h2>
<p>The <code>Comparator</code> interface in Java provides a way to define multiple ways of comparing and sorting objects. Unlike the <code>Comparable</code> interface, which allows only a single natural ordering, <code>Comparator</code> is designed to offer flexibility by allowing multiple sorting strategies. This makes it particularly useful for scenarios where objects need to be sorted in different ways.</p>
<h3 id="heading-overview-1">Overview</h3>
<p>The <code>Comparator</code> interface defines a single method, <code>compare()</code>, which compares two objects and returns:</p>
<ul>
<li>A negative integer if the first object is less than the second object.</li>
<li>Zero if the first object is equal to the second object.</li>
<li>A positive integer if the first object is greater than the second object.</li>
</ul>
<p>This method provides a way to define custom ordering for objects without modifying the class itself.</p>
<h3 id="heading-how-comparator-allows-for-multiple-ways-of-ordering-objects">How Comparator Allows for Multiple Ways of Ordering Objects</h3>
<p>The <code>Comparator</code> interface allows you to create multiple <code>Comparator</code> instances, each defining a different ordering for objects. This flexibility means that you can sort objects by various attributes or in different orders without altering the object's class.</p>
<p>Let's implement multiple <code>Comparator</code> instances for the <code>Person</code> class. We'll define comparators for sorting by name, by age, and by weight. First, we need to update the <code>Person</code> class to include getters and ensure that attributes are accessible.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
    String name;
    <span class="hljs-keyword">int</span> age;
    <span class="hljs-keyword">double</span> weight;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Person</span><span class="hljs-params">(String name, <span class="hljs-keyword">int</span> age, <span class="hljs-keyword">double</span> weight)</span> </span>{
        <span class="hljs-keyword">this</span>.name = name;
        <span class="hljs-keyword">this</span>.age = age;
        <span class="hljs-keyword">this</span>.weight = weight;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> name;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getAge</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> age;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">getWeight</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> weight;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Person [name="</span> + name + <span class="hljs-string">", age="</span> + age + <span class="hljs-string">", weight="</span> + weight + <span class="hljs-string">" kgs]"</span>;
    }
}
</code></pre>
<h4 id="heading-comparator-by-name"><strong>Comparator by Name</strong></h4>
<p>This comparator sorts <code>Person</code> objects alphabetically by their <code>name</code>.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial.comparator;

<span class="hljs-keyword">import</span> tutorial.Person;

<span class="hljs-keyword">import</span> java.util.Comparator;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PersonNameComparator</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Comparator</span>&lt;<span class="hljs-title">Person</span>&gt; </span>{

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">compare</span><span class="hljs-params">(Person p1, Person p2)</span> </span>{
        <span class="hljs-keyword">return</span> p1.getName().compareTo(p2.getName());
    }
}
</code></pre>
<h4 id="heading-comparator-by-age">Comparator by Age</h4>
<p>This comparator sorts <code>Person</code> objects by their <code>age</code>, in ascending order.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial.comparator;

<span class="hljs-keyword">import</span> tutorial.Person;

<span class="hljs-keyword">import</span> java.util.Comparator;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PersonAgeComparator</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Comparator</span>&lt;<span class="hljs-title">Person</span>&gt; </span>{

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">compare</span><span class="hljs-params">(Person p1, Person p2)</span> </span>{
        <span class="hljs-keyword">return</span> p1.getAge() - p2.getAge();
    }
}
</code></pre>
<h4 id="heading-comparator-by-weight">Comparator by Weight</h4>
<p>This comparator sorts <code>Person</code> objects by their <code>weight</code>, in ascending order.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial.comparator;

<span class="hljs-keyword">import</span> tutorial.Person;

<span class="hljs-keyword">import</span> java.util.Comparator;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PersonWeightComparator</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Comparator</span>&lt;<span class="hljs-title">Person</span>&gt; </span>{

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">compare</span><span class="hljs-params">(Person p1, Person p2)</span> </span>{
        <span class="hljs-keyword">return</span> (<span class="hljs-keyword">int</span>) (p1.getWeight() - p2.getWeight());
    }
}
</code></pre>
<p>Now, here’s how you can use these <code>Comparator</code> instances to sort a list of <code>Person</code> objects:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> tutorial;

<span class="hljs-keyword">import</span> tutorial.comparator.PersonAgeComparator;
<span class="hljs-keyword">import</span> tutorial.comparator.PersonNameComparator;
<span class="hljs-keyword">import</span> tutorial.comparator.PersonWeightComparator;

<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.Arrays;
<span class="hljs-keyword">import</span> java.util.Collections;
<span class="hljs-keyword">import</span> java.util.List;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomClassSortingV3</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        List&lt;Person&gt; people = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;(Arrays.asList(
                <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Alice"</span>, <span class="hljs-number">30</span>, <span class="hljs-number">65.5</span>),
                <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Bob"</span>, <span class="hljs-number">25</span>, <span class="hljs-number">75.0</span>),
                <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Charlie"</span>, <span class="hljs-number">35</span>, <span class="hljs-number">80.0</span>)
        ));
        System.out.println(<span class="hljs-string">"Original people list: "</span> + people);

        Collections.sort(people, <span class="hljs-keyword">new</span> PersonNameComparator());
        System.out.println(<span class="hljs-string">"Sorted people list by name: "</span> + people);

        Collections.sort(people, <span class="hljs-keyword">new</span> PersonAgeComparator());
        System.out.println(<span class="hljs-string">"Sorted people list by age: "</span> + people);

        Collections.sort(people, <span class="hljs-keyword">new</span> PersonWeightComparator());
        System.out.println(<span class="hljs-string">"Sorted people list by weight: "</span> + people);
    }
}
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Original people list: [Person [name=Alice, age=30, weight=65.5 kgs], Person [name=Bob, age=25, weight=75.0 kgs], Person [name=Charlie, age=35, weight=80.0 kgs]]
Sorted people list by name: [Person [name=Alice, age=30, weight=65.5 kgs], Person [name=Bob, age=25, weight=75.0 kgs], Person [name=Charlie, age=35, weight=80.0 kgs]]
Sorted people list by age: [Person [name=Bob, age=25, weight=75.0 kgs], Person [name=Alice, age=30, weight=65.5 kgs], Person [name=Charlie, age=35, weight=80.0 kgs]]
Sorted people list by weight: [Person [name=Alice, age=30, weight=65.5 kgs], Person [name=Bob, age=25, weight=75.0 kgs], Person [name=Charlie, age=35, weight=80.0 kgs]]
</code></pre>
<p>In this example, the <code>Comparator</code> instances allow sorting the <code>Person</code> objects by different attributes: name, age, and weight. This demonstrates how the <code>Comparator</code> interface enables flexible and versatile sorting strategies for a class.</p>
<h2 id="heading-comparable-vs-comparator">Comparable vs Comparator</h2>
<p>When sorting objects in Java, you have two primary options: the <code>Comparable</code> and <code>Comparator</code> interfaces. Understanding the differences between these two interfaces can help you choose the right approach for your needs. Please note that this is also a very important interview question.</p>
<h3 id="heading-comparison">Comparison</h3>
<p>Here’s a table comparing and contrasting the <code>Comparable</code> and <code>Comparator</code> interfaces in Java:</p>
<table><tbody><tr><th><p>Feature</p></th><th><p>Comparable</p></th><th><p>Comparator</p></th></tr><tr><td><p>Definition</p></td><td><p>Provides a single, natural ordering for objects</p></td><td><p>Provides multiple ways to compare objects</p></td></tr><tr><td><p>Method</p></td><td><p>compareTo(T o)</p></td><td><p>compare(T o1, T o2)</p></td></tr><tr><td><p>Implementation</p></td><td><p>Implemented within the class itself</p></td><td><p>Implemented outside the class</p></td></tr><tr><td><p>Sorting Criteria</p></td><td><p>One default natural ordering</p></td><td><p>Multiple sorting criteria</p></td></tr><tr><td><p>Flexibility</p></td><td><p>Limited to one way of comparing objects</p></td><td><p>Flexible; multiple comparators can be defined</p></td></tr><tr><td><p>Class Modification</p></td><td><p>Requires modifying the class to implement <code>Comparable</code></p></td><td><p>Does not require modifying the class</p></td></tr><tr><td><p>Use Case</p></td><td><p>Use when there is a clear, natural ordering (e.g., sorting employees by ID)</p></td><td><p>Use when different sorting orders are needed or when you cannot modify the class</p></td></tr></tbody></table>

<h3 id="heading-benefits-and-drawbacks-of-each-approach">Benefits and Drawbacks of Each Approach</h3>
<h4 id="heading-comparable-operator">Comparable Operator</h4>
<h5 id="heading-benefits">Benefits:</h5>
<ul>
<li><strong>Simplicity</strong>: Provides a default sorting order that is easy to implement and use.</li>
<li><strong>Built-in</strong>: The natural ordering is part of the class itself, so it is always available and used by default in sorting methods.</li>
</ul>
<h4 id="heading-drawbacks">Drawbacks:</h4>
<ul>
<li><strong>Single Ordering</strong>: Can only define one way to compare objects. If different sorting orders are needed, the class must be modified or additional <code>Comparator</code> instances must be used.</li>
<li><strong>Class Modification</strong>: Requires altering the class to implement <code>Comparable</code>, which might not be feasible if the class is part of a library or if its natural ordering is not clear.</li>
</ul>
<h4 id="heading-comparator">Comparator</h4>
<h5 id="heading-benefits-1">Benefits:</h5>
<ul>
<li><strong>Flexibility</strong>: Allows for multiple sorting orders and criteria, which can be defined externally and used as needed.</li>
<li><strong>Non-invasive</strong>: Does not require modification of the class itself, making it suitable for classes you do not control or when you need different sorting options.</li>
</ul>
<h5 id="heading-drawbacks-1">Drawbacks:</h5>
<ul>
<li><strong>Complexity</strong>: Requires creating and managing multiple <code>Comparator</code> instances, which can add complexity to the code.</li>
<li><strong>Overhead</strong>: Might introduce additional overhead if many comparators are used, especially if they are created on the fly.</li>
</ul>
<p>In summary, <code>Comparable</code> is best used when a class has a natural ordering that makes sense for most use cases. </p>
<p><code>Comparator</code>, on the other hand, provides flexibility for sorting by multiple criteria and is useful when the class does not have a natural ordering or when different sorting orders are needed. </p>
<p>Choosing between <code>Comparable</code> and <code>Comparator</code> depends on your specific sorting needs and whether you need a single default order or multiple flexible sorting options.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Understanding and utilizing both <code>Comparable</code> and <code>Comparator</code> can significantly enhance your ability to manage and manipulate object collections in Java. By applying these concepts, you can create more flexible and powerful sorting mechanisms.</p>
<p>To solidify your understanding, try implementing both <code>Comparable</code> and <code>Comparator</code> in real-world scenarios. Experiment with different classes and sorting criteria to see how each approach works in practice.</p>
<h3 id="heading-links-to-official-java-documentation">Links to Official Java Documentation:</h3>
<ul>
<li><a target="_blank" href="https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html">Java Comparable Interface</a></li>
<li><a target="_blank" href="https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html">Java Comparator Interface</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How To Implement Instant Search with Flask and HTMX ]]>
                </title>
                <description>
                    <![CDATA[ Instant search is a feature that shows search results as users type their query. Instead of waiting for a full page reload or submitting a form, results appear instantly, allowing users to find what they are looking for quickly. For example, when you... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-implement-instant-search-with-flask-and-htmx/</link>
                <guid isPermaLink="false">66ba0e96102ebf67c0a6d42a</guid>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 22 Jul 2024 11:36:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/instant-search.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Instant search is a feature that shows search results as users type their query. Instead of waiting for a full page reload or submitting a form, results appear instantly, allowing users to find what they are looking for quickly. For example, when you start typing in a search box, suggestions or matching items will appear immediately, making the process smoother and more efficient.</p>
<p>In this tutorial, you'll learn how to create a simple instant search feature using Flask and HTMX. This will help you build interactive web applications with better user experience.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-environment">How to Set Up the Environment</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-database">How to Set up the Database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-basic-routing-and-html">How to Set Up Basic Routing and HTML</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-htmx-for-instant-search">How to Add HTMX for Instant Search</a></li>
<li><a class="post-section-overview" href="#heading-demo">Demo</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h3 id="heading-why-use-instant-search"><strong>Why Use Instant Search?</strong></h3>
<ul>
<li><strong>Speed</strong>: Users get immediate feedback, which helps them refine their search.</li>
<li><strong>Convenience</strong>: It reduces the number of clicks and page loads, leading to a more seamless experience.</li>
<li><strong>Engagement</strong>: Users are more likely to stay on your site if they can find what they need easily.</li>
</ul>
<h3 id="heading-technologies-used"><strong>Technologies Used</strong></h3>
<p>To implement this instant search feature, we'll use two main technologies:</p>
<ul>
<li><strong>Flask</strong>: <a target="_blank" href="https://blog.ashutoshkrris.in/getting-started-with-flask">Flask</a> is a popular web framework for Python. It is simple and lightweight, making it easy to set up and start building web applications quickly. Flask lets you to create routes, handle requests, and serve HTML templates with minimal setup.</li>
<li><strong>HTMX</strong>: This is a powerful JavaScript library that lets you to create dynamic web pages without having to write a lot of JavaScript code. With HTMX, you can update parts of a page based on user actions, like typing in a search box. It makes it easy to load data from the server and display it on the page without a full reload.</li>
</ul>
<h2 id="heading-how-to-set-up-the-environment">How to Set Up the Environment</h2>
<p>In this section, we'll set up the environment for our Flask project, including installing the necessary packages and organizing the project structure.</p>
<h4 id="heading-1-how-to-install-flask-and-htmx">1. How to Install Flask and HTMX</h4>
<p>First, you need to install Flask, Flask-SQLAlchemy, and Flask-Migrate. You can do this using pip. Open your terminal and run:</p>
<pre><code class="lang-bash">pip install Flask Flask-SQLAlchemy Flask-Migrate
</code></pre>
<p>For HTMX, we'll include it in our HTML template directly from a CDN.</p>
<h4 id="heading-2-how-to-create-a-virtual-environment">2. How to Create a Virtual Environment</h4>
<p>It's a good practice to create a virtual environment for your projects to manage dependencies. Here's how to create one:</p>
<pre><code class="lang-bash">python -m venv venv
</code></pre>
<p>Next, activate the environment:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># On Windows</span>
venv\Scripts\activate

<span class="hljs-comment"># On macOS/Linux</span>
<span class="hljs-built_in">source</span> venv/bin/activate
</code></pre>
<h4 id="heading-3-how-to-set-up-the-project-structure">3. How to Set Up the Project Structure</h4>
<p>Now, set up your project structure as follows:</p>
<pre><code class="lang-bash">my_flask_app/
├── core/
│   ├── __init__.py
│   ├── models.py
│   └── routes.py
├── config.py
└── main.py
</code></pre>
<p>Let us start with creating the first file: <strong>core/<strong>init</strong>.py</strong>. This file is the initialization script for the core module of our Flask application. It sets up the Flask app instance and configures it using the settings from the <code>DevelopmentConfig</code> class, and initializes the database and migration system.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_sqlalchemy <span class="hljs-keyword">import</span> SQLAlchemy
<span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> Migrate
<span class="hljs-keyword">from</span> config <span class="hljs-keyword">import</span> DevelopmentConfig

<span class="hljs-comment"># Create the Flask app instance</span>
app = Flask(__name__)

<span class="hljs-comment"># Load configuration from DevelopmentConfig</span>
app.config.from_object(DevelopmentConfig)

<span class="hljs-comment"># Initialize SQLAlchemy with the app instance</span>
db = SQLAlchemy(app)

<span class="hljs-comment"># Initialize Flask-Migrate with the app instance and database</span>
migrate = Migrate(app, db)

<span class="hljs-comment"># Import routes to register them with the app</span>
<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> routes
</code></pre>
<p>Next, we will create the <strong>config.py</strong> file from where we'll import the <code>DevelopmentConfig</code> class. This file contains configuration settings for different environments (development, testing, production). These settings help manage different behaviors and configurations based on where your app is running.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Config</span>(<span class="hljs-params">object</span>):</span>
    DEBUG = <span class="hljs-literal">False</span>
    TESTING = <span class="hljs-literal">False</span>
    CSRF_ENABLED = <span class="hljs-literal">True</span>
    SECRET_KEY = <span class="hljs-string">"guess-me"</span>
    SQLALCHEMY_DATABASE_URI = <span class="hljs-string">"sqlite:///db.sqlite"</span>
    SQLALCHEMY_TRACK_MODIFICATIONS = <span class="hljs-literal">False</span>
    BCRYPT_LOG_ROUNDS = <span class="hljs-number">13</span>
    WTF_CSRF_ENABLED = <span class="hljs-literal">True</span>
    DEBUG_TB_ENABLED = <span class="hljs-literal">False</span>
    DEBUG_TB_INTERCEPT_REDIRECTS = <span class="hljs-literal">False</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DevelopmentConfig</span>(<span class="hljs-params">Config</span>):</span>
    DEVELOPMENT = <span class="hljs-literal">True</span>
    DEBUG = <span class="hljs-literal">True</span>
    WTF_CSRF_ENABLED = <span class="hljs-literal">False</span>
    DEBUG_TB_ENABLED = <span class="hljs-literal">True</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestingConfig</span>(<span class="hljs-params">Config</span>):</span>
    TESTING = <span class="hljs-literal">True</span>
    DEBUG = <span class="hljs-literal">True</span>
    SQLALCHEMY_DATABASE_URI = <span class="hljs-string">"sqlite:///testdb.sqlite"</span>
    BCRYPT_LOG_ROUNDS = <span class="hljs-number">1</span>
    WTF_CSRF_ENABLED = <span class="hljs-literal">False</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductionConfig</span>(<span class="hljs-params">Config</span>):</span>
    DEBUG = <span class="hljs-literal">False</span>
    DEBUG_TB_ENABLED = <span class="hljs-literal">False</span>
</code></pre>
<ul>
<li><code>Config</code>: The base configuration class with default settings.</li>
<li><code>DevelopmentConfig</code>: Inherits from <code>Config</code> and overrides development settings.</li>
<li><code>TestingConfig</code>: Inherits from <code>Config</code> and overrides settings for testing.</li>
<li><code>ProductionConfig</code>: Inherits from <code>Config</code> and overrides production settings.</li>
</ul>
<p>Finally, we'll create the <strong>main.py</strong> file. This is the entry point of our application. When we run this file, it starts the Flask web server.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> app

<span class="hljs-comment"># Start the Flask app</span>
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<ul>
<li><code>if __name__ == '__main__'</code>: This ensures that the Flask app runs only if the script is executed directly (not imported as a module).</li>
<li><code>app.run(debug=True)</code>: Starts the Flask development server with debug mode enabled, which provides detailed error messages and auto-reloading.</li>
</ul>
<p>Now that you understand the project files, we can proceed with implementing the instant search functionality. This will involve creating the models and search route, setting up the HTMX-powered front-end, and connecting everything to fetch and display search results dynamically.</p>
<h2 id="heading-how-to-set-up-the-database">How to Set up the Database</h2>
<p>In this section, we will set up the database for our Flask application. We will use SQLite for simplicity. We will create a model for the data we want to search and seed the database with sample data.</p>
<p>SQLite is a lightweight, disk-based database that doesn’t require a separate server process. It's an excellent choice for development and small projects because it is easy to set up and use.</p>
<h3 id="heading-how-to-create-a-model-for-the-data-to-be-searched">How to Create a Model for the Data to Be Searched</h3>
<p>We will create a <code>Book</code> model to represent the data in our database. This model will include fields like the book title and author.</p>
<p>Let's create the <code>core/models.py</code> file and add the model there:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> db

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span>(<span class="hljs-params">db.Model</span>):</span>
    id = db.Column(db.Integer, primary_key=<span class="hljs-literal">True</span>)
    title = db.Column(db.String(<span class="hljs-number">100</span>), nullable=<span class="hljs-literal">False</span>)
    author = db.Column(db.String(<span class="hljs-number">100</span>), nullable=<span class="hljs-literal">False</span>)
</code></pre>
<h3 id="heading-how-to-apply-migrations-using-flask-migrate">How to Apply Migrations Using Flask-Migrate</h3>
<p>Before we can seed our database, we need to set up database migrations using Flask-Migrate. This tool helps us manage database changes, such as creating tables and altering schemas, systematically.</p>
<p>Initialize the migrations folder by running the following command in your project directory:</p>
<pre><code class="lang-bash">flask db init
</code></pre>
<p>This command creates a <strong>migrations</strong> directory in our project, which will store migration scripts.</p>
<p>Generate a migration script that creates the necessary database tables based on your models:</p>
<pre><code class="lang-bash">flask db migrate -m <span class="hljs-string">"Initial migration"</span>
</code></pre>
<p>This command scans your models and generates a new migration script in the <strong>migrations</strong> folder.</p>
<p>Apply the migration to create the tables in your database:</p>
<pre><code class="lang-bash">flask db upgrade
</code></pre>
<p>This command executes the migration script, creating the tables defined by your models in the database. Post this step, you will see an <strong>instance/db.sqlite</strong> file created.</p>
<h3 id="heading-how-to-seed-data-into-your-database">How to Seed Data Into Your Database</h3>
<p>Now that we have set up the database and applied the migration, we can proceed with seeding the database. Create a file named <strong>seeder.py</strong> with the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> csv
<span class="hljs-keyword">from</span> sqlalchemy.exc <span class="hljs-keyword">import</span> IntegrityError

<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> db, app
<span class="hljs-keyword">from</span> core.models <span class="hljs-keyword">import</span> Book


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">seed_data</span>():</span>
    <span class="hljs-keyword">with</span> app.app_context():
        <span class="hljs-comment"># Open the CSV file</span>
        <span class="hljs-keyword">with</span> open(<span class="hljs-string">"data.csv"</span>, newline=<span class="hljs-string">''</span>, encoding=<span class="hljs-string">'utf-8'</span>) <span class="hljs-keyword">as</span> csvfile:
            reader = csv.DictReader(csvfile)

            <span class="hljs-comment"># Iterate over the rows in the CSV file</span>
            <span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> reader:
                <span class="hljs-comment"># Create a new Book instance</span>
                book = Book(
                    title=row[<span class="hljs-string">'Book Name'</span>],
                    author=row[<span class="hljs-string">'Author Name'</span>]
                )

                <span class="hljs-comment"># Add the book to the session</span>
                db.session.add(book)

            <span class="hljs-keyword">try</span>:
                <span class="hljs-comment"># Commit the session to write the books to the database</span>
                db.session.commit()
                print(<span class="hljs-string">"Books added successfully."</span>)
            <span class="hljs-keyword">except</span> IntegrityError <span class="hljs-keyword">as</span> e:
                db.session.rollback()
                print(<span class="hljs-string">f"Error occurred: <span class="hljs-subst">{e}</span>"</span>)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    seed_data()
</code></pre>
<p>The seeder script is responsible for populating the database with initial data. This is useful for testing and development purposes, allowing you to work with a set of sample data. This script reads data from <strong>data.csv</strong>, and processes it to insert it into the database.</p>
<p><strong>Note</strong>: You can download the <a target="_blank" href="https://github.com/ashutoshkrris/instant-search-with-flask-htmx/blob/main/data.csv">data.csv</a> file from here.</p>
<p>To use this script, ensure your <strong>data.csv</strong> file exists in the same directory as <strong>seeder.py</strong>. Run the script using Python:</p>
<pre><code class="lang-bash">python seeder.py
</code></pre>
<h2 id="heading-how-to-set-up-basic-routing-and-html">How to Set Up Basic Routing and HTML</h2>
<p>In this section, we'll set up a basic route in Flask to serve an index page (<strong>index.html</strong>) where users can search and display books.</p>
<h3 id="heading-how-to-set-up-flask-route">How to Set Up Flask Route</h3>
<p>Let's set up a Flask route (<code>/</code>) to render an <strong>index.html</strong> template and display books. For that, create a <strong>core/routes.py</strong> file and add the following route:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> render_template
<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> app
<span class="hljs-keyword">from</span> core.models <span class="hljs-keyword">import</span> Book

<span class="hljs-meta">@app.route('/')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index</span>():</span>
    <span class="hljs-comment"># Fetch the first 20 books to display by default</span>
    books = Book.query.limit(<span class="hljs-number">20</span>).all()
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"index.html"</span>, books=books)
</code></pre>
<p>The Flask application handles routing through the <code>@app.route('/')</code> decorator, which directs requests to the root URL (<code>/</code>). When a user visits the homepage, the <code>index()</code> function is invoked. </p>
<p>Inside this function, we query the <code>Book</code> model using SQLAlchemy to fetch the first 20 books from the database. These books are then passed as a parameter (<code>books</code>) to the <code>render_template</code> function, which renders the <strong>index.html</strong> template.</p>
<h3 id="heading-how-to-creating-the-indexhtml-template">How to Creating the index.html Template</h3>
<p>Create a file named <strong>index.html</strong> inside a <strong>templates</strong> directory in your project. The <strong>templates</strong> directory will lie in the <code>core</code> package. This file will contain the HTML structure for our book search page.</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Book Search<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"section"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"columns"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"column is-one-third is-offset-one-third"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"query"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table is-fullwidth"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>ID<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Book Title<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Book Author<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"results"</span>&gt;</span>
        {% for book in books %}
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.id }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.author }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        {% endfor %}
      <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This HTML file uses the Bulma CSS framework for styling and includes elements such as an input field for user searches and a table to display book details fetched from the database.</p>
<p>The <code>index.html</code> template utilizes Jinja2 templating to dynamically populate the table rows (<code>&lt;tr&gt;</code>) with book data retrieved from the Flask backend. Each book's <code>ID</code>, <code>title</code>, and <code>author</code> are displayed in the table rows using <code>{{</code><a target="_blank" href="http://book.id"><code>book.id</code></a><code>}}</code>, <code>{{ book.title }}</code>, and <code>{{</code><a target="_blank" href="http://book.author"><code>book.author</code></a><code>}}</code> respectively.</p>
<h3 id="heading-how-to-run-the-application">How to Run the Application</h3>
<p>Let's run the application using the following command:</p>
<pre><code class="lang-bash">flask run
</code></pre>
<p>Once your application is up and running, this what how it should look like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721316465728/d5037fd3-f49b-4c59-993c-4ff7c23cabef.png" alt="Book Search Application Home Page" width="1918" height="937" loading="lazy">
<em>web page with ID, book titles, and book authors</em></p>
<h2 id="heading-how-to-add-htmx-for-instant-search">How to Add HTMX for Instant Search</h2>
<p>Finally, we'll add HTMX to enhance our Flask application with dynamic search capabilities. For this, we'll introduce a new route and modify existing HTML template.</p>
<h3 id="heading-how-to-create-the-search-route">How to Create the Search Route</h3>
<p>First, create a new route <code>/search</code> in your Flask application to handle book searches based on user input:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> render_template, request
<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> app
<span class="hljs-keyword">from</span> core.models <span class="hljs-keyword">import</span> Book

<span class="hljs-meta">@app.route('/search')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">search</span>():</span>
    query = request.args.get(<span class="hljs-string">"query"</span>)
    <span class="hljs-keyword">if</span> query:
        results = Book.query.filter(Book.title.ilike(<span class="hljs-string">f"%<span class="hljs-subst">{query}</span>%"</span>) | Book.author.ilike(<span class="hljs-string">f"%<span class="hljs-subst">{query}</span>%"</span>)).limit(<span class="hljs-number">10</span>).all()
    <span class="hljs-keyword">else</span>:
        results = Book.query.limit(<span class="hljs-number">20</span>).all()
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"search_results.html"</span>, results=results)
</code></pre>
<p>This route listens for <code>GET</code> requests to <code>/search</code>. It retrieves the search query from the URL parameter using <code>request.args.get("query")</code>. </p>
<p>If a <code>query</code> parameter is present, it uses SQLAlchemy's <code>ilike</code> method to perform a case-insensitive search across the <code>title</code> and <code>author</code> columns of the <code>Book</code> table, fetching up to 10 results.</p>
<p>If no query parameter is provided, it defaults to fetching the first 20 books from the database. The results are passed to a new <code>search_results.html</code> template for rendering.</p>
<h3 id="heading-how-to-modify-indexhtml-to-add-htmx">How to Modify index.html to Add HTMX</h3>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Book Search<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"</span> /&gt;</span>
  <span class="hljs-comment">&lt;!-- Include HTMX library --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/htmx.org/dist/htmx.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"section"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"columns"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"column is-one-third is-offset-one-third"</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- HTMX-enabled search input --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">class</span>=<span class="hljs-string">"input"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"query"</span>
            <span class="hljs-attr">hx-get</span>=<span class="hljs-string">"/search"</span>
            <span class="hljs-attr">hx-trigger</span>=<span class="hljs-string">"keyup changed delay:500ms"</span>
            <span class="hljs-attr">hx-target</span>=<span class="hljs-string">"#results"</span>
          /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table is-fullwidth"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>ID<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Book Title<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Book Author<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"results"</span>&gt;</span>
        {% for book in books %}
          <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.id }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.author }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        {% endfor %}
      <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The <code>&lt;script&gt;</code> tag imports the HTMX library from a CDN, enabling client-side interactions without requiring complex JavaScript. In addition to that, we enhanced the <code>&lt;input&gt;</code> element with HTMX attributes:</p>
<ul>
<li><code>hx-get="/search"</code>: Specifies the endpoint (<code>/search</code>) to send GET requests when the user types in the input field.</li>
<li><code>hx-trigger="keyup changed delay:500ms"</code>: Triggers the search action after a 500ms delay when the user types (<code>keyup</code>) or changes the input (<code>changed</code>).</li>
<li><code>hx-target="#results"</code>: Updates the content of the element with <code>id="results"</code> with the response from the <code>/search</code> endpoint.</li>
</ul>
<h3 id="heading-how-to-create-the-searchresultshtml-template">How to Create the search_results.html Template</h3>
<p>Next, we will create a new template <strong>search_results.html</strong> to display search results:</p>
<pre><code class="lang-xml">{% for result in results %}
<span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ result.id }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ result.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ result.author }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
{% endfor %}
</code></pre>
<p>This template iterates over <code>results</code>, which are passed from the <code>/search</code> route. For each book in <code>results</code>, generates a table row (<code>&lt;tr&gt;</code>) that displays the book's ID, title, and author.</p>
<h2 id="heading-demo">Demo</h2>
<p>Finally, we have implemented instant search with HTMX in our Flask application. Here's what our final application should look like:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/llCmZXaopX0" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>You'd notice a delay in the search results. This is called debouncing. It is a technique used in programming and web development to limit the rate at which a function or event handler is executed. It ensures that a function is only executed after a certain amount of time has passed since the last invocation of the function. </p>
<p>In our case, we set the delay to 500ms before it calls the <code>/search</code> API again. This ensures that we do not hit the API for every character the user types.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to implement instant search using Flask and HTMX, focusing on enhancing user interaction and performance. By integrating HTMX for AJAX interactions, we enabled dynamic updates to search results without refreshing the entire page. </p>
<p>This approach not only improves user experience by providing real-time feedback but also optimizes server load by debouncing search queries. </p>
<p>By mastering these techniques, you're equipped to build responsive web applications that deliver seamless search experiences, combining the flexibility of Flask with the interactivity of HTMX to meet diverse user needs efficiently and effectively.</p>
<p>You can find the code for this tutorial in this repository: <a target="_blank" href="https://github.com/ashutoshkrris/instant-search-with-flask-htmx">https://github.com/ashutoshkrris/instant-search-with-flask-htmx</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Magic Link Authentication with React, Flask, and Authsignal ]]>
                </title>
                <description>
                    <![CDATA[ Authentication is the process of verifying the identity of a user or system. It ensures that only authorized individuals or systems can access certain resources or perform specific actions. Magic Link Authentication offers a simple yet secure way for... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/set-up-magic-link-authentication-with-react-flask-and-authsignal/</link>
                <guid isPermaLink="false">66ba0ec19065919bb4e84ca8</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Thu, 11 Jan 2024 18:40:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/magic-link-authsignal.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Authentication is the process of verifying the identity of a user or system. It ensures that only authorized individuals or systems can access certain resources or perform specific actions.</p>
<p>Magic Link Authentication offers a simple yet secure way for users to log in without passwords. This tutorial will walk you through the implementation of Magic Link Authentication using React for the front end, Flask for the back end, and the authentication service provided by <a target="_blank" href="https://www.authsignal.com/">Authsignal</a>.</p>
<h3 id="heading-table-of-contents">Table of Contents:</h3>
<ol>
<li><a class="post-section-overview" href="#heading-understanding-magic-link-authentication">Understanding Magic Link Authentication</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/set-up-magic-link-authentication-with-react-flask-and-authsignal/how-to-configure-authsignal">How to Configure Authsignal</a></li>
<li><a class="post-section-overview" href="#heading-application-flow">Application Flow</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-your-backend-server">How to Set Up Your Backend Server</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-environment-variables">How to Set Up Environment Variables</a></li>
<li><a class="post-section-overview" href="#heading-how-to-initialize-the-authsignal-client">How to Initialize the Authsignal Client</a></li>
<li><a class="post-section-overview" href="#heading-authsignal-actions">Authsignal Actions</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-required-routes">How to Create the Required Routes</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-new-frontend-react-project">How to Set Up a New Frontend React Project</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-components">How to Set Up the Components</a></li>
<li><a class="post-section-overview" href="#heading-how-to-run-the-application">How to Run the Application</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-understanding-magic-link-authentication">Understanding Magic Link Authentication</h2>
<p>Magic link authentication is a convenient and secure authentication method that simplifies users' login process. Instead of entering a username and password, users receive a unique link via email. This link, known as a magic link, grants them access to their account without traditional credentials.</p>
<p>One key difference between magic link authentication and authentication with email verification is the user experience. With magic link authentication, users can authenticate with just a single click. They don't need to remember or enter a password, which can be especially beneficial for users who struggle with password management or find it inconvenient to type in their credentials repeatedly.</p>
<p>While email verification adds an extra layer of security, it may require the user to remember additional credentials or go through multiple steps before accessing their account. If you're interested in learning more about email verification, you can check out my article <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-set-up-email-verification-in-a-flask-app">here</a> to dive deeper into the topic.</p>
<h2 id="heading-how-to-configure-authsignal">How to Configure Authsignal</h2>
<p><a target="_blank" href="https://www.authsignal.com/">Authsignal</a> is a service that makes implementing modern authentication methods (like Magic Links and Passkeys) easier. It provides simple tools to integrate secure login methods into your web apps without hassle.</p>
<p>Before proceeding with the tutorial, you need to create an Authsignal account. To do that, you can follow these steps:</p>
<p>First, go to <a target="_blank" href="https://portal.authsignal.com/users/sign_up">authsignal.com</a> and click on "Create Free Account".</p>
<p>In the next step, create your first tenant. Choose any name for your tenant and select the data storage region.</p>
<p><img src="https://lh7-us.googleusercontent.com/PoQ1Jl8b1fNXmzruv750erSeyi4jxnVlI_QAvoHDH6-O6GVHmDQ07yd2U7WxHrYTUMCyKowll7W-Bs0dBuet9KqiF-mZuV_w8IbFO5tpYziI5M5kaO1ipWEaJPJ7dkPWTNtXyib-BE-8S5VcVtanNNc" alt="Image" width="600" height="400" loading="lazy">
<em>Creating Tenant on Authsignal</em></p>
<p>Next, you need to configure the authenticators you want to use for your application. For example, I have enabled Email Magic Link and Authenticator App (TOTP).</p>
<p><img src="https://lh7-us.googleusercontent.com/AagTYGVbXToDeHqe4S-lFUx2qgIerUbzlUnGTv3sxZ2EyPBzfDeXNcvT-_oeQksckyhGFHX2YY6g8heKHdIz18qf2N_ejed9fJDFA_pSMzfKX3d5Tid4eDnrn7PUbEX_zVh10urhFa49Ek-eSYZJdAA" alt="Image" width="600" height="400" loading="lazy">
<em>Configuring Authenticators</em></p>
<p>Once you have configured the authenticator, navigate to the API Keys option. Here, you will find your Secret Key, which will be necessary for implementing the authentication.</p>
<p><img src="https://lh7-us.googleusercontent.com/UJgdqGLl6IRK8sr3NOsf1BXVp7EJpSFMkxTzdRw0QNhz7DqL5fyGMn7KBotMvrp3ivZnYtw8M-fdVX-aJgNrdszRyAziVCxIAXAxb-g8r42F9ZgQFlpm9D1FYicnhuS4DcS5V7hZ430FM5ruEUioiSw" alt="Image" width="600" height="400" loading="lazy">
<em>Finding your secret key</em></p>
<h2 id="heading-application-flow">Application Flow</h2>
<p>Let's understand the flow of the application:</p>
<h3 id="heading-initial-visit">Initial Visit</h3>
<ul>
<li>The user visits the application's user interface. On the user interface, they see a login input box and a signup option. Since the user is new, they opt to sign up.</li>
</ul>
<h3 id="heading-signup-flow">Signup Flow</h3>
<ul>
<li>Upon clicking the signup link, the user is directed to a page to enter their chosen username.</li>
<li>After entering the username and clicking the signup button, the front end triggers a POST API call to /api/signup, sending the username in the request body.</li>
<li>The backend receives the request and communicates with the Authsignal server for user authentication.</li>
<li>Authsignal prompts the user to set up Magic Link authentication by entering their email address.</li>
<li>Authsignal sends a magic link to the provided email address.</li>
<li>After clicking the magic link, the user is authenticated and redirected to the home page, where they receive a welcome message displaying their email address. The page also includes a logout button.</li>
</ul>
<h3 id="heading-login-flow">Login Flow</h3>
<ul>
<li>The user logs out and returns to the login page.</li>
<li>Here, the user enters their registered username and clicks the Login button.</li>
<li>Upon clicking Login, the front end triggers a POST API call to /api/login, passing the username in the request body.</li>
<li>The backend again communicates with Authsignal for user authentication, prompting the setup of Magic Link authentication.</li>
<li>The user is directed to a page to enter their email address.</li>
<li>Authsignal sends a magic link to the provided email address.</li>
<li>After clicking the magic link, the user is authenticated and redirected to the home page, greeted with a welcome message displaying their email address.</li>
</ul>
<p>This flow ensures users can sign up using a chosen username, and set up Magic Link authentication via email for both signup and login. Here is a video tutorial to visually aid you in understanding the flow:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/kr8frW5Wwcg" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-to-set-up-your-backend-server">How to Set Up Your Backend Server</h2>
<p>In this section, I will guide you through how to set up your Flask server for implementing Magic Link Authentication. Before we begin, it's recommended to set up a virtual environment to isolate your project's dependencies. Here's how you can do it:</p>
<ol>
<li>Open your terminal or command prompt.</li>
<li>Navigate to your project's directory.</li>
<li>Run the following command to create a new virtual environment:</li>
</ol>
<pre><code class="lang-bash">python -m venv myenv
</code></pre>
<p>Note: Replace <code>myenv</code> with the desired name for your virtual environment.</p>
<ol start="4">
<li><p>Activate the virtual environment using the appropriate command for your operating system:</p>
</li>
<li><p>For Windows:</p>
</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> myenv/Scripts/activate
</code></pre>
<ul>
<li>For macOS/Linux:</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> myenv/bin/activate
</code></pre>
<p>Now that you have your virtual environment set up, let's install the necessary dependencies.</p>
<p>To begin, make sure you have Flask installed, which is a micro web framework for Python. You can install it using the following one-liner:</p>
<pre><code class="lang-bash">pip install Flask
</code></pre>
<p>Next, we need <code>python-decouple</code>, a library that helps manage configuration settings in separate files. Install it with the following command:</p>
<pre><code class="lang-bash">pip install python-decouple
</code></pre>
<p>The <code>flask-cors</code> library is a Flask extension that allows for Cross-Origin Resource Sharing (CORS) support in your Flask application.</p>
<pre><code class="lang-bash">pip install flask-cors
</code></pre>
<p>Finally, we need to install the Python SDK for Authsignal. You can install it with the following command:</p>
<pre><code class="lang-bash">pip install authsignal
</code></pre>
<p>Now that we have all the necessary dependencies installed, let's create a sample Flask server to get started with Magic Link Authentication. Here's a basic setup to help you get started:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_cors <span class="hljs-keyword">import</span> CORS

app = Flask(__name__)
CORS(app, supports_credentials=<span class="hljs-literal">True</span>)

<span class="hljs-meta">@app.route("/")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hello</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello, world!"</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<p>In the next steps, we will integrate AuthSignal and implement the Magic Link Authentication functionality into this server.</p>
<h2 id="heading-how-to-set-up-environment-variables">How to Set Up Environment Variables</h2>
<p>To successfully configure and integrate AuthSignal into your Flask server, you need to set up the following environment variables:</p>
<ul>
<li><code>AUTHSIGNAL_BASE_URL</code>: This variable contains the base URL of the Authsignal server. It allows your server to communicate with Authsignal's authentication service.</li>
<li><code>AUTHSIGNAL_SECRET_KEY</code>: This variable contains the secret key associated with your Authsignal project. It is used for secure communication between your server and AuthSignal.</li>
<li><code>SECRET_KEY</code>: This variable is a random key used to encrypt the cookies and send them to the browser.</li>
</ul>
<p>Setting environment variables instead of hardcoding in the code provides improved security by keeping sensitive information, such as API keys and secret keys, separate from the codebase. This reduces the risk of accidental exposure or unauthorized access to these credentials.</p>
<p>To set up these environment variables, you can follow these steps:</p>
<ol>
<li>Open a terminal or command prompt.</li>
<li>Navigate to the directory where your Flask server is located.</li>
<li>Create a <code>.env</code> file and export the environment variables using the following commands:</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-built_in">export</span> AUTHSIGNAL_BASE_URL=&lt;base_url&gt;
<span class="hljs-built_in">export</span> AUTHSIGNAL_SECRET_KEY=&lt;secret_key&gt;
<span class="hljs-built_in">export</span> SECRET_KEY=&lt;random-secret-key&gt;
</code></pre>
<p>Make sure to replace <code>&lt;base_url&gt;</code>, <code>&lt;secret_key&gt;</code>, and <code>&lt;random-secret-key&gt;</code> with the appropriate values for your Authsignal project. You can find the values for these environment variables in the API Keys section of the Authsignal dashboard as explained earlier.</p>
<p>Note: The method for setting environment variables can vary depending on your operating system. The above commands are applicable for Unix-based systems. For Windows, you can use the <code>set</code> command instead of <code>export</code>.</p>
<p>To export the variables added in the .env file, you can use the following command in the terminal:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> .env
</code></pre>
<p>By properly setting these environment variables, your Flask server can securely communicate with Authsignal and implement the Magic Link Authentication functionality.</p>
<h2 id="heading-how-to-initialize-the-authsignal-client">How to Initialize the Authsignal Client</h2>
<p>To integrate Authsignal into your Flask server and implement Magic Link Authentication, you need to initialize the Authsignal client. Here's an example of how you can do this:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_cors <span class="hljs-keyword">import</span> CORS
<span class="hljs-keyword">import</span> authsignal.client
<span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config

app = Flask(__name__)
CORS(app)

AUTHSIGNAL_BASE_URL = config(<span class="hljs-string">"AUTHSIGNAL_BASE_URL"</span>)
AUTHSIGNAL_SECRET_KEY = config(<span class="hljs-string">"AUTHSIGNAL_SECRET_KEY"</span>)
SECRET_KEY = config(<span class="hljs-string">"SECRET_KEY"</span>)

authsignal_client = authsignal.Client(
    api_key=AUTHSIGNAL_SECRET_KEY,
    api_url=AUTHSIGNAL_BASE_URL
)
</code></pre>
<p>In this code snippet, we first import the <code>authsignal.client</code>, the Python SDK for Authsignal. We also import config from python-decouple to retrieve the environment variables.</p>
<p>We retrieve the environment variables <code>AUTHSIGNAL_BASE_URL</code>, <code>AUTHSIGNAL_SECRET_KEY</code> and <code>SECRET_KEY</code> using config from python-decouple.</p>
<p>Finally, we initialize the <code>authsignal.Client</code> by passing in the API key <code>AUTHSIGNAL_SECRET_KEY</code> and the base URL of the Authsignal server <code>AUTHSIGNAL_BASE_URL</code>.</p>
<p>By initializing the Authsignal client, we are ready to implement the Magic Link Authentication functionality in our Flask server.</p>
<h2 id="heading-authsignal-actions">Authsignal Actions</h2>
<p>Authsignal allows you to create actions to track and manage user interactions in your application. Actions are events that can be triggered by users, such as signing up or logging in. By creating custom actions, you can have more control over the authentication process and implement specific authentication methods like Magic Link Authentication.</p>
<p>To create an action on your Authsignal dashboard, follow these steps:</p>
<ol>
<li>Click on "<strong>Actions</strong>" in your Authsignal dashboard.</li>
<li>Click on "<strong>Configure a new action</strong>" to create a new action.</li>
<li>Enter a name for the action that describes its purpose or the user interaction it represents.</li>
<li>Next, you can configure the rule for the action. In our case, since we want to implement Magic Link Authentication, we will add a rule to challenge users with Email Magic Link. This will send a magic link to the user's email for authentication.</li>
<li>Save the action to apply the rule and make it active.</li>
</ol>
<p>Here is a video demonstrating the process of creating an Authsignal action and configuring it for Magic Link Authentication:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/action.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Creating action on Authsignal</em></p>
<p>You can create two actions – "<strong>signUp</strong>" and "<strong>signIn</strong>". In the next steps, we will make use of these actions.</p>
<h2 id="heading-how-to-create-the-required-routes">How to Create the Required Routes</h2>
<p>Finally, to implement the Magic Link Authentication, we need to create three routes: <code>/api/signup</code>, <code>/api/login</code>, <code>/api/callback</code>, and <code>/api/user</code>.</p>
<h3 id="heading-apisignup-route"><code>/api/signup</code> Route</h3>
<p>The <code>/api/signup</code> route is responsible for allowing the users to register in our application. Here's how we implement it:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route('/api/signup', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">signup</span>():</span>
    username = request.json.get(<span class="hljs-string">'username'</span>)
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> username:
        <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'error'</span>: <span class="hljs-string">'Missing username parameter'</span>}), <span class="hljs-number">400</span>

    response = authsignal_client.track(
        user_id=username,
        action=<span class="hljs-string">"signUp"</span>,
        payload={
            <span class="hljs-string">"user_id"</span>: username,
            <span class="hljs-string">"redirectUrl"</span>: <span class="hljs-string">"http://localhost:5000/api/callback"</span>
        }
    )
    <span class="hljs-keyword">return</span> jsonify(response), <span class="hljs-number">200</span>
</code></pre>
<p>In this implementation, the route expects a JSON payload containing the <code>username</code> parameter. It then uses the <code>authsignal_client</code> to track the user's <strong>signUp</strong> action and generate a Magic Link. The <code>track</code> method lets you record actions performed by users and initiate challenges. The <code>redirectUrl</code> specifies the URL where the user will be redirected after they have been authenticated. We will create this API next.</p>
<h3 id="heading-apicallback-route"><code>/api/callback</code> Route</h3>
<p>The <code>/api/callback</code> route handles the callback URL where the user is redirected after verifying themselves. Here's the implementation for this route:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route('/api/callback', methods=['GET'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">callback</span>():</span>
    token = request.args.get(<span class="hljs-string">'token'</span>)
    challenge_response = authsignal_client.validate_challenge(token)

    <span class="hljs-keyword">if</span> challenge_response[<span class="hljs-string">"state"</span>] == <span class="hljs-string">'CHALLENGE_SUCCEEDED'</span>:
        encoded_token = jwt.encode(
            payload={<span class="hljs-string">"username"</span>: challenge_response[<span class="hljs-string">"user_id"</span>]},
            key=SECRET_KEY,
            algorithm=<span class="hljs-string">"HS256"</span>
        )
        response = redirect(<span class="hljs-string">'http://localhost:3000/'</span>)
        response.set_cookie(
            key=<span class="hljs-string">'auth-session'</span>,
            value=encoded_token,
            secure=<span class="hljs-literal">False</span>,
            path=<span class="hljs-string">'/'</span>
        )
        <span class="hljs-keyword">return</span> response

    <span class="hljs-keyword">return</span> redirect(<span class="hljs-string">"/"</span>)
</code></pre>
<p>When the users are redirected, Authsignal adds the JWT token in the URL as a token query parameter. </p>
<p>In this implementation, the route retrieves the token parameter from the query string. It then uses the <code>authsignal_client</code> to validate the challenge and check if the authentication was successful. </p>
<p>If the authentication succeeds, we encode a JSON Web Token (JWT). The token payload includes the <code>username</code> obtained from the challenge response. It uses the <code>SECRET_KEY</code> and the <em>HS256 algorithm</em> for encryption. </p>
<p>Next, the user is redirected to the home page (http://localhost:3000/), and a <code>auth-session</code> cookie is set with the encoded token for further user identification.</p>
<p>Note that the token returned from Authsignal in the redirect is not intended to be used as a session token. It just contains information about the challenge so that we can determine if the challenge was successful.</p>
<h3 id="heading-apilogin-route"><code>/api/login</code> Route</h3>
<p>The <code>/api/login</code> route is responsible for allowing the users to log into the application. Here’s the implementation for the route:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route('/api/login', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">login</span>():</span>
    username = request.json.get(<span class="hljs-string">'username'</span>)
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> username:
        <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'error'</span>: <span class="hljs-string">'Missing username parameter'</span>}), <span class="hljs-number">400</span>

    response = authsignal_client.track(
        user_id=username,
        action=<span class="hljs-string">"signIn"</span>,
        payload={
            <span class="hljs-string">"user_id"</span>: username,
            <span class="hljs-string">"redirectUrl"</span>: <span class="hljs-string">"http://localhost:5000/api/callback"</span>
        }
    )
    <span class="hljs-keyword">return</span> jsonify(response), <span class="hljs-number">200</span>
</code></pre>
<p>The route is configured to handle POST requests on the <code>/api/login</code> endpoint. Upon receiving a POST request, the route first extracts the provided <code>username</code> from the JSON payload sent with the request. It ensures that the username is present. If not, it promptly returns a 400 error response indicating a missing username parameter.</p>
<p>Similar to the signup flow, it then uses the <code>authsignal_client</code> to track the user's <strong>signIn</strong> action and generate a Magic Link. The redirectUrl specifies the URL where the user will be redirected after they have been authenticated.</p>
<h3 id="heading-apiuser-route"><strong><code>/api/user</code> Route</strong></h3>
<p>The <code>/api/user</code> route is responsible for retrieving user information. Here's the implementation for this route:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route("/api/user", methods=['GET'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user</span>():</span>
    token = request.cookies.get(<span class="hljs-string">'auth-session'</span>)
    decoded_token = jwt.decode(token, SECRET_KEY, algorithms=[<span class="hljs-string">"HS256"</span>])
    username = decoded_token.get(<span class="hljs-string">'username'</span>)
    response = authsignal_client.get_user(user_id=username)
    <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">"username"</span>: username, <span class="hljs-string">"email"</span>: response[<span class="hljs-string">"email"</span>]}), <span class="hljs-number">200</span>
</code></pre>
<p>In this implementation, the GET endpoint starts by extracting the auth-session cookie from the incoming request. Then it decodes the JWT using the jwt.decode method, utilizing the <code>SECRET_KEY</code> as the secret key for decoding. </p>
<p>The decoded token provides the username of the user. It then uses the <code>authsignal_client</code> to retrieve user information based on the provided <code>userId</code>. It then returns a JSON response with the username and email information.</p>
<p>By implementing these routes, we will be able to handle the basic authentication process and retrieve user information in our Flask server.</p>
<h2 id="heading-how-to-set-up-a-new-frontend-react-project">How to Set Up a New Frontend React Project</h2>
<p>Let's set up our front-end project in this section. This will also include setting up routing in the application.</p>
<p>Start by initializing a new React project using <code>create-react-app</code> or any preferred method (<a target="_blank" href="https://www.freecodecamp.org/news/complete-vite-course-for-beginners/">like Vite</a>, for example, which is a more modern way to set up a React app). This command sets up the basic structure for your React application.</p>
<pre><code class="lang-bash">npx create-react-app magic-link-auth
<span class="hljs-built_in">cd</span> magic-link-auth
</code></pre>
<p>Once the project is created and you're inside the project directory, install the required dependencies. Here, we need <code>react-router-dom</code> for handling routing and <code>bootstrap</code> for easy styling.</p>
<pre><code class="lang-bash">npm install react-router-dom bootstrap
</code></pre>
<h3 id="heading-import-bootstrap-css">Import Bootstrap CSS</h3>
<p>Bootstrap provides pre-styled components and utilities for easier and faster styling of your application.</p>
<p>In the <code>index.js</code> file, import Bootstrap:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>;
<span class="hljs-keyword">import</span> reportWebVitals <span class="hljs-keyword">from</span> <span class="hljs-string">'./reportWebVitals'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"bootstrap/dist/css/bootstrap.min.css"</span>; <span class="hljs-comment">// Import Bootstrap CSS</span>

<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>));
root.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>
);

<span class="hljs-comment">// If you want to start measuring performance in your app, pass a function</span>
<span class="hljs-comment">// to log results (for example: reportWebVitals(console.log))</span>
<span class="hljs-comment">// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals</span>
reportWebVitals();
</code></pre>
<p>Additionally, we will write some custom CSS. Replace the code in the <code>index.css</code> file with the following code:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">html</span>,
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">font-family</span>: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}

* {
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">5rem</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
}

<span class="hljs-selector-tag">code</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#fafafa</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.75rem</span>;
  <span class="hljs-attribute">font-family</span>: Menlo, Monaco, Lucida Console, Courier New, monospace;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"button"</span>]</span> {
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">background</span>: cornflowerblue;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">12px</span> <span class="hljs-number">24px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
}
</code></pre>
<p>Similarly, replace the code in the <code>App.css</code> with the following code:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.mainContainer</span> {
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
}

<span class="hljs-selector-class">.titleContainer</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">48px</span>;
  <span class="hljs-attribute">font-weight</span>: bolder;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-class">.resultContainer</span>,
<span class="hljs-selector-class">.historyItem</span> {
  <span class="hljs-attribute">flex-direction</span>: row;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: space-between;
}

<span class="hljs-selector-class">.historyContainer</span> {
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">200px</span>;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">flex-grow</span>: <span class="hljs-number">5</span>;
  <span class="hljs-attribute">justify-content</span>: flex-start;
}

<span class="hljs-selector-class">.buttonContainer</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">260px</span>;
}

<span class="hljs-selector-class">.inputContainer</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">align-items</span>: flex-start;
  <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-class">.inputContainer</span>&gt;<span class="hljs-selector-class">.errorLabel</span> {
  <span class="hljs-attribute">color</span>: red;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-class">.inputBox</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">48px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">font-size</span>: medium;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid grey;
  <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">8px</span>;
}

<span class="hljs-selector-class">.inputButton</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">48px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
}
</code></pre>
<h3 id="heading-set-up-routing">Set Up Routing</h3>
<p>Routing in React applications helps navigate between different views or pages. <code>react-router-dom</code> simplifies this process.</p>
<p>In your <code>App.js</code> file, configure the routing:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { BrowserRouter, Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> Dashboard <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages/Dashboard"</span>;
<span class="hljs-keyword">import</span> Register <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages/Register"</span>;
<span class="hljs-keyword">import</span> Login <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages/Login"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Dashboard</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/login"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Login</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/signup"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Register</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>It defines an App component that encapsulates the entire application structure within a <code>&lt;BrowserRouter&gt;</code> component. Inside <code>&lt;Routes&gt;</code>, we define three  components: one for the root path <code>/</code> rendering the <code>Dashboard</code> component, and two for the <code>/login</code> and <code>/signup</code>  paths, rendering the <code>Login</code> and <code>Register</code> components respectively. </p>
<p>This setup enables navigation between different views based on URL paths, allowing users to access specific components when they visit corresponding routes within the application.</p>
<p>In the upcoming sections, we will set up the above-mentioned three components.</p>
<h2 id="heading-how-to-set-up-the-components">How to Set Up the Components</h2>
<p>In the previous section, we imported two components from the <code>src/pages</code> folder. Let's create a <code>pages</code> folder inside the <code>src</code> folder, and then we can start creating the components.</p>
<h3 id="heading-register-component">Register Component</h3>
<p>Let’s create a <code>Register.jsx</code> file inside the pages folder. The <strong>Register</strong> component allows users to register within our application.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useNavigate, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">const</span> Register = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [usernameError, setUsernameError] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> navigate = useNavigate();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> isAuthenticated = checkCookies();
    <span class="hljs-keyword">if</span> (isAuthenticated) {
      navigate(<span class="hljs-string">"/"</span>);
    }
  }, [navigate]);

  <span class="hljs-keyword">const</span> checkCookies = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> authSessionCookie = <span class="hljs-built_in">document</span>.cookie.match(<span class="hljs-string">"auth-session=([^;]+)"</span>);

    <span class="hljs-keyword">return</span> !!authSessionCookie;
  };

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

    <span class="hljs-keyword">if</span> (<span class="hljs-string">""</span> === username) {
      setUsernameError(<span class="hljs-string">"Username is mandatory!"</span>);
      <span class="hljs-keyword">return</span>;
    }

    signup();
  };

  <span class="hljs-keyword">const</span> signup = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:5000/api/login"</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        username,
      }),
      <span class="hljs-attr">credentials</span>: <span class="hljs-string">"include"</span>,
    });

    <span class="hljs-keyword">const</span> { url } = <span class="hljs-keyword">await</span> response.json();

    <span class="hljs-comment">// Redirect to verification URL</span>
    <span class="hljs-built_in">window</span>.location.href = url;
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">mainContainer</span>"}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">titleContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Sign Up<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{username}</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your username"</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setUsername(e.target.value)}
          className={"inputBox"}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorLabel text-center"</span>&gt;</span>{usernameError}<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputButton</span>"}
          <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onButtonClick}</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">Sign</span> <span class="hljs-attr">Up</span>"}
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        Existing User? <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/login"</span>&gt;</span>Login here<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Register;
</code></pre>
<p>The component initializes state variables using <code>useState</code> to manage the visibility of the <code>usernameError</code> and store the username input in <code>userName</code>. It also initializes the <code>navigate</code> function from <code>useNavigate</code> to handle navigation within the application.</p>
<p>We use the <code>useEffect</code> hook to check for authentication cookies when the component mounts. It calls the <code>checkCookies</code> function, which checks for the existence of cookies that we had set from the backend server. If <code>auth-session</code> cookie is found, the user is automatically redirected to the root URL using navigate("/").</p>
<p>Clicking the “Sign Up” button triggers the <code>onButtonClick</code> function. It first checks whether the user has entered the username. If not, it shows an error message using the <code>usernameError</code>. If the user has entered the username, it calls the <code>signup</code> function.</p>
<p>The <code>signup</code> performs an asynchronous POST request to the <code>/api/signup</code> endpoint with the provided username. Upon successful response, it redirects the user to the received verification URL by changing window.location.href.</p>
<p>The JSX returned by the component defines the UI layout that looks like the below:</p>
<p><img src="https://lh7-us.googleusercontent.com/gncsDRe9QVK20DWMkiWwdGOt_ZymbSVXTv-8UGvyKIpp5-TZ64-DwLGLbMtDM0B-wgXh8jNOCdkA0kia3-gJftMxFaH-za_4O0cqCSvK9GLMHSbO_nH_UfgGIf5QhHaOZg559_N0c4P9Oof4O5JmkPE" alt="Image" width="600" height="400" loading="lazy">
<em>Register UI Component</em></p>
<p>It includes an input field for the users to enter their username and a "Sign Up" button. Below the button, we have a link to the Login page for the existing users to log in.</p>
<h3 id="heading-login-component">Login Component</h3>
<p>We have kept the login page similar to the signup page for simplicity. Hence, the Login component is pretty much the same as the Register component.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useNavigate, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">const</span> Login = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [usernameError, setUsernameError] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> navigate = useNavigate();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> isAuthenticated = checkCookies();
    <span class="hljs-keyword">if</span> (isAuthenticated) {
      navigate(<span class="hljs-string">"/"</span>);
    }
  }, [navigate]);

  <span class="hljs-keyword">const</span> checkCookies = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> authSessionCookie = <span class="hljs-built_in">document</span>.cookie.match(<span class="hljs-string">"auth-session=([^;]+)"</span>);

    <span class="hljs-keyword">return</span> !!authSessionCookie;
  };

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

    <span class="hljs-keyword">if</span> (<span class="hljs-string">""</span> === username) {
      setUsernameError(<span class="hljs-string">"Username is mandatory!"</span>);
      <span class="hljs-keyword">return</span>;
    }

    login();
  };

  <span class="hljs-keyword">const</span> login = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:5000/api/login"</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        username,
      }),
      <span class="hljs-attr">credentials</span>: <span class="hljs-string">"include"</span>,
    });

    <span class="hljs-keyword">const</span> { url } = <span class="hljs-keyword">await</span> response.json();

    <span class="hljs-comment">// Redirect to verification URL</span>
    <span class="hljs-built_in">window</span>.location.href = url;
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">mainContainer</span>"}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">titleContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{username}</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your username"</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(ev)</span> =&gt;</span> setUsername(ev.target.value)}
          className={"inputBox"}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorLabel text-center"</span>&gt;</span>{usernameError}<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputButton</span>"}
          <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onButtonClick}</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">Log</span> <span class="hljs-attr">in</span>"}
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        New User? <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/signup"</span>&gt;</span>Sign up here<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Login;
</code></pre>
<p>The only significant difference other than the text and button in the UI here is that we will be making the API call to the <code>/api/login</code> route when the users hit the Login button.</p>
<p>The UI looks like below:</p>
<p><img src="https://lh7-us.googleusercontent.com/F4EDOhuMbTRtXt3UxhpLYdZPT8XtCuYWjEX3H95bEXEZatLDsuRxaut3KZ3ZtyHSWIQ1WkuA5WWUxZcXrCBHyCMfMG-LQTKjnQHXyY8Y2Ha93YstE0Kycd9ji9lj33wMc1D8Km7pFNu5EGyQh14D9m8" alt="Image" width="600" height="400" loading="lazy">
<em>Login UI Component</em></p>
<h3 id="heading-dashboard-component">Dashboard Component</h3>
<p>The Dashboard component in our application serves as the interface for authenticated users, displaying a welcome message with the user’s email and enabling user logout functionality. </p>
<p>Let’s create a <code>Dashboard.jsx</code> file inside the <code>pages</code> folder.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">const</span> Dashboard = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [userEmail, setUserEmail] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> navigate = useNavigate();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> checkCookies = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> authSessionCookie = <span class="hljs-built_in">document</span>.cookie.match(<span class="hljs-string">"auth-session=([^;]+)"</span>);

      <span class="hljs-keyword">if</span> (!authSessionCookie) {
        navigate(<span class="hljs-string">"/auth"</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
      }

      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    };

    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> cookiesValid = <span class="hljs-keyword">await</span> checkCookies();
      <span class="hljs-keyword">if</span> (!cookiesValid) <span class="hljs-keyword">return</span>;

      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:5000/api/user"</span>, {
          <span class="hljs-attr">method</span>: <span class="hljs-string">"GET"</span>,
          <span class="hljs-attr">headers</span>: {
            <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
          },
          <span class="hljs-attr">credentials</span>: <span class="hljs-string">"include"</span>
        });

        <span class="hljs-keyword">if</span> (!response.ok) {
          <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Failed to fetch user data"</span>);
        }

        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
        setUserEmail(data.email);
      } <span class="hljs-keyword">catch</span> (error) {
        navigate(<span class="hljs-string">"/auth"</span>);
      }
    };

    fetchData();
  }, [navigate]);

  <span class="hljs-keyword">const</span> handleLogout = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">document</span>.cookie = <span class="hljs-string">`auth-session=; max-age=0`</span>;
    navigate(<span class="hljs-string">"/auth"</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"d-flex justify-content-center align-items-center vh-100"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-3 text-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Welcome Home!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"lead"</span>&gt;</span>You're logged in as {userEmail}!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"d-flex justify-content-center"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"btn btn-lg btn-dark fw-bold border-white bg-dark"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleLogout}</span>
          &gt;</span>
            Log Out
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Dashboard;
</code></pre>
<p>Upon component mounting or when <code>navigate</code> changes (a dependency of <code>useEffect</code>), the effect runs. It begins by defining two asynchronous functions. The first, <code>checkCookies</code>, verifies the presence of <code>auth-session</code> cookies. If it is missing, it redirects the user to the authentication route.</p>
<p>The second function, <code>fetchData</code>, is responsible for fetching user data. It checks the validity of cookies using <code>checkCookies</code>. Upon verification, it sends a GET request to our back-end API endpoint. Upon successful response, it updates the <code>userEmail</code> state with the user's email fetched from the API data. </p>
<p>If any error occurs during this process, such as failing to fetch user data, it redirects the user back to the authentication route.</p>
<p>The JSX returned by the component renders a simple dashboard layout.</p>
<p><img src="https://lh7-us.googleusercontent.com/ca-epjkteyLzE_dVbbWN6bC5fMVogCJLRvR8Milfjl7UzoHRK7462_YJZhkJvhoTpBtD0sNFwpGbNaLTKNEuBg6wKSxv6j5-ApmjpOtPgx-UkeM8i39A0KwAuU3L2TeRc8R_3aXugnAMcH4iGrlBP0M" alt="Image" width="600" height="400" loading="lazy">
<em>Dashboard UI Component</em></p>
<p>The displayed content includes a welcoming message and the currently logged-in user's email. There's also a "Log Out" button which, upon clicking, initiates the logout process by triggering the <code>handleLogout</code> function. It removes the <code>auth-session</code> cookies by setting their max-age to 0, effectively expiring them. Afterward, it redirects the user to the authentication route.</p>
<h2 id="heading-how-to-run-the-application">How to Run the Application</h2>
<p>You can find the code of the final application in this <a target="_blank" href="https://github.com/ashutoshkrris/authsignal-magic-link-demo">GitHub repository</a>. To run your backend application, run <code>python app.py</code> from your back-end folder in your terminal. This will start your back-end server on port 5000. Next, run the frontend application using the <code>npm start</code> command. This will start your frontend application on the port 3000.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this tutorial, you learned how to use Authsignal to implement basic user authentication with email verification through magic links. </p>
<p>Authsignal makes handling users and keeping things safe easier, letting developers focus on improving apps. It also removes the overhead of remembering another password for the users of the application.</p>
<p>To learn more about Authsignal, <a target="_blank" href="https://docs.authsignal.com/">visit the Authsignal documentation</a>.</p>
<p>Should you have any issues or questions related to the tutorial, then feel free to reach out to me on <a target="_blank" href="https://twitter.com/ashutoshkrris">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Python One-Liners to Help You Write Simple, Readable Code ]]>
                </title>
                <description>
                    <![CDATA[ Python's beauty lies in its simplicity and readability. And mastering the art of writing concise yet powerful code can significantly enhance your productivity as a developer. I'm talking about really short lines of code that do big things. In this ar... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/python-one-liners/</link>
                <guid isPermaLink="false">66ba0eb29065919bb4e84ca3</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Tue, 28 Nov 2023 16:58:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/one-liners-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Python's beauty lies in its simplicity and readability. And mastering the art of writing concise yet powerful code can significantly enhance your productivity as a developer. I'm talking about really short lines of code that do big things.</p>
<p>In this article, we'll explore 8 essential Python one-liners that every Pythonista should have in their toolkit. From list comprehensions to lambda functions and beyond, these techniques offer elegant solutions to common programming challenges, helping you write cleaner, more efficient code.</p>
<h2 id="heading-list-comprehension">List Comprehension</h2>
<p>List comprehension is a Pythonic way to create lists with a single line of code. It offers a concise alternative to traditional loops, enabling you to generate lists quickly and efficiently.</p>
<p>Let's say you want to create a list containing squares of numbers from 0 to 9. Using a traditional loop, you'd do it like this:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using a traditional loop</span>
squared_numbers = []
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>):
    squared_numbers.append(i ** <span class="hljs-number">2</span>)
print(squared_numbers)
</code></pre>
<p>The traditional loop method requires more lines of code and explicitly defines the iteration process, appending each squared number to the list step by step.</p>
<p>On the other hand, list comprehension can achieve the same result in a single line, making the code more concise and readable. It condenses the loop into a clear, compact structure, generating the squared numbers directly into a list.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using list comprehension</span>
squared_numbers = [i ** <span class="hljs-number">2</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>)]
print(squared_numbers)
</code></pre>
<p>You can use list comprehensions when you need to apply a simple operation to every element in a sequence, such as transforming a list of numbers or strings.</p>
<p>You can learn how you can pack and destructure lists in Python <a target="_blank" href="https://blog.ashutoshkrris.in/mastering-list-destructuring-and-packing-in-python-a-comprehensive-guide">here</a>.</p>
<h2 id="heading-lambda-functions">Lambda Functions</h2>
<p><a target="_blank" href="https://blog.ashutoshkrris.in/mastering-lambdas-a-guide-to-anonymous-functions-in-python">Lambda functions</a>, also known as anonymous functions, allow you to create small, throwaway functions without explicitly defining them with <code>def</code>. They are particularly useful in scenarios where a function is needed for a short operation.</p>
<p>First, let's look at an example using <code>def</code>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using def</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_numbers</span>(<span class="hljs-params">x, y</span>):</span>
    <span class="hljs-keyword">return</span> x + y

print(add_numbers(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>))
</code></pre>
<p>In this code, the <code>def</code> keyword is used to define a named function <code>add_numbers</code> explicitly. It takes an argument <code>x</code> and <code>y</code> and returns the sum of them. This traditional approach provides a named function that can be called multiple times.</p>
<p>But when you need a function just for one-time usage, you can just define an anonymous function using the <code>lambda</code> keyword like this:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using Lambda</span>
add = <span class="hljs-keyword">lambda</span> x, y: x + y
print(add(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>))
</code></pre>
<p>It achieves the same result as <code>add_numbers</code> but in a single line without assigning a name explicitly. Lambda functions are useful for short, throwaway functions that are used infrequently or as part of other expressions.</p>
<h2 id="heading-map-and-filter">Map and Filter</h2>
<p>The <code>map</code> and <code>filter</code> functions are powerful tools for working with iterables, allowing concise manipulation and filtering of data.</p>
<p>Let's say you have a list of strings and you want to convert each item of the list into uppercase.</p>
<pre><code class="lang-python">fruits = [<span class="hljs-string">'apple'</span>, <span class="hljs-string">'banana'</span>, <span class="hljs-string">'cherry'</span>]
upper_case_loop = []
<span class="hljs-keyword">for</span> fruit <span class="hljs-keyword">in</span> fruits:
    upper_case_loop.append(fruit.upper())
print(upper_case_loop)
</code></pre>
<p>Now, you can achieve the same using the <code>map</code> function:</p>
<pre><code class="lang-python">upper_case = list(map(<span class="hljs-keyword">lambda</span> x: x.upper(), [<span class="hljs-string">'apple'</span>, <span class="hljs-string">'banana'</span>, <span class="hljs-string">'cherry'</span>]))
</code></pre>
<p>You can utilize <code>map</code> when you need to perform an operation on every element of an iterable. <code>filter</code> is handy for selectively choosing elements based on a condition.</p>
<p>You can learn more about the <code>map</code>, <code>filter</code> and <code>reduce</code> functions <a target="_blank" href="https://blog.ashutoshkrris.in/mastering-lambdas-a-guide-to-anonymous-functions-in-python#heading-using-lambda-functions-as-arguments-in-higher-order-functions-map-filter-reduce">here</a>.</p>
<h2 id="heading-ternary-operator">Ternary Operator</h2>
<p>The ternary operator provides a condensed way to write conditional statements in a single line, enhancing code readability.</p>
<p>Let's say, you have a number and you want to check if it's even or odd. You can do it using the traditional if condition as below:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Traditional if</span>
result = <span class="hljs-literal">None</span>
num = <span class="hljs-number">5</span>
<span class="hljs-keyword">if</span> num % <span class="hljs-number">2</span> == <span class="hljs-number">0</span>:
    result = <span class="hljs-string">"Even"</span>
<span class="hljs-keyword">else</span>:
    result = <span class="hljs-string">"Odd"</span>
</code></pre>
<p>But you can achieve the same results in a single line using the ternary operator:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Ternary Operator</span>
num = <span class="hljs-number">7</span>
result = <span class="hljs-string">"Even"</span> <span class="hljs-keyword">if</span> num % <span class="hljs-number">2</span> == <span class="hljs-number">0</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"Odd"</span>
</code></pre>
<p>When you need to assign values based on conditions, especially in situations requiring simple if-else checks, the ternary operator shines.</p>
<h2 id="heading-zip-function">Zip Function</h2>
<p>The <code>zip</code> function enables you to combine multiple iterables element-wise, forming tuples of corresponding elements.</p>
<p>Let's assume you have two lists: one containing the names of students and the other containing their respective grades for a specific assignment.</p>
<pre><code class="lang-python">students = [<span class="hljs-string">'Dilli'</span>, <span class="hljs-string">'Vikram'</span>, <span class="hljs-string">'Rolex'</span>, <span class="hljs-string">'Leo'</span>]
grades = [<span class="hljs-number">85</span>, <span class="hljs-number">92</span>, <span class="hljs-number">78</span>, <span class="hljs-number">88</span>]
</code></pre>
<p>Now, you want to create a report that pairs each student's name with their grade for easy comprehension or further analysis. You can do it by iterating over the list and appending them to a new list as below:</p>
<pre><code class="lang-python">students = [<span class="hljs-string">'Dilli'</span>, <span class="hljs-string">'Vikram'</span>, <span class="hljs-string">'Rolex'</span>, <span class="hljs-string">'Leo'</span>]
grades = [<span class="hljs-number">85</span>, <span class="hljs-number">92</span>, <span class="hljs-number">78</span>, <span class="hljs-number">88</span>]

student_grade_pairs = []
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(students)):
    student_grade_pairs.append((students[i], grades[i]))

print(student_grade_pairs)
</code></pre>
<p>The above loop method manually pairs elements from two lists by iterating through their indices, accessing elements at the same positions, and appending tuples of those elements into a new list <code>student_grade_pairs</code>.</p>
<p>But, what if I tell you that we can achieve the same pairing effect in one line using the <code>zip</code> function as below:</p>
<pre><code class="lang-python">students = [<span class="hljs-string">'Dilli'</span>, <span class="hljs-string">'Vikram'</span>, <span class="hljs-string">'Rolex'</span>, <span class="hljs-string">'Leo'</span>]
grades = [<span class="hljs-number">85</span>, <span class="hljs-number">92</span>, <span class="hljs-number">78</span>, <span class="hljs-number">88</span>]

student_grade_pairs = list(zip(students, grades))
print(student_grade_pairs)
</code></pre>
<p>The <code>zip</code> function elegantly combines elements from both lists, creating pairs of corresponding elements as tuples. The result <code>student_grade_pairs</code> is a list of tuples, where each tuple contains an element from the grades list paired with the corresponding element from the students list.</p>
<p>You can learn more about the <code>zip</code>  function <a target="_blank" href="https://blog.ashutoshkrris.in/zipping-through-python-a-comprehensive-guide-to-the-zip-function">here</a>.</p>
<h2 id="heading-enumerate-function">Enumerate Function</h2>
<p>The <code>enumerate</code> function offers a concise way to iterate over a sequence while keeping track of the index.</p>
<p>Let's say you're developing a feature where users can add items to their shopping list, and you want to display the items along with their position or index in the list for easy reference.</p>
<p>You can do it using a traditional for-loop as below:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Simulating a grocery list</span>
grocery_list = [<span class="hljs-string">'Apples'</span>, <span class="hljs-string">'Milk'</span>, <span class="hljs-string">'Bread'</span>, <span class="hljs-string">'Eggs'</span>, <span class="hljs-string">'Cheese'</span>]

<span class="hljs-comment"># Displaying the grocery list with indices</span>
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(grocery_list)):
    print(<span class="hljs-string">f"<span class="hljs-subst">{i}</span>. <span class="hljs-subst">{grocery_list[i]}</span>"</span>)
</code></pre>
<p>The traditional loop with manual indexing involves using <code>range</code> along with <code>len</code> to generate indices that are then used to access elements in the <code>grocery_list</code> list. This method requires more code and is less readable due to the explicit handling of indices.</p>
<p>The <code>enumerate</code> function simplifies the process by directly providing both indices and elements from the <code>grocery_list</code> list.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Simulating a grocery list</span>
grocery_list = [<span class="hljs-string">'Apples'</span>, <span class="hljs-string">'Milk'</span>, <span class="hljs-string">'Bread'</span>, <span class="hljs-string">'Eggs'</span>, <span class="hljs-string">'Cheese'</span>]

<span class="hljs-comment"># Displaying the grocery list with indices</span>
<span class="hljs-keyword">for</span> index, item <span class="hljs-keyword">in</span> enumerate(grocery_list):
    print(<span class="hljs-string">f"<span class="hljs-subst">{index}</span>. <span class="hljs-subst">{item}</span>"</span>)
</code></pre>
<p>It's concise, readable, and more Pythonic, eliminating the need for manual index handling and making the code cleaner. This approach is generally preferred for its simplicity and clarity in obtaining indices and elements from an iterable.</p>
<h2 id="heading-string-join">String Join</h2>
<p>The <code>join</code> method is a clean way to concatenate strings from an iterable into a single string.</p>
<p>Suppose you have a list of words and want to create a sentence by joining these words using traditional concatenation. You'd do it as below:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using traditional concatenation</span>
words = [<span class="hljs-string">'Python'</span>, <span class="hljs-string">'is'</span>, <span class="hljs-string">'awesome'</span>, <span class="hljs-string">'and'</span>, <span class="hljs-string">'powerful'</span>]

sentence = <span class="hljs-string">''</span>
<span class="hljs-keyword">for</span> word <span class="hljs-keyword">in</span> words:
    sentence += word + <span class="hljs-string">' '</span>

print(sentence.strip())  <span class="hljs-comment"># Strip to remove the trailing space</span>
</code></pre>
<p>In the traditional concatenation method, a loop iterates through the list of words, and each word is concatenated with a space. But this approach requires creating a new string for each concatenation operation, which might not be efficient for larger strings due to string immutability.</p>
<p>The <code>join</code> method, on the other hand, is more efficient and concise. It joins the elements of the list using the specified separator (in this case, a space), creating the sentence in a single operation.</p>
<pre><code class="lang-python">.<span class="hljs-comment"># Using join method</span>
words = [<span class="hljs-string">'Python'</span>, <span class="hljs-string">'is'</span>, <span class="hljs-string">'awesome'</span>, <span class="hljs-string">'and'</span>, <span class="hljs-string">'powerful'</span>]

sentence = <span class="hljs-string">' '</span>.join(words)
print(sentence)
</code></pre>
<p>This method is generally the preferred way to join strings in Python due to its efficiency and readability.</p>
<h2 id="heading-unpacking-lists">Unpacking Lists</h2>
<p>Python's unpacking feature allows for efficient assignment of elements from iterables to variables. </p>
<p>Suppose you have a list of numbers, and you want to assign each number to separate variables using traditional indexing.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using traditional unpacking</span>
numbers = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]

a = numbers[<span class="hljs-number">0</span>]
b = numbers[<span class="hljs-number">1</span>]
c = numbers[<span class="hljs-number">2</span>]

print(a, b, c)
</code></pre>
<p>In the traditional unpacking method, individual elements from the list are accessed and assigned to separate variables by explicitly indexing each element. This method is more verbose and requires knowing the number of elements in advance.</p>
<p>Now, let's accomplish the same using the <code>*</code> operator for unpacking the list into variables.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using * operator for unpacking</span>
numbers = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]

a, b, c = numbers

print(a, b, c)
</code></pre>
<p>You can learn more about the <code>*</code> operator and list unpacking in <a target="_blank" href="https://blog.ashutoshkrris.in/mastering-list-destructuring-and-packing-in-python-a-comprehensive-guide#heading-destructuring-assignment">this tutorial</a>.</p>
<h2 id="heading-should-you-always-use-one-liners">Should You Always Use One-Liners?</h2>
<p>While Python one-liners offer conciseness and elegance, there are considerations to keep in mind before applying them universally:</p>
<ol>
<li><strong>Readability</strong>: One-liners might sacrifice readability for crispness. Complex one-liners can be hard to understand, especially for newcomers or when revisiting code after some time. </li>
<li><strong>Maintainability</strong>: Overuse of one-liners, especially complex ones, can make code maintenance challenging. Debugging and modifying concise code might be more difficult.</li>
<li><strong>Performance</strong>: In certain scenarios, one-liners might not be the most performant solution. These concise expressions may consume more resources, such as memory or CPU, and their underlying operations might have higher time complexity, affecting efficiency, especially with large datasets or intensive computations.</li>
<li><strong>Debugging</strong>: Debugging a one-liner can be more challenging due to its compactness. Identifying issues or errors might take longer compared to well-structured, multiple-line code.</li>
<li><strong>Context</strong>: Not all situations warrant one-liners. Sometimes, a straightforward, explicit approach might be more suitable for code clarity, especially when working in teams.</li>
</ol>
<p>Ultimately, the decision to use one-liners should consider the trade-offs between conciseness and readability. Strive for a balance that enhances code clarity without compromising maintainability and understanding, especially when collaborating or working on larger projects.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Mastering Python's concise techniques like list comprehensions, lambda functions, <code>enumerate</code>, <code>join</code>, <code>zip</code>, and unpacking with the <code>*</code> operator can significantly enhance code readability, efficiency, and simplicity. These methods offer elegant solutions to common programming challenges, reducing verbosity and improving code maintainability. </p>
<p>Understanding when and how to use these Pythonic constructs empowers developers to write cleaner, more expressive code and enhancing overall productivity in various programming scenarios.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement Two-Factor Authentication with PyOTP and Google Authenticator in Your Flask App ]]>
                </title>
                <description>
                    <![CDATA[ Two-Factor Authentication, or 2FA, is like having an extra lock on the door to your online accounts. Instead of just using a password, 2FA adds another layer of security. It's a bit like needing both a key and a special code to open a vault. Think of... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-implement-two-factor-authentication-in-your-flask-app/</link>
                <guid isPermaLink="false">66ba0e98102ebf67c0a6d42c</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Two-factor authentication ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 27 Nov 2023 21:41:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/2fa-tutorial.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Two-Factor Authentication, or 2FA, is like having an extra lock on the door to your online accounts. Instead of just using a password, 2FA adds another layer of security. It's a bit like needing both a key and a special code to open a vault.</p>
<p>Think of it as a shield for your accounts. Passwords can sometimes be guessed or stolen, but with 2FA, even if someone gets your password, they'd still need that extra code or device to get in. It's an extra step that makes your accounts much harder for hackers to break into.</p>
<p>So, let's explore how to set up this extra layer of protection using PyOTP and Google Authenticator in your Flask app. </p>
<h3 id="heading-table-of-contents">Table of Contents:</h3>
<ol>
<li><a class="post-section-overview" href="#heading-overview-of-pyotp-and-google-authenticator">Overview of PyOTP and Google Authenticator</a></li>
<li><a class="post-section-overview" href="#heading-two-factor-authentication-workflow-in-our-application">Two-Factor Authentication Workflow in Our Application</a></li>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-get-your-tools-ready">Get Your Tools Ready</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-project">How to Set Up the Project</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-blueprints-for-accounts-and-core">How to Create Blueprints for Accounts and Core</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-user-model">How to Create a User Model</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-flask-login">How to Add Flask-Login</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-templates-and-static-files">How to Add Templates and Static Files</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-homepage">How to Create the Homepage</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-user-registration">How to Implement User Registration</a></li>
<li>[How to Implement User Login](#<h2 id="how-to-implement-user-login"><strong>How to Implement User Login</strong></h2>)</li>
<li><a class="post-section-overview" href="#heading-how-to-log-out-the-users">How to Log Out the Users</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-the-setup-2fa-page">How to Add the Setup 2FA Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-a-2fa-verification-page">How to Add a 2FA Verification Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-run-the-completed-app-for-the-first-time">How to Run the Completed App for the First Time</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-overview-of-pyotp-and-google-authenticator">Overview of PyOTP and Google Authenticator</h2>
<p>PyOTP is a Python library that's incredibly handy for generating Time-based One-Time Passwords (TOTP) and HMAC-based One-Time Passwords (HOTP). Its primary role revolves around creating these unique, time-sensitive codes that add an extra layer of security to user accounts. </p>
<p>By integrating PyOTP into your Flask application, you can easily implement Two-Factor Authentication (2FA) by generating and verifying these OTPs.</p>
<p>If you're new to PyOTP or would like a refresher on its functionalities, I recommend reviewing my previous <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-generate-otps-using-pyotp-in-python">guide on PyOTP</a>. This understanding will be beneficial as we get into the integration of PyOTP within your Flask application for Two-Factor Authentication (2FA).</p>
<p>Google Authenticator, on the other hand, stands out as one of the most widely used OTP generator apps available. It functions as a secure platform for generating time-based OTPs, compatible with various services and applications supporting 2FA. Users can easily set up Google Authenticator on their devices to generate these time-sensitive codes, adding an extra level of security to their accounts.</p>
<h2 id="heading-two-factor-authentication-workflow-in-our-application">Two-Factor Authentication Workflow in Our Application</h2>
<p>Here's a breakdown of the flow of two-factor authentication in our application:</p>
<ol>
<li><strong>Registration with 2FA Setup</strong>: When users sign up on our website, they're prompted to set up an extra layer of security—2FA. This involves scanning a QR code using an authenticator app, such as Google Authenticator, to link their account securely.</li>
<li><strong>Login Initiation</strong>: When users return to log in, they start by entering their usual email/username and password combo to access their account.</li>
<li><strong>Extra Security Check</strong>: Before granting access, our website throws in an additional hurdle: users need to provide an OTP (One-Time Password) displayed on their authenticator app. This ensures they're not just entering the password but also confirming their identity with a unique, time-sensitive code.</li>
<li><strong>Validation and Authorization</strong>: The user inputs the received OTP into our platform. The system then double-checks this OTP against the expected code, validating the information. If the OTP matches, it's like handing over the secret handshake, granting the user access to their account.</li>
</ol>
<p>This seamless back-and-forth between passwords, authenticator apps, and unique codes ensures that only the rightful account owner can access the precious content behind the digital doors of your website.</p>
<p>If you also enjoy visual learning, here's a fancy video showing how the app does its thing.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/qzLcbq5-UNA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Now, let's get to some coding!</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you get started with the tutorial, make sure you have the following requirements satisfied:</p>
<ul>
<li>Working knowledge of Python</li>
<li>Python 3.8+ installed on your system</li>
<li>Basic knowledge of <a target="_blank" href="https://ashutoshkrris.hashnode.dev/getting-started-with-flask">Flask</a> and <a target="_blank" href="https://ashutoshkrris.hashnode.dev/how-to-use-blueprints-to-organize-your-flask-apps">Flask Blueprints</a></li>
<li>Knowledge of <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-set-up-basic-user-authentication-in-a-flask-app">basic authentication in Flask</a> (optional)</li>
</ul>
<h2 id="heading-get-your-tools-ready"><strong>Get Your Tools Ready</strong></h2>
<p>You'll need a few external libraries for this project. Let's learn more about them and install them one by one.</p>
<p>But before we install them, let's create a virtual environment and activate it.</p>
<p>First, start with creating the project directory and navigating to it like this:</p>
<pre><code class="lang-bash">mkdir flask-two-factor-auth
ccd flask-two-factor-auth
</code></pre>
<p>We are going to create a virtual environment using <code>venv</code>. Python now ships with a pre-installed <code>venv</code> library. So, to create a virtual environment, you can use the below command:</p>
<pre><code class="lang-bash">python -m venv env
</code></pre>
<p>The above command will create a virtual environment named env. Now, we need to activate the environment using this command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> env/Scripts/activate
</code></pre>
<p>To verify if the environment has been activated or not, you can see <code>(env)</code> in your terminal. Now, we can install the libraries.</p>
<ul>
<li><a target="_blank" href="https://flask.palletsprojects.com/en/2.2.x/">Flask</a> is a simple, easy-to-use microframework for Python that helps you build scalable and secure web applications.</li>
<li><a target="_blank" href="https://flask-login.readthedocs.io/en/latest/">Flask-Login</a> provides user session management for Flask. It handles the common tasks of logging in, logging out, and remembering your users’ sessions over extended periods of time.</li>
<li><a target="_blank" href="https://flask-bcrypt.readthedocs.io/en/1.0.1/">Flask-Bcrypt</a> is a Flask extension that provides bcrypt hashing utilities for your application.</li>
<li><a target="_blank" href="https://flask-wtf.readthedocs.io/en/1.0.x/">Flask-WTF</a> is a simple integration of Flask and WTForms that helps you create forms in Flask.</li>
<li><a target="_blank" href="https://flask-migrate.readthedocs.io/en/latest/">Flask-Migrate</a> is an extension that handles SQLAlchemy database migrations for Flask applications using Alembic. The database operations are made available through the Flask command-line interface.</li>
<li><a target="_blank" href="https://flask-sqlalchemy.palletsprojects.com/en/2.x/">Flask-SQLAlchemy</a> is an extension for Flask that adds support for SQLAlchemy to your application. It helps you simplify things using SQLAlchemy with Flask by giving you useful defaults and extra helpers that make it easier to perform common tasks.</li>
<li><a target="_blank" href="https://blog.ashutoshkrris.in/how-to-generate-otps-using-pyotp-in-python">PyOTP</a> helps you generate OTPs using Time-based OTP (TOTP) and HMAC-based OTP (HOTP) algorithms effortlessly.</li>
<li><a target="_blank" href="https://pypi.org/project/qrcode/">QRCode</a> helps you generate QR Codes in Python</li>
<li><a target="_blank" href="https://pypi.org/project/python-decouple/">Python Decouple</a> helps you use environment variables in your Python project.</li>
</ul>
<p>To install the above-mentioned libraries all in one go, run the following command:</p>
<pre><code class="lang-bash">pip install Flask Flask-Login Flask-Bcrypt Flask-WTF FLask-Migrate Flask-SQLAlchemy pyotp qrcode python-decouple
</code></pre>
<h2 id="heading-how-to-set-up-the-project"><strong>How to Set Up the Project</strong></h2>
<p>Let’s start by creating a <code>src</code> directory:</p>
<pre><code class="lang-bash">mkdir src
</code></pre>
<p>The first file will be the <code>__init__.py</code> file for the project:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_bcrypt <span class="hljs-keyword">import</span> Bcrypt
<span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> Migrate
<span class="hljs-keyword">from</span> flask_sqlalchemy <span class="hljs-keyword">import</span> SQLAlchemy

app = Flask(__name__)
app.config.from_object(config(<span class="hljs-string">"APP_SETTINGS"</span>))

bcrypt = Bcrypt(app)
db = SQLAlchemy(app)
migrate = Migrate(app, db)

<span class="hljs-comment"># Registering blueprints</span>
<span class="hljs-keyword">from</span> src.accounts.views <span class="hljs-keyword">import</span> accounts_bp
<span class="hljs-keyword">from</span> src.core.views <span class="hljs-keyword">import</span> core_bp

app.register_blueprint(accounts_bp)
app.register_blueprint(core_bp)
</code></pre>
<p>In the above script, we created a Flask app called <code>app</code> . We use the <code>__name__</code> argument to indicate the app's module or package so that Flask knows where to find other files such as templates. We also set the configuration of the app using an environment variable called <code>APP_SETTINGS</code>. We'll export it later.</p>
<p>To use Flask-Bcrypt, Flask-SQLAlchemy, and Flask-Migrate in our application, we just need to create objects of the <code>Bcrypt</code>, <code>SQLAlchemy</code> and <code>Migrate</code> classes from the <code>flask_bcrypt</code>, <code>flask_sqlalchemy</code> and, <code>flask_migrate</code> libraries, respectively.</p>
<p>We've also registered blueprints called <code>accounts_bp</code> and <code>core_bp</code> in the application. We'll define them later in the tutorial.</p>
<p>In the root directory of the project (that is, outside the <code>src</code> directory), create a file called <code>config.py</code>. We'll store the configurations for the project in this file. Within the file, add the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config

DATABASE_URI = config(<span class="hljs-string">"DATABASE_URL"</span>)
<span class="hljs-keyword">if</span> DATABASE_URI.startswith(<span class="hljs-string">"postgres://"</span>):
    DATABASE_URI = DATABASE_URI.replace(<span class="hljs-string">"postgres://"</span>, <span class="hljs-string">"postgresql://"</span>, <span class="hljs-number">1</span>)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Config</span>(<span class="hljs-params">object</span>):</span>
    DEBUG = <span class="hljs-literal">False</span>
    TESTING = <span class="hljs-literal">False</span>
    CSRF_ENABLED = <span class="hljs-literal">True</span>
    SECRET_KEY = config(<span class="hljs-string">"SECRET_KEY"</span>, default=<span class="hljs-string">"guess-me"</span>)
    SQLALCHEMY_DATABASE_URI = DATABASE_URI
    SQLALCHEMY_TRACK_MODIFICATIONS = <span class="hljs-literal">False</span>
    BCRYPT_LOG_ROUNDS = <span class="hljs-number">13</span>
    WTF_CSRF_ENABLED = <span class="hljs-literal">True</span>
    DEBUG_TB_ENABLED = <span class="hljs-literal">False</span>
    DEBUG_TB_INTERCEPT_REDIRECTS = <span class="hljs-literal">False</span>
    APP_NAME = config(<span class="hljs-string">"APP_NAME"</span>)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DevelopmentConfig</span>(<span class="hljs-params">Config</span>):</span>
    DEVELOPMENT = <span class="hljs-literal">True</span>
    DEBUG = <span class="hljs-literal">True</span>
    WTF_CSRF_ENABLED = <span class="hljs-literal">False</span>
    DEBUG_TB_ENABLED = <span class="hljs-literal">True</span>


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestingConfig</span>(<span class="hljs-params">Config</span>):</span>
    TESTING = <span class="hljs-literal">True</span>
    DEBUG = <span class="hljs-literal">True</span>
    SQLALCHEMY_DATABASE_URI = <span class="hljs-string">"sqlite:///testdb.sqlite"</span>
    BCRYPT_LOG_ROUNDS = <span class="hljs-number">1</span>
    WTF_CSRF_ENABLED = <span class="hljs-literal">False</span>


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductionConfig</span>(<span class="hljs-params">Config</span>):</span>
    DEBUG = <span class="hljs-literal">False</span>
    DEBUG_TB_ENABLED = <span class="hljs-literal">False</span>
</code></pre>
<p>In the above script, we have created a <code>Config</code> class and defined various attributes inside that. Also, we have created different child classes (as per different stages of development) that inherit the <code>Config</code> class.</p>
<p>Notice that we're using a few environment variables like <code>SECRET_KEY</code>, <code>DATABASE_URL</code>, and <code>APP_NAME</code>. Create a file named <code>.env</code> in the root directory and add the following content there:</p>
<pre><code class="lang-python">export SECRET_KEY=fdkjshfhjsdfdskfdsfdcbsjdkfdsdf
export DEBUG=<span class="hljs-literal">True</span>
export APP_SETTINGS=config.DevelopmentConfig
export DATABASE_URL=sqlite:///db.sqlite
export FLASK_APP=src
export FLASK_DEBUG=<span class="hljs-number">1</span>
export APP_NAME=<span class="hljs-string">"Flask User Authentication App"</span>
</code></pre>
<p>Apart from the <code>SECRET_KEY</code> , <code>DATABASE_URL</code> and <code>APP_NAME</code>, we've also exported <code>APP_SETTINGS</code>, <code>DEBUG</code>, <code>FLASK_APP</code>, and <code>FLASK_DEBUG</code>.</p>
<p>The <code>APP_SETTINGS</code> refers to one of the classes we created in the <code>config.py</code> file. We set it to the current stage of the project.</p>
<p>The value of <code>FLASK_APP</code> is the name of the package we have created. Since the app is in the development stage, you can set the values of <code>DEBUG</code> and <code>FLASK_DEBUG</code> to <code>True</code> and <code>1</code>, respectively.</p>
<p>Run the following command to export all the environment variables from the <code>.env</code> file:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> .env
</code></pre>
<p>Next, we'll create a CLI application of the app so that we can later add custom commands if required.</p>
<p>Create a <code>manage.py</code> file in the root directory of the application and add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask.cli <span class="hljs-keyword">import</span> FlaskGroup

<span class="hljs-keyword">from</span> src <span class="hljs-keyword">import</span> app

cli = FlaskGroup(app)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    cli()
</code></pre>
<p>Now, your basic application is ready. You can run it using the following command:</p>
<pre><code class="lang-bash">python manage.py run
</code></pre>
<p>Your file structure should look like below as of now:</p>
<pre><code class="lang-bash">flask-two-factor-auth/
├── src/
│   └── __init__.py
├── .env
├── config.py
└── manage.py
</code></pre>
<h2 id="heading-how-to-create-blueprints-for-accounts-and-core"><strong>How to Create Blueprints for Accounts and Core</strong></h2>
<p>As mentioned earlier, you'll use the concepts of blueprints in the project. Let's create two blueprints – <code>accounts_bp</code> and <code>core_bp</code> – in this section.</p>
<p>First create a directory called <code>accounts</code> like this:</p>
<pre><code class="lang-bash">mkdir accounts
<span class="hljs-built_in">cd</span> accounts
</code></pre>
<p>Next, add an empty <code>__init__.py</code> file to covert it into a Python package. Now, create a <code>views.py</code> file inside the package where you'll store all your routes related to user authentication.</p>
<pre><code class="lang-bash">touch __init__.py views.py
</code></pre>
<p>Add the following code inside the <code>views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint

accounts_bp = Blueprint(<span class="hljs-string">"accounts"</span>, __name__)
</code></pre>
<p>In the above script, you have created a blueprint called <code>accounts_bp</code> for the <code>accounts</code> package.</p>
<p>Similarly, you can create a <code>core</code> package in the root directory, and add a <code>views.py</code> file.</p>
<pre><code class="lang-bash">mkdir core
<span class="hljs-built_in">cd</span> core
touch __init__.py views.py
</code></pre>
<p>Now, add the following code inside the <code>views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint

core_bp = Blueprint(<span class="hljs-string">"core"</span>, __name__)
</code></pre>
<p>Note: If you're new to Flask Blueprints, make sure you go through <a target="_blank" href="https://ashutoshkrris.hashnode.dev/how-to-use-blueprints-to-organize-your-flask-apps">this tutorial</a> to learn more about how it works.</p>
<p>Now, your file structure should look like what you see below:</p>
<pre><code class="lang-bash">flask-two-factor-auth/
├── src/
│   ├── accounts/
│   │   ├── __init__.py
│   │   └── views.py
│   ├── core/
│   │   ├── __init__.py
│   │   └── views.py
│   └── __init__.py
├── .env
├── config.py
└── manage.py
</code></pre>
<h2 id="heading-how-to-create-a-user-model"><strong>How to Create a User Model</strong></h2>
<p>Let's create a <code>models.py</code> file inside the <code>accounts</code> package.</p>
<pre><code class="lang-bash">touch src/accounts/models.py
</code></pre>
<p>Inside the <code>models.py</code> file, add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime

<span class="hljs-keyword">import</span> pyotp
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> UserMixin

<span class="hljs-keyword">from</span> src <span class="hljs-keyword">import</span> bcrypt, db
<span class="hljs-keyword">from</span> config <span class="hljs-keyword">import</span> Config


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span>(<span class="hljs-params">db.Model</span>):</span>

    __tablename__ = <span class="hljs-string">"users"</span>

    id = db.Column(db.Integer, primary_key=<span class="hljs-literal">True</span>)
    username = db.Column(db.String, unique=<span class="hljs-literal">True</span>, nullable=<span class="hljs-literal">False</span>)
    password = db.Column(db.String, nullable=<span class="hljs-literal">False</span>)
    created_at = db.Column(db.DateTime, nullable=<span class="hljs-literal">False</span>)
    is_two_factor_authentication_enabled = db.Column(
        db.Boolean, nullable=<span class="hljs-literal">False</span>, default=<span class="hljs-literal">False</span>)
    secret_token = db.Column(db.String, unique=<span class="hljs-literal">True</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, username, password</span>):</span>
        self.username = username
        self.password = bcrypt.generate_password_hash(password)
        self.created_at = datetime.now()
        self.secret_token = pyotp.random_base32()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_authentication_setup_uri</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> pyotp.totp.TOTP(self.secret_token).provisioning_uri(
            name=self.username, issuer_name=Config.APP_NAME)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_otp_valid</span>(<span class="hljs-params">self, user_otp</span>):</span>
        totp = pyotp.parse_uri(self.get_authentication_setup_uri())
        <span class="hljs-keyword">return</span> totp.verify(user_otp)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__repr__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"&lt;user <span class="hljs-subst">{self.username}</span>&gt;"</span>
</code></pre>
<p>In the above code, you created a <code>User</code> model by inheriting the <code>db.Model</code> class. The <code>User</code> model consists of the following fields:</p>
<ul>
<li><code>id</code>: stores the primary key for the <code>users</code> table</li>
<li><code>username</code>: stores the username of the user</li>
<li><code>password</code>: stores the hashed password of the user</li>
<li><code>created_at</code>: stores the timestamp when the user was created</li>
<li><code>is_two_factor_authentication_enabled</code>: boolean flag that stores whether the user has activated two-factor authentication. Default value is <code>False</code>.</li>
<li><code>secret_token</code>: stores a unique token generated for each user, essential for implementing two-factor authentication.</li>
</ul>
<p>The constructor initializes the <code>User</code> object upon instantiation by accepting <code>username</code> and <code>password</code> parameters. It hashes the provided password using <code>bcrypt.generate_password_hash(password)</code>, records the current timestamp as the <code>created_at</code> value, and generates a unique <code>secret_token</code> using <code>pyotp.random_base32()</code> for 2FA setup.</p>
<p>The <code>get_authentication_setup_uri()</code> method generates a setup URI used by authenticator apps like Google Authenticator. It constructs a URI containing the user's username and the application's name (<code>Config.APP_NAME</code>) necessary for setting up two-factor authentication. The basic format of the URI is:</p>
<pre><code class="lang-bash">otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&amp;issuer=Example
</code></pre>
<p>where, alice@google.com is the username of the user and Example is the application's name.</p>
<p>Next up, the <code>is_otp_valid()</code> method verifies the one-time password (OTP) entered by the user during login. It parses the setup URI generated earlier, checks the validity of the provided OTP (<code>user_otp</code>), and returns <code>True</code> if the OTP matches, ensuring secure authentication.</p>
<p>Finally, the <code>__repr__</code> method provides a string representation of the <code>User</code> object, displaying the associated username when an instance of the class is printed or represented as a string.</p>
<h2 id="heading-how-to-add-flask-login"><strong>How to Add Flask-Login</strong></h2>
<p>The most important part of Flask-Login is the <code>LoginManager</code> class that lets your application and Flask-Login work together.</p>
<p>In the <code>src/__init__.py</code> file, add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> LoginManager <span class="hljs-comment"># Add this line</span>
<span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> Migrate
<span class="hljs-keyword">from</span> flask_sqlalchemy <span class="hljs-keyword">import</span> SQLAlchemy

app = Flask(__name__)
app.config.from_object(config(<span class="hljs-string">"APP_SETTINGS"</span>))

login_manager = LoginManager() <span class="hljs-comment"># Add this line</span>
login_manager.init_app(app) <span class="hljs-comment"># Add this line</span>
db = SQLAlchemy(app)
migrate = Migrate(app, db)

<span class="hljs-comment"># Registering blueprints</span>
<span class="hljs-keyword">from</span> src.accounts.views <span class="hljs-keyword">import</span> accounts_bp
<span class="hljs-keyword">from</span> src.core.views <span class="hljs-keyword">import</span> core_bp

app.register_blueprint(accounts_bp)
app.register_blueprint(core_bp)
</code></pre>
<p>In the above script, we created and initialized the login manager in our app.</p>
<p>Next, we need to provide a <code>user_loader</code> callback. This callback is used to reload the user object from the user ID stored in the session. It should take the ID of a user, and return the corresponding user object.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> src.accounts.models <span class="hljs-keyword">import</span> User

<span class="hljs-meta">@login_manager.user_loader</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">load_user</span>(<span class="hljs-params">user_id</span>):</span>
    <span class="hljs-keyword">return</span> User.query.filter(User.id == int(user_id)).first()
</code></pre>
<p>The <code>User</code> model should implement the following properties and methods:</p>
<ul>
<li><code>is_authenticated</code>: This property returns True if the user is authenticated.</li>
<li><code>is_active</code>: This property returns True if this is an active user (the account is activated)</li>
<li><code>is_anonymous</code>: This property returns True if this is an anonymous user (actual users return False).</li>
<li><code>get_id()</code>: This method returns a string that uniquely identifies this user, and can be used to load the user from the <code>user_loader</code> callback.</li>
</ul>
<p>Now, we don't need to implement these explicitly. Instead, the Flask-Login provides a <code>UserMixin</code> class that contains the default implementations for all of these properties and methods. We just need to inherit it in the following way:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime

<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> UserMixin <span class="hljs-comment"># Add this line</span>

<span class="hljs-keyword">from</span> src <span class="hljs-keyword">import</span> bcrypt, db


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span>(<span class="hljs-params">UserMixin, db.Model</span>):</span> <span class="hljs-comment"># Change this line</span>
    ....
</code></pre>
<p>We can also customize the default login process in the <code>src/__init__.py</code> file.</p>
<p>The name of the login view can be set as <code>LoginManager.login_view</code>. The value refers to the function name that will handle the login process.</p>
<pre><code class="lang-python">login_manager.login_view = <span class="hljs-string">"accounts.login"</span>
</code></pre>
<p>To customize the message category, set <code>LoginManager.login_message_category</code>:</p>
<pre><code class="lang-python">login_manager.login_message_category = <span class="hljs-string">"danger"</span>
</code></pre>
<h2 id="heading-how-to-add-templates-and-static-files"><strong>How to Add Templates and Static Files</strong></h2>
<p>Let's create a CSS file called <code>styles.css</code> inside the <code>src/static</code> folder:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.error</span> {
  <span class="hljs-attribute">color</span>: red;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">text-decoration</span>: none;
}
</code></pre>
<p>Let's also create the basic templates inside the <code>src/templates</code> folder. Create a <code>_base.html</code> file and add the following code:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Two Factor Authentication<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- meta --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">""</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"author"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">""</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width,initial-scale=1"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- styles --&gt;</span>
    <span class="hljs-comment">&lt;!-- CSS only --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{url_for('static', filename="</span><span class="hljs-attr">styles.css</span>")}}"&gt;</span>
    {% block css %}{% endblock %}
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

    {% include "navigation.html" %}

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>

      <span class="hljs-comment">&lt;!-- messages --&gt;</span>
      {% with messages = get_flashed_messages(with_categories=true) %}
      {% if messages %}
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
          {% for category, message in messages %}
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-{{ category }} alert-dismissible fade show"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
           {{message}}
           <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn-close"</span> <span class="hljs-attr">data-bs-dismiss</span>=<span class="hljs-string">"alert"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Close"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          {% endfor %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      {% endif %}
      {% endwith %}

      <span class="hljs-comment">&lt;!-- child template --&gt;</span>
      {% block content %}{% endblock %}

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- scripts --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://code.jquery.com/jquery-3.7.1.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- JavaScript Bundle with Popper --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-BBtl+eGJRgqQAUMxJ7pMwbEyER4l1g+O15P+16Ep7Q9Q+zqX6gSbd85u4mG4QzX+"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    {% block js %}{% endblock %}
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The <code>_base.html</code> is the parent HTML file that will be inherited by the other templates. We have added Bootstrap 5 support in the above file. We are also making use of Flask Flashes to show Bootstrap alerts in the app.</p>
<p>Let's also create a <code>navigation.html</code> file that contains the navbar of the app:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Navigation --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar bg-dark navbar-expand-lg bg-body-tertiary p-3"</span> <span class="hljs-attr">data-bs-theme</span>=<span class="hljs-string">"dark"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container-fluid"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('core.home') }}"</span>&gt;</span>Two-Factor Authentication App<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-toggler"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">data-bs-toggle</span>=<span class="hljs-string">"collapse"</span> <span class="hljs-attr">data-bs-target</span>=<span class="hljs-string">"#navbarSupportedContent"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"navbarSupportedContent"</span> <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">"false"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Toggle navigation"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-toggler-icon"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"collapse navbar-collapse"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"navbarSupportedContent"</span>&gt;</span>
      {% if current_user.is_authenticated %}
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.logout') }}"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-danger me-2"</span>&gt;</span>Logout<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      {% endif %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
</code></pre>
<p>Note that we have not yet created the views used above.</p>
<h2 id="heading-how-to-create-the-homepage"><strong>How to Create the Homepage</strong></h2>
<p>In this section, we'll first create a view function for the homepage inside the <code>core/views.py</code> file. Add the following code there:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint, render_template
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> login_required

core_bp = Blueprint(<span class="hljs-string">"core"</span>, __name__)


<span class="hljs-meta">@core_bp.route("/")</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">home</span>():</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"core/index.html"</span>)
</code></pre>
<p>Notice that we have used the blueprint to add the route. We also added a <code>@login_required</code> middleware to prevent access for unauthenticated users.</p>
<p>Next, let's create an <code>index.html</code> file inside the <code>templates/core</code> folder, and add the following code:</p>
<pre><code class="lang-html">{% extends "_base.html" %}
{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center"</span>&gt;</span>Welcome {{current_user.username}}!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

{% endblock %}
</code></pre>
<p>The HTML page will just have a welcome message for authenticated users.</p>
<p>Your file structure as of now should look like below:</p>
<pre><code class="lang-bash">flask-two-factor-auth/
├── src/
│   ├── accounts/
│   │   ├── __init__.py
│   │   └── views.py
│   ├── core/
│   │   ├── __init__.py
│   │   └── views.py
│   ├── static/
│   │   └── styles.css
│   ├── templates/
│   │   ├── core/
│   │   │   └── index.html
│   │   ├── _base.html
│   │   └── navigation.html
│   └── __init__.py
├── .env
├── config.py
└── manage.py
</code></pre>
<h2 id="heading-how-to-implement-user-registration"><strong>How to Implement User Registration</strong></h2>
<p>First of all, we'll create a registration form using Flask-WTF. Create a <code>forms.py</code> file inside the <code>accounts</code> package and add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask_wtf <span class="hljs-keyword">import</span> FlaskForm
<span class="hljs-keyword">from</span> wtforms <span class="hljs-keyword">import</span> EmailField, PasswordField
<span class="hljs-keyword">from</span> wtforms.validators <span class="hljs-keyword">import</span> DataRequired, Email, EqualTo, Length

<span class="hljs-keyword">from</span> src.accounts.models <span class="hljs-keyword">import</span> User


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegisterForm</span>(<span class="hljs-params">FlaskForm</span>):</span>
    username = StringField(
        <span class="hljs-string">"Username"</span>, validators=[DataRequired(), Length(min=<span class="hljs-number">6</span>, max=<span class="hljs-number">40</span>)]
    )
    password = PasswordField(
        <span class="hljs-string">"Password"</span>, validators=[DataRequired(), Length(min=<span class="hljs-number">6</span>, max=<span class="hljs-number">25</span>)]
    )
    confirm = PasswordField(
        <span class="hljs-string">"Repeat password"</span>,
        validators=[
            DataRequired(),
            EqualTo(<span class="hljs-string">"password"</span>, message=<span class="hljs-string">"Passwords must match."</span>),
        ],
    )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">validate</span>(<span class="hljs-params">self, extra_validators</span>):</span>
        initial_validation = super(RegisterForm, self).validate(extra_validators)
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> initial_validation:
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
        user = User.query.filter_by(username=self.username.data).first()
        <span class="hljs-keyword">if</span> user:
            self.username.errors.append(<span class="hljs-string">"Username already registered"</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
        <span class="hljs-keyword">if</span> self.password.data != self.confirm.data:
            self.password.errors.append(<span class="hljs-string">"Passwords must match"</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
        <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
</code></pre>
<p>The <code>RegisterForm</code> extends the <code>FlaskForm</code> class and contains three fields – <code>username</code>, <code>password</code>, and <code>confirm</code>. We have added different validators such as <code>DataRequired</code>, <code>Length</code>, <code>Email</code>, and <code>EqualTo</code> to the respective fields.</p>
<p>We also defined a <code>validate()</code> method which is automatically called when the form is submitted.</p>
<p>Inside the method, we first perform the initial validation provided by FlaskForm. If that is successful, we perform our custom validation such as checking whether user is already registered, and matching the password with the confirmed password. If there are any errors, we append the error message in the respective fields.</p>
<p>Now, let's use this form inside the HTML file. Create an <code>accounts</code> directory inside the <code>templates</code> folder and add a new file called <code>register.html</code> inside it. Add the following code:</p>
<pre><code class="lang-html">{% extends "_base.html" %}

{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-signin w-100 m-auto"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">""</span>&gt;</span>
        {{ form.csrf_token }}
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h3 mb-3 fw-normal text-center"</span>&gt;</span>Please register<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.username(placeholder="username", class="form-control mb-2") }}
          {{ form.username.label }}
            {% if form.username.errors %}
              {% for error in form.username.errors %}
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                  {{ error }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.password(placeholder="password", class="form-control mb-2") }}
          {{ form.password.label }}
            {% if form.password.errors %}
              {% for error in form.password.errors %}
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                  {{ error }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.confirm(placeholder="Confirm Password", class="form-control mb-2") }}
          {{ form.confirm.label }}
            {% if form.confirm.errors %}
              {% for error in form.confirm.errors %}
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                  {{ error }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-100 btn btn-lg btn-primary"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Sign up<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center mt-3"</span>&gt;</span>Already registered? <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.login') }}"</span>&gt;</span>Login now<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

{% endblock %}
</code></pre>
<p>In the above Jinja template, we make use of the form that we created, and add relevant error handling logic checks for validation errors in each field. Users can submit the form by clicking the "Sign up" button, and a link below the form allows already registered users to navigate to the login page for authentication.</p>
<p>Next, let's use this form in the <code>views.py</code> to create a function to handle the registration process.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> .forms <span class="hljs-keyword">import</span> RegisterForm
<span class="hljs-keyword">from</span> src.accounts.models <span class="hljs-keyword">import</span> User
<span class="hljs-keyword">from</span> src <span class="hljs-keyword">import</span> db, bcrypt
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> current_user
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint, flash, redirect, render_template, request, url_for

accounts_bp = Blueprint(<span class="hljs-string">"accounts"</span>, __name__)

HOME_URL = <span class="hljs-string">"core.home"</span>
SETUP_2FA_URL = <span class="hljs-string">"accounts.setup_two_factor_auth"</span>
VERIFY_2FA_URL = <span class="hljs-string">"accounts.verify_two_factor_auth"</span>

<span class="hljs-meta">@accounts_bp.route("/register", methods=["GET", "POST"])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">register</span>():</span>
    <span class="hljs-keyword">if</span> current_user.is_authenticated:
        <span class="hljs-keyword">if</span> current_user.is_two_factor_authentication_enabled:
            flash(<span class="hljs-string">"You are already registered."</span>, <span class="hljs-string">"info"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(HOME_URL))
        <span class="hljs-keyword">else</span>:
            flash(<span class="hljs-string">"You have not enabled 2-Factor Authentication. Please enable first to login."</span>, <span class="hljs-string">"info"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(SETUP_2FA_URL))
    form = RegisterForm(request.form)
    <span class="hljs-keyword">if</span> form.validate_on_submit():
        <span class="hljs-keyword">try</span>:
            user = User(username=form.username.data, password=form.password.data)
            db.session.add(user)
            db.session.commit()

            login_user(user)
            flash(<span class="hljs-string">"You are registered. You have to enable 2-Factor Authentication first to login."</span>, <span class="hljs-string">"success"</span>)

            <span class="hljs-keyword">return</span> redirect(url_for(SETUP_2FA_URL))
        <span class="hljs-keyword">except</span> Exception:
            db.session.rollback()
            flash(<span class="hljs-string">"Registration failed. Please try again."</span>, <span class="hljs-string">"danger"</span>)

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/register.html"</span>, form=form)
</code></pre>
<p>The route begins by checking if the current user is already authenticated. If so, it verifies whether 2FA is enabled for the user. If 2FA is already enabled, a message informs the user that they're already registered, redirecting them to the home URL. However, if the user is authenticated but 2FA is not enabled, a flash message prompts the user to enable 2FA first before logging in, redirecting them to the 2FA setup URL.</p>
<p>If the user is not authenticated or has not yet registered 2FA, the code initializes a registration form and proceeds to validate the form data on submission. Upon successful form validation, we create a new <code>User</code> object with the provided username and password and save it to the database.</p>
<p>Upon successful user registration, the newly registered user is logged in. A success message flashes, notifying the user of successful registration and prompting them to enable 2FA before logging in. Subsequently, the user is redirected to the 2FA setup URL to enable 2FA.</p>
<h2 id="heading-how-to-implement-user-login"><strong>How to Implement User Login</strong></h2>
<p>First, let's create a login form in the <code>accounts/forms.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginForm</span>(<span class="hljs-params">FlaskForm</span>):</span>
    username = StringField(<span class="hljs-string">"Username"</span>, validators=[DataRequired()])
    password = PasswordField(<span class="hljs-string">"Password"</span>, validators=[DataRequired()])
</code></pre>
<p>The form is similar to the registration form but it has only two fields – <code>username</code> and <code>password</code>.</p>
<p>Now, let's use this form inside new HTML file called <code>login.html</code> created inside the <code>templates/accounts</code> directory. Add the following code:</p>
<pre><code class="lang-html">{% extends "_base.html" %}

{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-signin w-100 m-auto"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">""</span>&gt;</span>
        {{ form.csrf_token }}
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h3 mb-3 fw-normal text-center"</span>&gt;</span>Please sign in<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.username(placeholder="username", class="form-control mb-2") }}
          {{ form.username.label }}
            {% if form.username.errors %}
              {% for error in form.username.errors %}
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                {{ error }}
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.password(placeholder="password", class="form-control mb-2") }}
          {{ form.password.label }}
            {% if form.password.errors %}
              {% for error in form.password.errors %}
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                  {{ error }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-100 btn btn-lg btn-primary"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Sign in<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center mt-3"</span>&gt;</span>New User? <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.register') }}"</span>&gt;</span>Register now<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

{% endblock %}
</code></pre>
<p>The above HTML file is also similar to the <code>register.html</code> file but with just two fields for the username and password.</p>
<p>Next, let's create a view function to handle the login process inside the <code>accounts/views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> .forms <span class="hljs-keyword">import</span> LoginForm, RegisterForm

<span class="hljs-meta">@accounts_bp.route("/login", methods=["GET", "POST"])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">login</span>():</span>
    <span class="hljs-keyword">if</span> current_user.is_authenticated:
        <span class="hljs-keyword">if</span> current_user.is_two_factor_authentication_enabled:
            flash(<span class="hljs-string">"You are already logged in."</span>, <span class="hljs-string">"info"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(HOME_URL))
        <span class="hljs-keyword">else</span>:
            flash(<span class="hljs-string">"You have not enabled 2-Factor Authentication. Please enable first to login."</span>, <span class="hljs-string">"info"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(SETUP_2FA_URL))

    form = LoginForm(request.form)
    <span class="hljs-keyword">if</span> form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        <span class="hljs-keyword">if</span> user <span class="hljs-keyword">and</span> bcrypt.check_password_hash(user.password, request.form[<span class="hljs-string">"password"</span>]):
            login_user(user)
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> current_user.is_two_factor_authentication_enabled:
                flash(
                    <span class="hljs-string">"You have not enabled 2-Factor Authentication. Please enable first to login."</span>, <span class="hljs-string">"info"</span>)
                <span class="hljs-keyword">return</span> redirect(url_for(SETUP_2FA_URL))
            <span class="hljs-keyword">return</span> redirect(url_for(VERIFY_2FA_URL))
        <span class="hljs-keyword">elif</span> <span class="hljs-keyword">not</span> user:
            flash(<span class="hljs-string">"You are not registered. Please register."</span>, <span class="hljs-string">"danger"</span>)
        <span class="hljs-keyword">else</span>:
            flash(<span class="hljs-string">"Invalid username and/or password."</span>, <span class="hljs-string">"danger"</span>)
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/login.html"</span>, form=form)
</code></pre>
<p>The route starts by checking if the current user is already authenticated. If the user is authenticated and 2FA is enabled, a message informs the user they're already logged in, redirecting them to the home URL. If the user is authenticated but 2FA isn't enabled, a flash message prompts the user to enable 2FA before logging in, redirecting them to the 2FA setup URL.</p>
<p>If the user isn't authenticated, the code initializes a login form and validates the form data upon submission. Upon successful validation, it queries the database to find a user matching the provided username. If the user exists and the password matches the hashed password stored in the database, the user is logged in.</p>
<p>Additionally, if 2FA isn't enabled for the current user after successful login, a flash message prompts the user to enable 2FA before proceeding, redirecting them to the 2FA setup URL. If the login is successful and 2FA is enabled, the user is redirected to the 2FA verification URL.</p>
<p>If the user isn't registered, a flash message informs them to register. If there's a mismatch in the provided username or password, another flash message notifies the user of invalid credentials.</p>
<h2 id="heading-how-to-log-out-the-users">How to Log Out the Users</h2>
<p>Logging out the user is a very simple process. You just need to create a view function for it inside the <code>accounts/views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> login_required, login_user, logout_user


<span class="hljs-meta">@accounts_bp.route("/logout")</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">logout</span>():</span>
    logout_user()
    flash(<span class="hljs-string">"You were logged out."</span>, <span class="hljs-string">"success"</span>)
    <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"accounts.login"</span>))
</code></pre>
<p>The <code>Flask-Login</code> library contains a <code>logout_user</code> method that removes the user from the session. We used the <code>@login_required</code> decorator so that only authenticated users can logout.</p>
<h2 id="heading-how-to-add-the-setup-2fa-page">How to Add the Setup 2FA Page</h2>
<p>Up until now, we have been redirecting the users to the setup 2FA page whenever the 2FA is not enabled in their accounts, but we haven't implemented it yet. Let's do that in this section.</p>
<p>Let's start with the route for the page:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> src.utils <span class="hljs-keyword">import</span> get_b64encoded_qr_image

<span class="hljs-meta">@accounts_bp.route("/setup-2fa")</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setup_two_factor_auth</span>():</span>
    secret = current_user.secret_token
    uri = current_user.get_authentication_setup_uri()
    base64_qr_image = get_b64encoded_qr_image(uri)
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/setup-2fa.html"</span>, secret=secret, qr_image=base64_qr_image)
</code></pre>
<p>The route, created inside <code>accounts/views.py</code>, ensures that only authenticated users can access it using the <code>@login_required</code> decorator. </p>
<p>Upon accessing this route, the function retrieves the current user's <code>secret_token</code> for 2FA setup and generates a URI through <code>current_user.get_authentication_setup_uri()</code> to configure an authenticator app like Google Authenticator. </p>
<p>It also uses <code>get_b64encoded_qr_image(uri)</code> to obtain a Base64-encoded QR code image representing this setup URI. We will define it below. </p>
<p>Finally, it renders the <code>setup-2fa.html</code> template, passing the user's <code>secret_token</code> and the Base64-encoded QR image to the template for users to scan it.</p>
<p>Next, create a <code>utils.py</code> file in the <code>src</code> directory and add the following code to <a target="_blank" href="https://blog.ashutoshkrris.in/5-quick-python-projects#heading-qr-codes-in-python">generate the QR</a>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> io <span class="hljs-keyword">import</span> BytesIO
<span class="hljs-keyword">import</span> qrcode
<span class="hljs-keyword">from</span> base64 <span class="hljs-keyword">import</span> b64encode


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_b64encoded_qr_image</span>(<span class="hljs-params">data</span>):</span>
    print(data)
    qr = qrcode.QRCode(version=<span class="hljs-number">1</span>, box_size=<span class="hljs-number">10</span>, border=<span class="hljs-number">5</span>)
    qr.add_data(data)
    qr.make(fit=<span class="hljs-literal">True</span>)
    img = qr.make_image(fill_color=<span class="hljs-string">'black'</span>, back_color=<span class="hljs-string">'white'</span>)
    buffered = BytesIO()
    img.save(buffered)
    <span class="hljs-keyword">return</span> b64encode(buffered.getvalue()).decode(<span class="hljs-string">"utf-8"</span>)
</code></pre>
<p>Remember the <code>qrcode</code> library we installed in the beginning of the tutorial? This is where we're going to use it. </p>
<p>Upon receiving <code>data</code> as input, representing the content to be embedded within the QR code, the function initializes a QRCode object using the <code>qrcode</code> library. It adds the provided data to this QR code instance and generates the QR code. The code then converts this QR code into an image representation. </p>
<p>Using a BytesIO object, it stores this image in memory. The function proceeds to encode the content of this in-memory buffer, representing the QR code image, into Base64 format. Finally, it returns this Base64-encoded string, encapsulating the QR code image, ready for transmission or display in various applications.</p>
<p>Next, let's create the <code>setup-2fa.html</code> page inside the <code>templates/accounts</code> folder, and add the following content:</p>
<pre><code class="lang-html">{% extends "_base.html" %}

{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-signin w-100 m-auto"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"form"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h5</span>&gt;</span>Instructions!<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Download <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&amp;hl=en&amp;gl=US"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>Google Authenticator<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span> on your mobile.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Set up a new authenticator.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Once you have scanned the QR, please click <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.verify_two_factor_auth') }}"</span>&gt;</span>here.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"data:image/png;base64, {{ qr_image }}"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Secret Token"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"width:200px;height:200px"</span>/&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"secret"</span>&gt;</span>Secret Token<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"secret"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"{{ secret }}"</span> <span class="hljs-attr">readonly</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center mt-2"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"copySecret()"</span>&gt;</span>
            Copy Secret
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-4 text-center"</span>&gt;</span>
          Once you have scanned the QR, please click <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.verify_two_factor_auth') }}"</span>&gt;</span>here<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>.
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

{% endblock %}

{% block js %}
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">copySecret</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> copyText = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"secret"</span>);
    copyText.select();
    copyText.setSelectionRange(<span class="hljs-number">0</span>, <span class="hljs-number">99999</span>); <span class="hljs-comment">/*For mobile devices*/</span>
    <span class="hljs-built_in">document</span>.execCommand(<span class="hljs-string">"copy"</span>);
    alert(<span class="hljs-string">"Successfully copied TOTP secret token!"</span>);
  }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
{% endblock %}
</code></pre>
<p>We add some instructions in the page for the users to follow. These instructions provide clear steps for users to enable 2FA: directing them to download the Google Authenticator app via a link, guiding the setup process within the app, and prompting users to proceed by clicking a link after scanning the displayed QR code.</p>
<p>Displaying the QR code is central to the setup process. The template embeds the QR code image using an <code>&lt;img&gt;</code> tag with its source set to a Base64-encoded string (<code>{{ qr_image }}</code>). This image represents the secret key essential for 2FA setup. </p>
<p>We also show the secret key in read-only mode, allowing users to view the key without being able to modify it. We have added a copy button to make it easier for the users to copy the key.</p>
<p>Moreover, we have added a link to the 2FA verification page guiding users to proceed with the setup process after scanning the QR code. We will implement this functionality in the next section.</p>
<p>Here's how your page looks right now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Screenshot-2023-11-26-010925.png" alt="Image" width="600" height="400" loading="lazy">
<em>2FA Setup Page</em></p>
<h2 id="heading-how-to-add-a-2fa-verification-page">How to Add a 2FA Verification Page</h2>
<p>In this section, let's implement the 2FA verification. To start with, we will require an OTP form where users can enter their OTP. Add the following content in the <code>accounts/forms.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TwoFactorForm</span>(<span class="hljs-params">FlaskForm</span>):</span>
    otp = StringField(<span class="hljs-string">'Enter OTP'</span>, validators=[
                      InputRequired(), Length(min=<span class="hljs-number">6</span>, max=<span class="hljs-number">6</span>)])
</code></pre>
<p>The <code>TwoFactorForm</code> contains just one field (<code>otp</code>) to get the OTP from the users.</p>
<p>Now, let's use this form in the <code>verify-2fa.html</code> file inside the <code>templates/accounts</code> folder:</p>
<pre><code class="lang-html">{% extends "_base.html" %}

{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-signin w-100 m-auto"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">""</span>&gt;</span>
        {{ form.csrf_token }}
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h3 mb-3 fw-normal text-center"</span>&gt;</span>Enter OTP<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.otp(placeholder="OTP", class="form-control mb-2") }}
          {{ form.otp.label }}
            {% if form.otp.errors %}
              {% for error in form.otp.errors %}
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                {{ error }}
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-100 btn btn-lg btn-primary"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Verify<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

{% endblock %}
</code></pre>
<p>The Jinja template essentially contains a form with one field for OTP and a verify button. </p>
<p>Let's create the route which handles the submission of this form inside the <code>accounts/views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-meta">@accounts_bp.route("/verify-2fa", methods=["GET", "POST"])</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">verify_two_factor_auth</span>():</span>
    form = TwoFactorForm(request.form)
    <span class="hljs-keyword">if</span> form.validate_on_submit():
        <span class="hljs-keyword">if</span> current_user.is_otp_valid(form.otp.data):
            <span class="hljs-keyword">if</span> current_user.is_two_factor_authentication_enabled:
                flash(<span class="hljs-string">"2FA verification successful. You are logged in!"</span>, <span class="hljs-string">"success"</span>)
                <span class="hljs-keyword">return</span> redirect(url_for(HOME_URL))
            <span class="hljs-keyword">else</span>:
                <span class="hljs-keyword">try</span>:
                    current_user.is_two_factor_authentication_enabled = <span class="hljs-literal">True</span>
                    db.session.commit()
                    flash(<span class="hljs-string">"2FA setup successful. You are logged in!"</span>, <span class="hljs-string">"success"</span>)
                    <span class="hljs-keyword">return</span> redirect(url_for(HOME_URL))
                <span class="hljs-keyword">except</span> Exception:
                    db.session.rollback()
                    flash(<span class="hljs-string">"2FA setup failed. Please try again."</span>, <span class="hljs-string">"danger"</span>)
                    <span class="hljs-keyword">return</span> redirect(url_for(VERIFY_2FA_URL))
        <span class="hljs-keyword">else</span>:
            flash(<span class="hljs-string">"Invalid OTP. Please try again."</span>, <span class="hljs-string">"danger"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(VERIFY_2FA_URL))
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> current_user.is_two_factor_authentication_enabled:
            flash(
                <span class="hljs-string">"You have not enabled 2-Factor Authentication. Please enable it first."</span>, <span class="hljs-string">"info"</span>)
        <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/verify-2fa.html"</span>, form=form)
</code></pre>
<p>The route starts by initializing a form (<code>TwoFactorForm</code>) meant for 2FA verification using the data obtained from the request. Upon form submission, the code proceeds with several conditional checks to validate the OTP entered by the user.</p>
<p>Once the form has been successfully submitted and validated, the code verifies the authenticity of the OTP using <code>current_user.is_otp_valid(form.otp.data)</code>, which checks if the entered OTP is valid for the current user. If the OTP is valid, the code executes the following logic:</p>
<ul>
<li>If the provided OTP is valid and 2FA is already enabled for the user, a success message is flashed indicating successful 2FA verification, and the user is redirected to the home URL.</li>
<li>If the OTP is valid but 2FA isn't enabled for the user, it attempts to enable 2FA for that user. Upon successful activation, a success message flashes, and the user is redirected to the home URL.</li>
</ul>
<p>Furthermore, if the OTP entered by the user is invalid, the code flashes an error message indicating an invalid OTP and redirects the user back to the 2FA verification URL to retry the verification process.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Screenshot-2023-11-26-011107.png" alt="Image" width="600" height="400" loading="lazy">
<em>2FA Verification Page</em></p>
<p>With this, we have completed the implementation of all the features! 🎉</p>
<h2 id="heading-how-to-run-the-completed-app-for-the-first-time"><strong>How to Run the Completed App for the First Time</strong></h2>
<p>Now that our application is ready, you can first migrate the database, and then run the app.</p>
<p>To initialize the database (create a migration repository), use the command:</p>
<pre><code class="lang-bash">flask db init
</code></pre>
<p>To migrate the database changes, use the command:</p>
<pre><code class="lang-bash">flask db migrate
</code></pre>
<p>To apply the migrations, use the command:</p>
<pre><code class="lang-bash">flask db upgrade
</code></pre>
<p>Since this is the first time we're running our app, you'll need to run all the above commands. Later, whenever you make changes to the database, you'll just need to run the last two commands.</p>
<p>After that, you can run your application using the command:</p>
<pre><code>python manage.py run
</code></pre><p>Since we have completed the development, here's how your file structure should look like:</p>
<pre><code class="lang-bash">flask-two-factor-auth/
├── migrations/
├── src/
│   ├── accounts/
│   │   ├── __init__.py
│   │   ├── forms.py
│   │   ├── models.py
│   │   └── views.py
│   ├── core/
│   │   ├── __init__.py
│   │   └── views.py
│   ├── static/
│   │   └── styles.css
│   ├── templates/
│   │   ├── accounts/
│   │   │   ├── login.html
│   │   │   ├── register.html
│   │   │   ├── setup-2fa.html
│   │   │   └── verify-2fa.html
│   │   ├── core/
│   │   │   └── index.html
│   │   ├── _base.html
│   │   └── navigation.html
│   ├── __init__.py
│   └── utils.py
├── .env
├── config.py
└── manage.py
</code></pre>
<h2 id="heading-wrapping-up"><strong>Wrapping up</strong></h2>
<p>In this tutorial, you learned how to set up two-factor authentication in your Flask app using PyOTP.</p>
<p>Here's the link to the <a target="_blank" href="https://github.com/ashutoshkrris/Flask-Two-Factor-Authentication">GitHub repository</a>. Feel free to check it out whenever you're stuck.</p>
<p>Here are some other tutorials I wrote about authentication, email verification, and OTPs that you might enjoy:</p>
<ul>
<li><a target="_blank" href="https://blog.ashutoshkrris.in/how-to-set-up-basic-user-authentication-in-a-flask-app">How to Set Up Basic User Authentication in a Flask App</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-to-setup-user-authentication-in-flask/">How to Set Up Email Verification in a Flask App</a></li>
<li><a target="_blank" href="https://blog.ashutoshkrris.in/how-to-generate-otps-using-pyotp-in-python">How To Generate OTPs Using PyOTP in Python</a></li>
</ul>
<p>Thank you for reading. I hope you found this article useful. You can follow me on <a target="_blank" href="https://twitter.com/ashutoshkrris">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Automate Data Exports and Email Reports with Python – a Step-by-Step Guide ]]>
                </title>
                <description>
                    <![CDATA[ In today's data-driven world, automation is key to streamlining tasks and saving time. In this beginner-friendly tutorial, I'll walk you through the process of automating data exports from a PostgreSQL database and sending them as an email attachment... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/automate-data-exports-email-reports-with-python/</link>
                <guid isPermaLink="false">66ba0e68d14c87384322b68d</guid>
                
                    <category>
                        <![CDATA[ automation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ excel ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgres ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 30 Oct 2023 16:08:37 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/report-automation.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In today's data-driven world, automation is key to streamlining tasks and saving time. In this beginner-friendly tutorial, I'll walk you through the process of automating data exports from a PostgreSQL database and sending them as an email attachment using Python. </p>
<p>This step-by-step guide will help you grasp the fundamentals of working with databases, data manipulation, and email communication, all while automating these processes with a Python script.</p>
<h2 id="heading-business-context">Business Context</h2>
<p>Imagine you're a part of an organization where your managers expect a weekly report filled with valuable insights. But creating this report is far from a straightforward task. </p>
<p>To get the information you need, you have to manually run ten different database queries, gather the results, and then meticulously compile them into an Excel spreadsheet. It's a time-consuming and error-prone process that can leave you exhausted.</p>
<p>In this scenario, wouldn't it be a game-changer if Python could take the reins and handle this entire process for you? </p>
<p>Picture this: Every week, without any manual intervention, Python seamlessly extracts the required data, compiles it into a neat Excel sheet, and even sends it off to your managers like clockwork. </p>
<p>This tutorial will help you learn how to do this. I'll walk you through the steps to automate this process, making your weekly or monthly reporting a breeze, and freeing you up to focus on more critical tasks.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-your-virtual-environment">How to Set Up Your Virtual Environment</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-your-sample-database">How to Set Up Your Sample Database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-logging-and-environment-variables">How to Set Up Logging and Environment Variables</a></li>
<li><a class="post-section-overview" href="#heading-how-to-extract-the-data-from-the-database">How to Extract the Data From the Database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-structure-the-booking-data-with-the-bookinginfo-class">How to Structure the Booking Data with the <code>BookingInfo</code> Class</a></li>
<li><a class="post-section-overview" href="#heading-how-to-convert-the-data-into-an-excel-sheet">How to Convert the Data into an Excel Sheet</a></li>
<li><a class="post-section-overview" href="#heading-how-to-combine-the-functionalities">How to Combine the Functionalities</a></li>
<li><a class="post-section-overview" href="#heading-how-to-send-an-email-with-the-bookings-data-report">How to Send an Email with the Bookings Data Report</a></li>
<li><a class="post-section-overview" href="#heading-how-to-test-the-flow">How to Test the Flow</a></li>
<li><a class="post-section-overview" href="#heading-how-to-schedule-the-application">How to Schedule the Application</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you get started, make sure you have the following:</p>
<ol>
<li>Python installed on your computer. You can download Python from <a target="_blank" href="https://www.python.org/downloads/">Python.org</a>.</li>
<li>Basic knowledge of the Python programming language</li>
<li>Familiarity with <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-send-emails-using-python">sending emails in Python</a></li>
<li>PostgreSQL installed on your computer. You can download PostgreSQL from <a target="_blank" href="https://www.postgresql.org/download/">here</a>.</li>
</ol>
<h2 id="heading-how-to-set-up-your-virtual-environment">How to Set Up Your Virtual Environment</h2>
<p>Before you start coding, you'll need to make sure you have all the necessary tools and libraries installed. </p>
<p>To ensure that you have a clean and isolated environment, you'll <a target="_blank" href="https://www.freecodecamp.org/news/how-to-setup-virtual-environments-in-python/">create a virtual environment</a> using <code>venv</code>.</p>
<p>Create a project directory and navigate to it in the terminal:</p>
<pre><code class="lang-bash">mkdir report-automation
<span class="hljs-built_in">cd</span> report-automation
</code></pre>
<p>Create a virtual environment named <code>env</code> using the following command:</p>
<pre><code class="lang-bash">python -m venv env
</code></pre>
<p>Python now ships with the pre-installed <code>venv</code> library to create virtual environments.</p>
<p>Activate the virtual environment like this:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> env/bin/activate
</code></pre>
<p>Note: if you're on Windows, you'll need to use <code>source env/Scripts/activate</code> to activate the environment.</p>
<p>You should see <code>(env)</code> in your terminal prompt, indicating that the virtual environment has been activated.</p>
<h3 id="heading-how-to-install-the-required-libraries">How to Install the Required Libraries</h3>
<p>Now that you've created the virtual environment, you can install the following libraries:</p>
<ul>
<li><code>psycopg2</code>: Python adapter for PostgreSQL, enabling Python applications to interact with PostgreSQL databases.</li>
<li><code>pandas</code>: A versatile data manipulation and analysis library for Python, ideal for working with structured data.</li>
<li><code>xlsxwriter</code>: Python module for creating and formatting Excel (XLSX) files, useful for generating reports and spreadsheets.</li>
</ul>
<p>To install the libraries, run the following command:</p>
<pre><code class="lang-bash">pip install psycopg2 pandas xlsxwriter
</code></pre>
<h2 id="heading-how-to-set-up-your-sample-database">How to Set Up Your Sample Database</h2>
<p>In this section, I will guide you through setting up a demo database named "airlines" that we'll use throughout this tutorial. The database includes three tables: <code>bookings</code>, <code>flights</code>, and <code>airports_data</code>. </p>
<p>I will provide you with an SQL script file named <code>airlines_db.sql</code> that creates the database and populates it with sample data. To set up the database, you will need PostgreSQL installed on your system.</p>
<h3 id="heading-download-and-install-the-database">Download and Install the Database</h3>
<ol>
<li>Download the SQL script file "airlines_db.sql" from <a target="_blank" href="https://drive.google.com/file/d/1CPo4ZC8dmuyCetEwpyDa6pfKnpbiqyO3/view?usp=sharing">here</a>.</li>
<li>Open your terminal or command prompt.</li>
<li>Use the following command to install the database. Make sure you have the PostgreSQL command-line tools installed and that you can access the <code>psql</code> command. Replace <code>postgres</code> with your PostgreSQL username if it's different.</li>
</ol>
<pre><code class="lang-bash">psql -f airlines_db.sql -U postgres
</code></pre>
<p>This command will execute the SQL script and create the "airlines" database with the <code>bookings</code>, <code>flights</code>, and <code>airports_data</code> tables.</p>
<h3 id="heading-schema-description">Schema Description</h3>
<p>The main schema in the database is <code>bookings</code>. Let's take a closer look at the tables in the "airlines" database:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-29-115228.png" alt="Image" width="600" height="400" loading="lazy">
<em>Schema Diagram</em></p>
<h4 id="heading-table-bookingsbookings">Table <code>bookings.bookings</code></h4>
<p>The "bookings" table is designed to store crucial information about bookings made for flights. Each booking is uniquely identified by the <code>book_ref</code>, which is a <code>character(6)</code> field. The <code>total_amount</code> field is a <code>numeric(10,2)</code> type and represents the total cost of the booking. </p>
<p>To track the booking date and time, the table includes a <code>book_date</code> field of type <code>bigint</code>. This table serves as the central repository for booking data and is essential for tracking passenger reservations, costs, and booking dates.</p>
<h4 id="heading-table-bookingsflights">Table <code>bookings.flights</code></h4>
<p>The "flights" table is dedicated to capturing comprehensive details about flights, including information about their statuses, scheduled and actual times of departure and arrival, and other important flight-related data. </p>
<p>The primary key for this table is the <code>flight_id</code>, an <code>integer</code> identifier. Each flight is associated with a specific flight number denoted by the <code>flight_no</code> field, a <code>character(6)</code> type. </p>
<p>To understand the flight's origin and destination, the <code>departure_airport</code> and <code>arrival_airport</code> fields store the departure and arrival airport codes as <code>character(3)</code> types, respectively. </p>
<p>The <code>status</code> field is a <code>character varying(20)</code> that records the flight's status, which must be one of 'On Time,' 'Delayed,' 'Departed,' 'Arrived,' 'Scheduled,' or 'Cancelled.' The table also includes fields for scheduled departure and arrival times (<code>scheduled_departure</code> and <code>scheduled_arrival</code>) and actual departure and arrival times (<code>actual_departure</code> and <code>actual_arrival</code>). </p>
<p>Furthermore, this table establishes two essential foreign keys: <code>flights_arrival_airport_fkey</code> and <code>flights_departure_airport_fkey</code>, which link to the <code>airport_code</code> in the "airports_data" table. This establishes connections between flights and their respective departure and arrival airports.</p>
<h4 id="heading-table-bookingsairportsdata">Table <code>bookings.airports_data</code></h4>
<p>The "airports_data" table serves as a repository for data related to airports and their geographic locations. Each airport is identified by a unique <code>character(3)</code> code stored in the <code>airport_code</code> field, which also serves as the primary key. </p>
<p>The <code>timezone</code> field, of type <code>text</code>, records the specific timezone of the airport, providing essential information for scheduling and operational purposes. The <code>airport_name</code> field is a <code>character varying</code> type that holds the name of the airport. Additionally, the table includes the <code>city</code> field as a <code>character varying</code> type, indicating the city in which the airport is situated. </p>
<p>These details enable the "airports_data" table to provide a comprehensive overview of airport locations and information. This serves as a reference for the "flights" table through the <code>flights_arrival_airport_fkey</code> and <code>flights_departure_airport_fkey</code> foreign keys, facilitating the association between flights and their respective departure and arrival airports.</p>
<h2 id="heading-how-to-set-up-logging-and-environment-variables">How to Set Up Logging and Environment Variables</h2>
<p>In this section, we'll configure logging to provide informative messages and handle errors throughout the code. We'll also set up environment variables to securely store sensitive information and configuration parameters. These practices enhance code readability, maintainability, and security.</p>
<h3 id="heading-logging-configuration">Logging Configuration</h3>
<p>We will utilize Python's built-in <code>logging</code> module to configure a logging system. Logging is essential for tracking the execution flow of the code and capturing important information or errors. </p>
<p>The <code>logging.basicConfig</code> method is called to define the format of log messages and set the logging level to <code>INFO</code>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> logging

logging.basicConfig(
    format=<span class="hljs-string">"%(asctime)s | %(levelname)s : %(message)s"</span>, level=logging.INFO
)
</code></pre>
<ul>
<li><strong>Format</strong>: The <code>format</code> parameter specifies the format of log messages. In this case, each log entry includes a timestamp, log level (for example, INFO, ERROR), and the actual log message.</li>
<li><strong>Log Levels</strong>: We set the logging level to <code>INFO</code>, which means the logger will record informational messages. You can also use higher severity levels, such as <code>WARNING</code> or <code>ERROR</code>, for more critical issues.</li>
</ul>
<p>You can learn more about logging in Python in <a target="_blank" href="https://earthly.dev/blog/logging-in-python/">this tutorial</a>.</p>
<h3 id="heading-how-to-manage-environment-variables">How to Manage Environment Variables</h3>
<p>We will create a <code>.env</code> file to manage environment variables. Environment variables are used to store sensitive information and configuration settings, allowing us to keep such data separate from the code. </p>
<p>In this case, we set environment variables for email credentials and database connection details.</p>
<pre><code><span class="hljs-keyword">export</span> EMAIL=
<span class="hljs-keyword">export</span> PASSWORD=
<span class="hljs-keyword">export</span> EMAIL_PORT=<span class="hljs-number">587</span>
<span class="hljs-keyword">export</span> SMTP_SERVER=smtp.gmail.com
<span class="hljs-keyword">export</span> DB_HOSTNAME=localhost
<span class="hljs-keyword">export</span> DB_NAME=airlines
<span class="hljs-keyword">export</span> DB_PORT=<span class="hljs-number">5432</span>
<span class="hljs-keyword">export</span> DB_USERNAME=postgres
<span class="hljs-keyword">export</span> DB_PASSWORD=postgres
</code></pre><p>Here's a breakdown of the variables:</p>
<ul>
<li><strong>EMAIL</strong>: The email address to be used for sending emails.</li>
<li><strong>PASSWORD</strong>: The password associated with the email account.</li>
<li><strong>EMAIL_PORT</strong>: The port for the email server (for example, SMTP server). The default is 587 for secure email transmission (TLS/SSL).</li>
<li><strong>SMTP_SERVER</strong>: The SMTP server address, often specific to the email service provider.</li>
<li><strong>DB_HOSTNAME</strong>: The hostname or IP address of the PostgreSQL database server.</li>
<li><strong>DB_NAME</strong>: The name of the PostgreSQL database.</li>
<li><strong>DB_PORT</strong>: The port number for connecting to the database (default is 5432 for PostgreSQL).</li>
<li><strong>DB_USERNAME</strong>: The username for authenticating with the database.</li>
<li><strong>DB_PASSWORD</strong>: The password for the database user.</li>
</ul>
<p>Make sure you run <code>source .env</code> to load the environment variables.</p>
<p>By using environment variables, sensitive data like passwords and email credentials can be kept separate from the code, reducing the risk of accidental exposure or unauthorized access. The code can access these variables at runtime, ensuring security and flexibility in configuration.</p>
<h2 id="heading-how-to-extract-the-data-from-the-database">How to Extract the Data From the Database</h2>
<p>Let's start by setting the database configurations.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> logging
<span class="hljs-keyword">import</span> os

logging.basicConfig(
    format=<span class="hljs-string">"%(asctime)s | %(levelname)s : %(message)s"</span>, level=logging.INFO
)

DB_CONFIG = {
    <span class="hljs-string">"host"</span>: os.environ.get(<span class="hljs-string">"DB_HOSTNAME"</span>),
    <span class="hljs-string">"database"</span>: os.environ.get(<span class="hljs-string">"DB_NAME"</span>),
    <span class="hljs-string">"user"</span>: os.environ.get(<span class="hljs-string">"DB_USERNAME"</span>),
    <span class="hljs-string">"password"</span>: os.environ.get(<span class="hljs-string">"DB_PASSWORD"</span>),
}
</code></pre>
<p>The <code>DB_CONFIG</code> dictionary is used to store the configuration parameters for connecting to the PostgreSQL database. These parameters include the host, database name, username, and password. These values can be set through environment variables.</p>
<h3 id="heading-how-to-connect-to-the-database">How to Connect to the Database</h3>
<p>Before we extract the data from the database, we need to connect to our database. We will use the <code>psycopg2</code> library to connect to the PostgreSQL database.</p>
<p>We will start by defining a <code>DataExporter</code> class that will contain methods to extract the database and generate the Excel sheet.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DataExporter</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""Initialize the DataExporter with the database configuration."""</span>
        self.db_config = DB_CONFIG
</code></pre>
<p>The class constructor initializes the <code>DataExporter</code> with the database configuration stored in the <code>DB_CONFIG</code> <a target="_blank" href="https://blog.ashutoshkrris.in/everything-you-need-to-know-about-python-dictionaries">dictionary</a>.</p>
<p>Next, let's define a method that connects to the database.</p>
<pre><code class="lang-python">...
<span class="hljs-keyword">import</span> psycopg2

...

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DataExporter</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""Initialize the DataExporter with the database configuration."""</span>
        self.db_config = DB_CONFIG

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__connect_to_database</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
        <span class="hljs-string">"""
        Establish a connection to the PostgreSQL database.

        Raises:
            Exception: If a connection to the database cannot be established.
        """</span>
        <span class="hljs-keyword">try</span>:
            self.conn = psycopg2.connect(**self.db_config)
            self.cursor = self.conn.cursor()
            logging.info(<span class="hljs-string">"Connected to the database"</span>)
        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            logging.error(
                <span class="hljs-string">"Failed to connect to the database with error: %s"</span>, e)
            <span class="hljs-keyword">raise</span>
</code></pre>
<p>The <code>__connect_to_database</code> private method is responsible for establishing a connection to the PostgreSQL database. It uses the <code>psycopg2</code> library to create a connection and a cursor for executing SQL queries. If the connection fails, it logs an error and raises an exception.</p>
<p>You can learn more about exception handling in Python <a target="_blank" href="https://blog.ashutoshkrris.in/exception-handling-in-python">here</a>.</p>
<h3 id="heading-how-to-fetch-data-from-the-database">How to Fetch Data from the Database</h3>
<p>Now we'll define another private method that connects to the database and fetches the total number of bookings and the total amount from the database.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DataExporter</span>:</span>
    ...

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__fetch_from_database</span>(<span class="hljs-params">self, start_timestamp, end_timestamp</span>) -&gt; list | <span class="hljs-keyword">None</span>:</span>
        <span class="hljs-string">"""
        Fetch booking data from the database for a given time range.

        Args:
            start_timestamp (datetime): The start of the time range.
            end_timestamp (datetime): The end of the time range.

        Returns:
            list: A list containing booking data (num_bookings, total_amount) or None if an error occurs.
        """</span>
        self.__connect_to_database()
        query = <span class="hljs-string">f"""
        SELECT COUNT(*) AS num_bookings, SUM(total_amount) AS total_amount
        FROM bookings
        WHERE book_date &gt;= <span class="hljs-subst">{int(start_timestamp.timestamp()) * <span class="hljs-number">1000</span>}</span> AND book_date &lt;= <span class="hljs-subst">{int(end_timestamp.timestamp()) * <span class="hljs-number">1000</span>}</span>
        """</span>
        logging.info(
            <span class="hljs-string">"Exracting bookings data from database for start timestamp=%s and end_timestamp=%s"</span>,
            start_timestamp,
            end_timestamp,
        )
        result = <span class="hljs-literal">None</span>
        <span class="hljs-keyword">try</span>:
            self.cursor.execute(query)
            result = list(self.cursor.fetchone())
            result.append(
                <span class="hljs-string">f'<span class="hljs-subst">{start_timestamp.strftime(<span class="hljs-string">"%d %b, %Y"</span>)}</span> - <span class="hljs-subst">{end_timestamp.strftime(<span class="hljs-string">"%d %b, %Y"</span>)}</span>'</span>
            )
            logging.info(
                <span class="hljs-string">"Successfully exracted bookings data from database for start timestamp=%s and end_timestamp=%s"</span>,
                start_timestamp,
                end_timestamp,
            )
        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            logging.error(
                <span class="hljs-string">"Error occurred while extracting bookings data from database: %s"</span>, e
            )
        <span class="hljs-keyword">return</span> result
</code></pre>
<p>This private method retrieves booking data from the database for a specified time range. </p>
<p>It takes two <code>datetime</code> objects as arguments, <code>start_timestamp</code> and <code>end_timestamp</code>. It also constructs a SQL query to retrieve the count of bookings and the total booking amount for that time range. </p>
<p>The query is executed, and if it's successful, the method returns the data as a tuple. We convert the tuple into a list and append the timeframe for which data was extracted to the list. If an error occurs during the database interaction, it logs an error and returns <code>None</code>.</p>
<p>Using the above method, you can extract booking data for various timeframes, whether it's for a week, a month, a year, or any custom time range of your choice.</p>
<h2 id="heading-how-to-structure-the-booking-data-with-the-bookinginfo-class">How to Structure the Booking Data with the <code>BookingInfo</code> Class</h2>
<p>In this section, we will define a <code>BookingInfo</code> class in <code>booking_info.py</code>, which serves as a structured container for booking data retrieved from the database. The class encapsulates booking-related information, making it easier to work with and present the data. </p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> decimal <span class="hljs-keyword">import</span> Decimal


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookingInfo</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, data_list: list</span>):</span>
        <span class="hljs-string">"""
        Initialize BookingInfo with data from the database.

        Args:
            data_list (list): A list containing booking data (total_bookings, total_amount, timestamp).

        Note:
            The total_amount is converted to a Decimal type.

        """</span>
        self.__total_bookings, self.__total_amount, self.__timestamp = data_list
        self.__total_amount = Decimal(self.__total_amount) <span class="hljs-keyword">if</span> self.__total_amount <span class="hljs-keyword">else</span> Decimal(<span class="hljs-number">0</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>) -&gt; str:</span>
        <span class="hljs-string">"""
        Return a string representation of BookingInfo.

        Returns:
            str: A string in the format "Total Bookings: X, Total Amount: $Y".

        """</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Total Bookings: <span class="hljs-subst">{self.__total_bookings}</span>, Total Amount: $<span class="hljs-subst">{self.__total_amount}</span>"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_total_bookings</span>(<span class="hljs-params">self</span>) -&gt; int:</span>
        <span class="hljs-string">"""
        Get the total number of bookings.

        Returns:
            int: The total number of bookings.

        """</span>
        <span class="hljs-keyword">return</span> self.__total_bookings

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_total_amount</span>(<span class="hljs-params">self</span>) -&gt; Decimal:</span>
        <span class="hljs-string">"""
        Get the total booking amount as a Decimal.

        Returns:
            Decimal: The total booking amount.

        """</span>
        <span class="hljs-keyword">return</span> self.__total_amount

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_timestamp</span>(<span class="hljs-params">self</span>) -&gt; str:</span>
        <span class="hljs-string">"""
        Get the timestamp associated with the booking data.

        Returns:
            str: The timestamp as a string.

        """</span>
        <span class="hljs-keyword">return</span> self.__timestamp
</code></pre>
<p>The <code>BookingInfo</code> class is designed to organize and represent booking data returned from the database. It receives a list of values containing total bookings, total booking amount, and a timestamp as input and converts the total amount to a Decimal type. The class offers methods for accessing and presenting this data in a structured manner.</p>
<p>The constructor of the <code>BookingInfo</code> class takes a <code>data_list</code> as input, which is expected to be a list containing the following elements:</p>
<ul>
<li><code>total_bookings</code>: An integer representing the total number of bookings.</li>
<li><code>total_amount</code>: A floating-point value representing the total booking amount.</li>
<li><code>timestamp</code>: A timestamp associated with the booking data.</li>
</ul>
<p>The <code>__init__</code> method initializes private instance variables (<code>__total_bookings</code>, <code>__total_amount</code>, and <code>__timestamp</code>) with the values from the <code>data_list</code>. It also converts the <code>__total_amount</code> to a decimal type for precise handling of monetary values.</p>
<p>The <code>__str__</code> method is implemented to provide a string representation of the <code>BookingInfo</code> object. It returns a string in the format "Total Bookings: X, Total Amount: $Y", where <code>X</code> is the total number of bookings and <code>Y</code> is the total booking amount formatted as dollars.</p>
<h3 id="heading-getter-methods">Getter Methods</h3>
<p>The class provides three getter methods to access the encapsulated data:</p>
<ul>
<li><code>get_total_bookings()</code>: Returns the total number of bookings as an integer.</li>
<li><code>get_total_amount()</code>: Returns the total booking amount as a Decimal type.</li>
<li><code>get_timestamp()</code>: Returns the timestamp associated with the booking data as a string.</li>
</ul>
<p>By encapsulating the booking data within the <code>BookingInfo</code> class, the code is more organized, readable, and reusable. This structured approach simplifies the handling of booking information throughout the application, making it more intuitive to work with and present the data.</p>
<h2 id="heading-how-to-convert-the-data-into-an-excel-sheet">How to Convert the Data into an Excel Sheet</h2>
<p>Now that you can retrieve data from the database for a specific time range, you can also generate an Excel sheet based on the extracted data. </p>
<p>To do this, let's define another private method to create the Excel sheet.</p>
<pre><code class="lang-python">...
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd

<span class="hljs-keyword">from</span> booking_info <span class="hljs-keyword">import</span> BookingInfo


...

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DataExporter</span>:</span>

    ...

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__convert_to_excelsheet</span>(<span class="hljs-params">self, data: list, sheet_name: str</span>):</span>
        <span class="hljs-string">"""
        Convert the fetched data into an Excel sheet.

        Args:
            data (list): A list containing booking data.
            sheet_name (str): Name of the Excel sheet to be created.

        Raises:
            ValueError: If there is an error in converting data to an Excel sheet.
        """</span>
        <span class="hljs-keyword">try</span>:
            booking_info = BookingInfo(data)
            data = {
                <span class="hljs-string">""</span>: [<span class="hljs-string">"Total Bookings"</span>, <span class="hljs-string">"Total Amount ($)"</span>],
                booking_info.get_timestamp(): [
                    booking_info.get_total_bookings(),
                    booking_info.get_total_amount(),
                ],
            }
            logging.info(<span class="hljs-string">"Converting the data into pandas dataframe"</span>)
            df = pd.DataFrame(data)
            logging.info(<span class="hljs-string">"Inserting the data into the excelsheet"</span>)
            <span class="hljs-keyword">with</span> pd.ExcelWriter(sheet_name, engine=<span class="hljs-string">"xlsxwriter"</span>) <span class="hljs-keyword">as</span> writer:
                df.to_excel(writer, sheet_name=<span class="hljs-string">"Sheet1"</span>, index=<span class="hljs-literal">False</span>)
            logging.info(<span class="hljs-string">"Successfully inserted data into the excelsheet"</span>)
        <span class="hljs-keyword">except</span> ValueError <span class="hljs-keyword">as</span> e:
            logging.error(<span class="hljs-string">"Error converting data into excel: %s"</span>, e)
</code></pre>
<p>The <code>__convert_to_excelsheet</code> method within the <code>DataExporter</code> class is responsible for structuring and converting extracted booking data into an Excel sheet. </p>
<p>It accepts two input parameters. The first parameter, <code>data</code>, is expected to be a list containing specific booking data. This data includes the total number of bookings, the total booking amount, and a timestamp for which data was extracted. The second parameter, <code>sheet_name</code>, represents the desired name for the Excel sheet that will contain the formatted data.</p>
<p>A key aspect of the method is the structuring of the data. To achieve this, the method initiates the creation of a <code>BookingInfo</code> object, referred to as <code>booking_info</code>. The <code>BookingInfo</code> object provides a structured representation of the booking data, which simplifies the subsequent formatting and presentation.</p>
<p>Following the creation of the <code>booking_info</code> object, a new dictionary called <code>data</code> is generated. This dictionary is designed to structure the data in a format suitable for conversion into an Excel sheet. </p>
<p>The dictionary consists of two key-value pairs:</p>
<ul>
<li>The first pair uses an empty string as the key and contains a list with two header values, "Total Bookings" and "Total Amount ($)".</li>
<li>The second pair uses the timestamp obtained from <code>booking_info.get_timestamp()</code> as the key and includes a list with two elements: the total number of bookings (<code>booking_info.get_total_bookings()</code>) and the total booking amount (<code>booking_info.get_total_amount()</code>).</li>
</ul>
<p>This dictionary allows the data to be inserted in the excel sheet as below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-29-135512.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sample Excel Sheet</em></p>
<p>Then, the structured <code>data</code> dictionary is converted into a pandas DataFrame, referred to as <code>df</code>. Dataframes are a commonly used data structures for handling tabular data in Python. This step streamlines the manipulation and export of the data for further processing or visualization. </p>
<p>To create the Excel sheet, the code uses the <code>pd.ExcelWriter</code> context manager with the "xlsxwriter" engine. This context manager ensures that the Excel file is appropriately prepared for data insertion. The <code>sheet_name</code> parameter is supplied to specify the name of the sheet within the Excel file.</p>
<p>The data within the DataFrame, <code>df</code>, is then written to the Excel sheet. The <code>to_excel</code> method is used in conjunction with the <code>writer</code> object, and the <code>index</code> parameter is set to <code>False</code>. This specific configuration excludes the default row numbers that are typically included in Excel sheets.</p>
<h2 id="heading-how-to-combine-the-functionalities">How to Combine the Functionalities</h2>
<p>Now let's write a public method that the users can use to extract the data from the database and convert the extracted data into the Excel sheet file.</p>
<pre><code class="lang-python">...


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DataExporter</span>:</span>

    ...

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_excelsheet</span>(<span class="hljs-params">
        self,
        start_timestamp: datetime,
        end_timestamp: datetime,
        sheet_name: str = <span class="hljs-string">"Bookings Data.xlsx"</span>,
    </span>) -&gt; bool:</span>
        <span class="hljs-string">"""
        Generate an Excel sheet with booking data for a specified time range.

        Args:
            start_timestamp (datetime): The start of the time range.
            end_timestamp (datetime): The end of the time range.
            sheet_name (str, optional): Name of the Excel sheet to be created. Defaults to "Bookings Data.xlsx".

        Returns:
            bool: True if excelsheet was generated successfully else False

        Note:
            This method logs errors but does not raise exceptions to avoid breaking the workflow.
        """</span>
        data = self.__fetch_from_database(start_timestamp, end_timestamp)
        <span class="hljs-keyword">if</span> data <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span>:
            self.__convert_to_excelsheet(data, sheet_name)
            <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
        <span class="hljs-keyword">else</span>:
            logging.error(<span class="hljs-string">"No data to convert generate excelsheet"</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
</code></pre>
<p>This method accepts several parameters, including <code>start_timestamp</code> and <code>end_timestamp</code>, which define the beginning and end of the time period for data extraction. There's also an optional <code>sheet_name</code> parameter that allows the user to specify the name of the Excel sheet. By default, the sheet is named "Bookings Data.xlsx" to provide a convenient default option.</p>
<p>Upon execution, the method initiates the data retrieval process by calling the <code>__fetch_from_database</code> method, an internal private method of the class, with the specified time range. </p>
<p>If the data retrieval is successful and data is available, the method proceeds to call the <code>__convert_to_excelsheet</code> method. This structures and formats the data for insertion into the Excel sheet. </p>
<p>If, on the other hand, no data is available for the provided time range, the method logs an error message and returns "False" to indicate that the Excel sheet generation was unsuccessful.</p>
<h2 id="heading-how-to-send-an-email-with-the-bookings-data-report">How to Send an Email with the Bookings Data Report</h2>
<p>In this section, you will learn how you can <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-send-emails-using-python">use Python to send an email</a> with a bookings data report as an attachment.</p>
<p>Create a <code>mailer.py</code> file and add the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> logging
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> smtplib
<span class="hljs-keyword">import</span> ssl

<span class="hljs-keyword">from</span> email <span class="hljs-keyword">import</span> encoders
<span class="hljs-keyword">from</span> email.mime.base <span class="hljs-keyword">import</span> MIMEBase
<span class="hljs-keyword">from</span> email.mime.multipart <span class="hljs-keyword">import</span> MIMEMultipart
<span class="hljs-keyword">from</span> email.mime.text <span class="hljs-keyword">import</span> MIMEText

logging.basicConfig(
    format=<span class="hljs-string">"%(asctime)s | %(levelname)s : %(message)s"</span>, level=logging.INFO
)

SMTP_SERVER = os.environ.get(<span class="hljs-string">"SMTP_SERVER"</span>)
PORT = os.environ.get(<span class="hljs-string">"EMAIL_PORT"</span>)
EMAIL = os.environ.get(<span class="hljs-string">"EMAIL"</span>)
PASSWORD = os.environ.get(<span class="hljs-string">"PASSWORD"</span>)


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_email</span>(<span class="hljs-params">to_email: str, subject: str, attachment_name: str</span>):</span>
    <span class="hljs-string">"""
    Send an email with an attachment to the specified recipient.

    Args:
        to_email (str): The recipient's email address.
        subject (str): The subject of the email.
        attachment_name (str): The filename of the attachment.

    Note:
        This function assumes that the SMTP server requires TLS encryption.

    Raises:
        smtplib.SMTPException: If there is an issue with sending the email.

    """</span>
    message = MIMEMultipart()
    message[<span class="hljs-string">"From"</span>] = EMAIL
    message[<span class="hljs-string">"To"</span>] = to_email
    message[<span class="hljs-string">"Subject"</span>] = subject
    body = <span class="hljs-string">"Hi there\n\nPlease find attached your report.\n\nThanks"</span>

    message.attach(MIMEText(body, <span class="hljs-string">"plain"</span>))

    <span class="hljs-keyword">with</span> open(attachment_name, <span class="hljs-string">"rb"</span>) <span class="hljs-keyword">as</span> file:
        part = MIMEBase(
            <span class="hljs-string">"application"</span>, <span class="hljs-string">"vnd.openxmlformats-officedocument.spreadsheetml.sheet"</span>
        )
        part.set_payload(file.read())

    encoders.encode_base64(part)

    part.add_header(
        <span class="hljs-string">"Content-Disposition"</span>,
        <span class="hljs-string">f"attachment; filename= <span class="hljs-subst">{attachment_name}</span>"</span>,
    )

    logging.info(<span class="hljs-string">f"Attaching <span class="hljs-subst">{attachment_name}</span> to the email"</span>)
    message.attach(part)
    text = message.as_string()

    context = ssl.create_default_context()
    <span class="hljs-keyword">with</span> smtplib.SMTP(SMTP_SERVER, PORT) <span class="hljs-keyword">as</span> server:
        logging.info(<span class="hljs-string">f"Sending email to <span class="hljs-subst">{to_email}</span>"</span>)
        server.starttls(context=context)
        server.login(EMAIL, PASSWORD)
        server.sendmail(EMAIL, to_email, text)
        logging.info(<span class="hljs-string">f"Successfully sent the email to <span class="hljs-subst">{to_email}</span>"</span>)
</code></pre>
<p>As usual, we have configured the logger and environment variables in our script. </p>
<p>The core functionality is encapsulated within the <code>send_email</code> function. This function takes three parameters:</p>
<ol>
<li><code>to_email</code>: The recipient's email address.</li>
<li><code>subject</code>: The subject of the email.</li>
<li><code>attachment_name</code>: The filename of the attachment, which should be the bookings data report in this context.</li>
</ol>
<p>Within the function, we construct an email message using the <code>MIMEMultipart</code> class. This message includes the sender's email address, recipient's email address, subject, and a plain text body with a simple message.</p>
<p>The script allows attaching the bookings data report as an attachment. It reads the attachment file, encodes it, and adds it to the email message. This ensures that the recipient can easily access and download the data report from the email.</p>
<p>You can learn how you can add attachments while sending emails using Python <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-send-emails-using-python#heading-including-attachments">here</a>.</p>
<p>The <code>create_default_context</code> function from the <code>ssl</code> library creates a secure SSL context for email communication. Finally, the script connects to the SMTP server, logs in using the sender's email address and password, sends the email, and logs a success message upon successful transmission.</p>
<h2 id="heading-how-to-test-the-flow">How to Test the Flow</h2>
<p>Let's finally test the flow of the application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/finally-about-time.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In this section, we will automate the monthly reports. Create a <code>main.py</code> file and add the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> exporter <span class="hljs-keyword">import</span> DataExporter
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime
<span class="hljs-keyword">from</span> mailer <span class="hljs-keyword">import</span> send_email

start_timestamp = datetime(<span class="hljs-number">2023</span>, <span class="hljs-number">5</span>, <span class="hljs-number">28</span>, <span class="hljs-number">00</span>, <span class="hljs-number">00</span>, <span class="hljs-number">00</span>)  <span class="hljs-comment"># May 28 2023 00:00:00</span>
end_timestamp = datetime(<span class="hljs-number">2023</span>, <span class="hljs-number">8</span>, <span class="hljs-number">20</span>, <span class="hljs-number">23</span>, <span class="hljs-number">59</span>, <span class="hljs-number">59</span>)  <span class="hljs-comment"># Aug 20 2023 23:59:59</span>

exporter = DataExporter()
<span class="hljs-keyword">if</span> exporter.generate_excelsheet(
        start_timestamp, end_timestamp, sheet_name=<span class="hljs-string">"Bookings Data.xlsx"</span>):
    send_email(<span class="hljs-string">"myemail@gmail.com"</span>, <span class="hljs-string">"Your Report"</span>, <span class="hljs-string">"Bookings Data.xlsx"</span>)
</code></pre>
<p>In the above code, we create two timestamp objects, <code>start_timestamp</code> and <code>end_timestamp</code>, to specify a time range. We have the start date set to May 28, 2023 at midnight and the end date set to August 20, 2023 just before midnight. </p>
<p>Next, we create an instance of the <code>DataExporter</code> class, which handles the data export and Excel sheet generation. The <code>generate_excelsheet</code> method of this instance is called with the previously defined timestamps to create a report related to bookings. </p>
<p>Finally, the code sends an email with the generated Excel sheet as an attachment using the <code>send_email</code> function.</p>
<h2 id="heading-how-to-schedule-the-application">How to Schedule the Application</h2>
<p>Next, our goal is to automate the report scheduling process. We aim to schedule report deliveries for two distinct scenarios: on every Monday for the previous week's data, and on the 1st day of every month for the previous month's information. </p>
<p>To schedule the execution, you will need to install the <code>schedule</code> library:</p>
<pre><code class="lang-bash">pip install schedule
</code></pre>
<p>Once the library is installed, here's how you can do automate the monthly and weekly reports:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> schedule
<span class="hljs-keyword">from</span> exporter <span class="hljs-keyword">import</span> DataExporter
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime, timedelta
<span class="hljs-keyword">from</span> mailer <span class="hljs-keyword">import</span> send_email


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    today = datetime.now()
    sheet_name = <span class="hljs-string">"Bookings Data.xlsx"</span>

    <span class="hljs-keyword">if</span> today.weekday() == <span class="hljs-number">0</span>:  <span class="hljs-comment"># Check if it's Monday (0 means Monday)</span>
        <span class="hljs-comment"># It's Monday, fetch data for the previous week (Monday to Sunday)</span>
        start_timestamp = (today - timedelta(days=<span class="hljs-number">7</span>)
                           ).replace(hour=<span class="hljs-number">0</span>, minute=<span class="hljs-number">0</span>, second=<span class="hljs-number">0</span>, microsecond=<span class="hljs-number">0</span>)
        end_timestamp = (today - timedelta(days=<span class="hljs-number">1</span>)
                         ).replace(hour=<span class="hljs-number">23</span>, minute=<span class="hljs-number">59</span>, second=<span class="hljs-number">59</span>, microsecond=<span class="hljs-number">0</span>)
        sheet_name = <span class="hljs-string">"Weekly Report.xlsx"</span>
    <span class="hljs-keyword">elif</span> today.day == <span class="hljs-number">29</span>:
        <span class="hljs-comment"># It's the 1st day of the month, fetch data for the last month</span>
        start_timestamp = (today.replace(day=<span class="hljs-number">1</span>) - timedelta(days=<span class="hljs-number">1</span>)
                           ).replace(day=<span class="hljs-number">1</span>, hour=<span class="hljs-number">0</span>, minute=<span class="hljs-number">0</span>, second=<span class="hljs-number">0</span>, microsecond=<span class="hljs-number">0</span>)
        end_timestamp = (today.replace(day=<span class="hljs-number">1</span>) - timedelta(days=<span class="hljs-number">1</span>)
                         ).replace(hour=<span class="hljs-number">23</span>, minute=<span class="hljs-number">59</span>, second=<span class="hljs-number">59</span>, microsecond=<span class="hljs-number">0</span>)
        sheet_name = <span class="hljs-string">"Monthly Report.xlsx"</span>

    exporter = DataExporter()
    exporter.generate_excelsheet(
        start_timestamp, end_timestamp, sheet_name)

    send_email(<span class="hljs-string">"youremail@gmail.com"</span>,
               <span class="hljs-string">"Your Report"</span>, sheet_name)


schedule.every().day.at(<span class="hljs-string">"00:00"</span>).do(main)

<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
    schedule.run_pending()
</code></pre>
<p>The above script uses the <code>schedule</code> library to run the <code>main</code> function daily at midnight. The <code>main</code> function calculates the timestamps for data extraction and Excel sheet generation. After generating the Excel sheet, the script sends it via email to a specified recipient.</p>
<p>If the script runs on a Monday, it sets up to generate a weekly report. It calculates the <code>start_timestamp</code> and <code>end_timestamp</code> for the previous week. The <code>start_timestamp</code> is set to the previous Monday at midnight (00:00:00), and the <code>end_timestamp</code> is set to the previous Sunday just before midnight (23:59:59). The Excel sheet is named "Weekly Report.xlsx."</p>
<p>On the 1st day of the month, the script shifts its focus to generating a monthly report. It calculates the <code>start_timestamp</code> and <code>end_timestamp</code> to encompass the entire previous month. The <code>start_timestamp</code> is set to the first day of the previous month at midnight (00:00:00), while the <code>end_timestamp</code> is set to the last day of the previous month just before midnight (23:59:59). The Excel sheet is named "Monthly Report.xlsx."</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this tutorial, you learned how you can leverage Python to automate generating a report and sending it to email recipients. I hope you found the tutorial helpful!</p>
<h3 id="heading-future-scope">Future Scope</h3>
<ul>
<li>You can add the email recipients in a database and fetch their list from there instead of hardcoding them in the code itself. This will make the application more configurable.</li>
<li>You can also use Cron Jobs to automate the execution of the script every day at midnight. In that case, you won't need the <code>schedule</code> library.</li>
</ul>
<p>Here's a link to the <a target="_blank" href="https://github.com/ashutoshkrris/report-automation">Github Code Repository</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Digital Products Store with Medusa and Next.js ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you will learn how to build an e-book online store using Medusa and Next.js. Throughout the course of the article, we will: Utilize the Medusa Next.js Starter Template along with the Digital Products Recipe build the store. Enhance... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-digital-products-store-with-medusa-and-next-js/</link>
                <guid isPermaLink="false">66ba0e6b79b7f411df58dea1</guid>
                
                    <category>
                        <![CDATA[ ecommerce ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Tue, 17 Oct 2023 22:59:34 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/digital-products.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you will learn how to build an e-book online store using Medusa and Next.js.</p>
<p>Throughout the course of the article, we will:</p>
<ol>
<li>Utilize the Medusa <a target="_blank" href="https://medusajs.com/nextjs-commerce/">Next.js Starter Template</a> along with the <a target="_blank" href="https://docs.medusajs.com/recipes/digital-products">Digital Products Recipe</a> build the store.</li>
<li>Enhance the product pages to suit digital products. This involves adding a button for previewing media content and displaying essential product details.</li>
<li>Refine the checkout process to make it more efficient for delivering digital products.</li>
<li>Create Next.js API routes to validate and conceal file paths for product downloads.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/rmjjaunyells0it99c7a.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Demo of the final application</em></p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-medusa">What is Medusa?</a></li>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-starting-out">Starting Out</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-typescript-type-definitions">How to Set Up TypeScript Type Definitions</a></li>
<li><a class="post-section-overview" href="#heading-how-to-incorporate-e-book-previews-into-the-product-details">How to Incorporate e-Book Previews into the Product Details</a></li>
<li><a class="post-section-overview" href="#heading-how-to-offer-e-book-previews">How to Offer e-Book Previews</a></li>
<li><a class="post-section-overview" href="#heading-how-to-adjust-the-product-and-shipping-details">How to Adjust the Product and Shipping Details</a></li>
<li><a class="post-section-overview" href="#heading-how-to-simplify-the-checkout">How to Simplify the Checkout</a></li>
<li><a class="post-section-overview" href="#heading-how-to-deliver-digital-products">How to Deliver Digital Products</a></li>
</ol>
<p>Let's get started.</p>
<h2 id="heading-what-is-medusa">What is Medusa?</h2>
<p>Medusa is a suite of tools and modules specifically designed for e-Commerce products. </p>
<p>Using Medusa, you can build modularized commerce logic like <a target="_blank" href="https://docs.medusajs.com/modules/carts-and-checkout/overview">carts</a>, <a target="_blank" href="https://docs.medusajs.com/modules/products/overview">products</a>, and <a target="_blank" href="https://docs.medusajs.com/modules/orders/overview">order management</a>. It also provide tools that help you orchestrate powerful ecommerce websites, POS applications, commerce-enabled products, and everything in between.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you get started with the tutorial, you should have installed:</p>
<ul>
<li><a target="_blank" href="https://docs.medusajs.com/tutorial/set-up-your-development-environment#nodejs">Node.js(V14 or later)</a></li>
<li><a target="_blank" href="https://docs.medusajs.com/tutorial/set-up-your-development-environment/#git">Git</a></li>
<li><a target="_blank" href="https://docs.medusajs.com/tutorial/set-up-your-development-environment#medusa-cli">Medusa CLI</a></li>
</ul>
<h2 id="heading-starting-out">Starting Out</h2>
<p>Using the Next.js starter, you can create a new Medusa app by running the following command:</p>
<pre><code class="lang-bash">npx create-medusa-app@latest --with-nextjs-starter
</code></pre>
<p>After that, you can opt to create a user account for admin panel access. Then, set up the backend infrastructure following the Medusa Digital Products Recipe. </p>
<p>Once the backend is set, create sample products through your Medusa admin interface. Make sure that these products include digital media files for previews and primary content. Also make sure to incorporate relevant product metadata values using key/value pairs linked to each product.</p>
<h2 id="heading-how-to-set-up-typescript-type-definitions">How to Set Up TypeScript Type Definitions</h2>
<p>If you’re using regular JavaScript, you can skip this step.</p>
<p>Before we continue, let's make sure to add in the necessary TypeScript type definitions for digital products in the Next.js storefront.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Product } <span class="hljs-keyword">from</span> <span class="hljs-string">"@medusajs/medusa"</span>
<span class="hljs-keyword">import</span> { ProductVariant } <span class="hljs-keyword">from</span> <span class="hljs-string">"@medusajs/product"</span>

<span class="hljs-keyword">export</span> enum ProductMediaVariantType {
  PREVIEW = <span class="hljs-string">"preview"</span>,
  MAIN = <span class="hljs-string">"main"</span>,
}

<span class="hljs-keyword">export</span> type ProductMedia = {
  <span class="hljs-attr">id</span>: string
  name?: string
  file?: string
  mime_type?: string
  created_at?: <span class="hljs-built_in">Date</span>
  updated_at?: <span class="hljs-built_in">Date</span>
  attachment_type?: ProductMediaVariantType
  variant_id?: string
  variants?: ProductMediaVariant[]
}

<span class="hljs-keyword">export</span> type ProductMediaVariant = {
  <span class="hljs-attr">id</span>: string
  <span class="hljs-attr">variant_id</span>: string
  <span class="hljs-attr">product_media_id</span>: string
  <span class="hljs-attr">type</span>: string
  <span class="hljs-attr">created_at</span>: <span class="hljs-built_in">Date</span>
  <span class="hljs-attr">updated_at</span>: <span class="hljs-built_in">Date</span>
}

<span class="hljs-keyword">export</span> type DigitalProduct = Omit&lt;Product, <span class="hljs-string">"variants"</span>&gt; &amp; {
  product_medias?: ProductMedia[]
  variants?: DigitalProductVariant[]
}

<span class="hljs-keyword">export</span> type DigitalProductVariant = ProductVariant &amp; {
  product_medias?: ProductMedia
}

      <span class="hljs-keyword">throw</span> err
    })

  <span class="hljs-keyword">return</span> product_medias[<span class="hljs-number">0</span>]
}
</code></pre>
<p>This code defines TypeScript types and interfaces for managing digital products and their associated media files in an e-commerce system. It introduces several crucial structures:</p>
<ol>
<li><code>ProductMedia</code>: This interface describes media files related to a product. These files can include images, documents, or any digital assets. It encompasses properties such as an <code>id</code> (a unique identifier for the media), <code>name</code> (an optional name for the media), <code>file</code> (representing the file path or URL), <code>mime_type</code> (the type of media, e.g., image/jpeg), <code>created_at</code> and <code>updated_at</code> timestamps, and <code>attachment_type</code> that categorizes the media as "preview" or "main." Additionally, a media item can have multiple variants, making it adaptable for various use cases.</li>
<li><code>ProductMediaVariant</code>: This interface represents different variants or versions of a product's media. Each variant has its unique <code>id</code>, <code>variant_id</code> (relating it to a specific product variant), <code>product_media_id</code> (linking it to a particular media item), and timestamps for <code>created_at</code> and <code>updated_at</code>.</li>
<li><code>DigitalProduct</code>: It extends the standard <code>Product</code> type by introducing an array called <code>product_medias</code>. This array enables the association of media files with a digital product, allowing the presentation of images or other media related to the product. The <code>variants</code> property is tailored for digital products, adapting the generic <code>ProductVariant</code> to digital product-specific requirements.</li>
<li><code>DigitalProductVariant</code>: This type, an extension of <code>ProductVariant</code>, allows the linking of media files with a specific variant of a digital product. This is particularly valuable for showcasing different digital assets associated with each variant of the product.</li>
</ol>
<h2 id="heading-how-to-incorporate-e-book-previews-into-the-product-details">How to Incorporate e-Book Previews into the Product Details</h2>
<p>Now, let's move forward by adding e-book previews to our product detail page. To do this, we'll get the media previews linked to the currently selected product variant. </p>
<p>In the <code>src/lib/data/index.ts</code> file, we'll create a function to get these previews based on the chosen variant.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ... other imports</span>
<span class="hljs-keyword">import</span> { DigitalProduct, ProductMedia } <span class="hljs-keyword">from</span> <span class="hljs-string">"types/product-media"</span>

<span class="hljs-comment">// ... rest of the functions</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProductMediaPreviewByVariant</span>(<span class="hljs-params">
  variant: Variant
</span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">ProductMedia</span>&gt; </span>{
  <span class="hljs-keyword">const</span> { product_medias } = <span class="hljs-keyword">await</span> medusaRequest(<span class="hljs-string">"GET"</span>, <span class="hljs-string">`/product-media`</span>, {
    <span class="hljs-attr">query</span>: {
      <span class="hljs-attr">variant_ids</span>: variant.id,
      <span class="hljs-attr">expand</span>: [<span class="hljs-string">"variants"</span>],
    },
  })
    .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.body)
    .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
      <span class="hljs-keyword">throw</span> err
    })

  <span class="hljs-keyword">return</span> product_medias[<span class="hljs-number">0</span>]
}
</code></pre>
<p>This function is responsible for fetching information related to a specific product variant. It does this by making an HTTP request to the <code>/product-media</code> endpoint. It takes one argument, <code>variant</code>, which is expected to be of type <code>Variant</code>. The request includes query parameters specifying the <code>variant_ids</code> and requests additional details about related "variants". </p>
<p>The function awaits the response from the HTTP request and extracts the response body, which is assumed to be an array of product media objects. It then returns the first product media object from this array, presuming there is at least one such object. If an error occurs during the request, it catches the error and rethrows it.</p>
<h2 id="heading-how-to-offer-e-book-previews">How to Offer e-Book Previews</h2>
<p>To give customers a glimpse of the e-book's content, we'll provide a preview PDF with the first few pages. </p>
<p>To do this, we'll set up a Next API route to manage file downloads while keeping the file's location private. We'll also create a component for a straightforward "download free preview" button. If a product variant has preview media, it will be shown in the product-actions component.</p>
<p>You can use the newly created <code>DigitalProduct</code> and <code>DigitalProductVariant</code> types to fix any TypeScript errors that you may encounter.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { NextRequest, NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/server"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GET</span>(<span class="hljs-params">req: NextRequest</span>) </span>{
  <span class="hljs-comment">// Get the file info from the URL</span>
  <span class="hljs-keyword">const</span> { filepath, filename } = <span class="hljs-built_in">Object</span>.fromEntries(req.nextUrl.searchParams)

  <span class="hljs-comment">// Fetch the PDF file</span>
  <span class="hljs-keyword">const</span> pdfResponse = <span class="hljs-keyword">await</span> fetch(filepath)

  <span class="hljs-comment">// Handle the case where the PDF could not be fetched</span>
  <span class="hljs-keyword">if</span> (!pdfResponse.ok) <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> NextResponse(<span class="hljs-string">"PDF not found"</span>, { <span class="hljs-attr">status</span>: <span class="hljs-number">404</span> })

  <span class="hljs-comment">// Get the PDF content as a buffer</span>
  <span class="hljs-keyword">const</span> pdfBuffer = <span class="hljs-keyword">await</span> pdfResponse.arrayBuffer()

  <span class="hljs-comment">// Define response headers</span>
  <span class="hljs-keyword">const</span> headers = {
    <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/pdf"</span>,
    <span class="hljs-string">"Content-Disposition"</span>: <span class="hljs-string">`attachment; filename="<span class="hljs-subst">${filename}</span>"`</span>, <span class="hljs-comment">// This sets the file name for the download</span>
  }

  <span class="hljs-comment">// Create a NextResponse with the PDF content and headers</span>
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">new</span> NextResponse(pdfBuffer, {
    <span class="hljs-attr">status</span>: <span class="hljs-number">200</span>,
    headers,
  })

  <span class="hljs-keyword">return</span> response
}
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"@modules/common/components/button"</span>
<span class="hljs-keyword">import</span> { ProductMedia } <span class="hljs-keyword">from</span> <span class="hljs-string">"types/product-media"</span>

type Props = {
  <span class="hljs-attr">media</span>: ProductMedia
}

<span class="hljs-keyword">const</span> ProductMediaPreview: React.FC&lt;Props&gt; = <span class="hljs-function">(<span class="hljs-params">{ media }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> downloadPreview = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">window</span>.location.href = <span class="hljs-string">`<span class="hljs-subst">${process.env.NEXT_PUBLIC_BASE_URL}</span>/api/download/preview?filepath=<span class="hljs-subst">${media.file}</span>&amp;filename=<span class="hljs-subst">${media.name}</span>`</span>
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"secondary"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{downloadPreview}</span>&gt;</span>
        Download free preview
      <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ProductMediaPreview
</code></pre>
<p>The <code>GET</code> function is designed to handle incoming HTTP GET requests using the Next.js framework. It first extracts information from the request URL, specifically the <code>filepath</code> and <code>filename</code>, which are expected to be query parameters. It then attempts to fetch a PDF file from the specified <code>filepath</code>. If the PDF is successfully retrieved, it proceeds to convert the PDF content into a buffer.</p>
<p>In case the PDF retrieval fails, for instance, if the file is not found, it returns a response with a "PDF not found" message and a 404 status code, indicating a not found error.</p>
<p>If the PDF is successfully fetched, it defines response headers, specifying that the content type is "application/pdf" and setting the "Content-Disposition" header to control the behavior of file downloads. The <code>Content-Disposition</code> header is set to "attachment," and the <code>filename</code> parameter is used to suggest a filename for the downloaded PDF.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"@modules/common/components/button"</span>
<span class="hljs-keyword">import</span> { ProductMedia } <span class="hljs-keyword">from</span> <span class="hljs-string">"types/product-media"</span>

type Props = {
  <span class="hljs-attr">media</span>: ProductMedia
}

<span class="hljs-keyword">const</span> ProductMediaPreview: React.FC&lt;Props&gt; = <span class="hljs-function">(<span class="hljs-params">{ media }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> downloadPreview = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">window</span>.location.href = <span class="hljs-string">`<span class="hljs-subst">${process.env.NEXT_PUBLIC_BASE_URL}</span>/api/download/preview?filepath=<span class="hljs-subst">${media.file}</span>&amp;filename=<span class="hljs-subst">${media.name}</span>`</span>
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"secondary"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{downloadPreview}</span>&gt;</span>
        Download free preview
      <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ProductMediaPreview
</code></pre>
<p> The above component displays a preview of a product's media along with a button to download a free preview of that media. The component receives a prop named <code>media</code>, which is expected to be of type <code>ProductMedia</code>.</p>
<p>Inside the component, there's a <code>downloadPreview</code> function that's called when a user clicks the "Download free preview" button. This function constructs a URL for downloading the preview using the <code>window.location.href</code> property. It combines the base URL from the environment variable <code>NEXT_PUBLIC_BASE_URL</code> with the "/api/download/preview" route and includes query parameters for the file path and file name, which are extracted from the <code>media</code> prop.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ...other imports</span>
<span class="hljs-keyword">import</span> ProductMediaPreview <span class="hljs-keyword">from</span> <span class="hljs-string">"../product-media-preview"</span>
<span class="hljs-keyword">import</span> { getProductMediaPreviewByVariant } <span class="hljs-keyword">from</span> <span class="hljs-string">"@lib/data"</span>

<span class="hljs-keyword">const</span> ProductActions: React.FC&lt;ProductActionsProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ product }</span>) =&gt;</span> {
    <span class="hljs-comment">// ...other code</span>

  <span class="hljs-keyword">const</span> [productMedia, setProductMedia] = useState({} <span class="hljs-keyword">as</span> ProductMedia)

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> getProductMedia = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">if</span> (!variant) <span class="hljs-keyword">return</span>
      <span class="hljs-keyword">await</span> getProductMediaPreviewByVariant(variant).then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
        setProductMedia(res)
      })
    }
    getProductMedia()
  }, [variant])

  <span class="hljs-keyword">return</span> (
            <span class="hljs-comment">// ...other code</span>

      {productMedia &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ProductMediaPreview</span> <span class="hljs-attr">media</span>=<span class="hljs-string">{productMedia}</span> /&gt;</span></span>}

      &lt;Button onClick={addToCart}&gt;
        {!inStock ? <span class="hljs-string">"Out of stock"</span> : <span class="hljs-string">"Add to cart"</span>}
      &lt;/Button&gt;
    &lt;/div&gt;
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ProductActions
</code></pre>
<p>This component is responsible for displaying product-related actions, such as adding a product to the cart, and showing product media preview if available. It leverages asynchronous operations to fetch the media data based on the provided <code>variant</code>, making it a dynamic and interactive component.</p>
<h2 id="heading-how-to-adjust-the-product-and-shipping-details">How to Adjust the Product and Shipping Details</h2>
<p>Because product and shipping information differs between digital and physical products, we'll make changes to these sections on the product page as needed.</p>
<h3 id="heading-how-to-add-product-details">How to Add Product Details</h3>
<p>I've added product details to the e-book using the product's metadata section in the Medusa admin. Since we're not using the standard attributes, we'll enhance the <code>ProductInfoTab</code> component to display any additional metadata we include.</p>
<p>By default, metadata is structured as an object. To make it simpler to create our list of attributes, we'll change it into an array. </p>
<p>In this case, we'll feature four attributes from the metadata, splitting them into two columns. If you want to show a different number of attributes, you can easily adjust the values within the <code>slice()</code> function as needed.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ... other components</span>

<span class="hljs-keyword">const</span> ProductInfoTab = <span class="hljs-function">(<span class="hljs-params">{ product }: ProductTabsProps</span>) =&gt;</span> {
  <span class="hljs-comment">// map the metadata object to an array</span>
  <span class="hljs-keyword">const</span> metadata = useMemo(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!product.metadata) <span class="hljs-keyword">return</span> []
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.keys(product.metadata).map(<span class="hljs-function">(<span class="hljs-params">key</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> [key, product.metadata?.[key]]
    })
  }, [product])

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Tab.Panel</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-small-regular py-8"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid grid-cols-2 gap-x-8"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col gap-y-4"</span>&gt;</span>
                {/* Map the metadata as product information */}
          {metadata &amp;&amp;
            metadata.slice(0, 2).map(([key, value], i) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{i}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold"</span>&gt;</span>{key}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{value}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col gap-y-4"</span>&gt;</span>
          {metadata.length &gt; 2 &amp;&amp;
            metadata.slice(2, 4).map(([key, value], i) =&gt; {
              return (
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{i}</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold"</span>&gt;</span>{key}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{value}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              )
            })}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      {product.tags?.length ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold"</span>&gt;</span>Tags<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      ) : null}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Tab.Panel</span>&gt;</span></span>
  )
}

<span class="hljs-comment">// ... other components</span>
</code></pre>
<h3 id="heading-how-to-adjust-the-shipping-details">How to Adjust the Shipping Details</h3>
<p>Shipping information isn't relevant for digital products, so we'll change the content in this tab. You can make any necessary adjustments to the content within the <code>ShippingInfoTab</code> component in the same file to better match your store's requirements.</p>
<pre><code class="lang-jaavscript">// ... other components

const ProductTabs = ({ product }: ProductTabsProps) =&gt; {
  const tabs = useMemo(() =&gt; {
    return [
      {
        label: "Product Information",
        component: &lt;ProductInfoTab product={product} /&gt;,
      },
      {
        label: "E-book delivery",
        component: &lt;ShippingInfoTab /&gt;,
      },
    ]
  }, [product])
    // ... rest of code
}

// ... other components

const ShippingInfoTab = () =&gt; {
  return (
    &lt;Tab.Panel className="text-small-regular py-8"&gt;
      &lt;div className="grid grid-cols-1 gap-y-8"&gt;
        &lt;div className="flex items-start gap-x-2"&gt;
          &lt;FastDelivery /&gt;
          &lt;div&gt;
            &lt;span className="font-semibold"&gt;Instant delivery&lt;/span&gt;
            &lt;p className="max-w-sm"&gt;
              Your e-book will be delivered instantly via email. You can also
              download it from your account anytime.
            &lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div className="flex items-start gap-x-2"&gt;
          &lt;Refresh /&gt;
          &lt;div&gt;
            &lt;span className="font-semibold"&gt;Free previews&lt;/span&gt;
            &lt;p className="max-w-sm"&gt;
              Get a free preview of the e-book before you buy it. Just click the
              button above to download it.
            &lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/Tab.Panel&gt;
  )
}

// ... other components
</code></pre>
<p>The <code>ProductTabs</code> component is used for rendering a set of tabs. The component takes a <code>product</code> prop, and it uses the <code>useMemo</code> hook to create an array of tab objects. Each tab object consists of a label and a component to be displayed when that tab is active. </p>
<p>In the above snippet, there are two tabs: "Product Information" and "E-book delivery." The "Product Information" tab displays information about the product using the <code>ProductInfoTab</code> component, which we defined earlier. </p>
<p>The "E-book delivery" tab uses the <code>ShippingInfoTab</code> component to display information related to e-book delivery. Inside the <code>ShippingInfoTab</code> component, it provides details about the delivery process, mentioning instant delivery via email and the option to download from an account, as well as free e-book previews.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/10p0z2piqkpv60m4jgab.png" alt="Image" width="600" height="400" loading="lazy">
<em>Product Page</em></p>
<h2 id="heading-how-to-simplify-the-checkout">How to Simplify the Checkout</h2>
<p>Selling digital products doesn't require gathering customers' physical addresses. We only need their first name and email address to deliver the e-book, making the checkout process simpler by removing unnecessary input fields. </p>
<p>In this example, we'll keep only the first name, last name, country, and email fields, completely removing the billing address section. Keep in mind that your specific requirements may require different input fields.</p>
<p>To start, we'll adjust the checkout types and context by removing any references to values that are no longer needed.</p>
<pre><code class="lang-javascript"><span class="hljs-string">"use client"</span>

<span class="hljs-keyword">import</span> { medusaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@lib/config"</span>
<span class="hljs-keyword">import</span> useToggleState, { StateType } <span class="hljs-keyword">from</span> <span class="hljs-string">"@lib/hooks/use-toggle-state"</span>
<span class="hljs-keyword">import</span> { Cart, Customer, StorePostCartsCartReq } <span class="hljs-keyword">from</span> <span class="hljs-string">"@medusajs/medusa"</span>
<span class="hljs-keyword">import</span> Wrapper <span class="hljs-keyword">from</span> <span class="hljs-string">"@modules/checkout/components/payment-wrapper"</span>
<span class="hljs-keyword">import</span> { isEqual } <span class="hljs-keyword">from</span> <span class="hljs-string">"lodash"</span>
<span class="hljs-keyword">import</span> {
  formatAmount,
  useCart,
  useCartShippingOptions,
  useMeCustomer,
  useRegions,
  useSetPaymentSession,
  useUpdateCart,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"medusa-react"</span>
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/navigation"</span>
<span class="hljs-keyword">import</span> React, { createContext, useContext, useEffect, useMemo } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { FormProvider, useForm, useFormContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-hook-form"</span>
<span class="hljs-keyword">import</span> { useStore } <span class="hljs-keyword">from</span> <span class="hljs-string">"./store-context"</span>

type AddressValues = {
  <span class="hljs-attr">first_name</span>: string
  <span class="hljs-attr">last_name</span>: string
  <span class="hljs-attr">country_code</span>: string
}

<span class="hljs-keyword">export</span> type CheckoutFormValues = {
  <span class="hljs-attr">shipping_address</span>: AddressValues
  billing_address?: AddressValues
  <span class="hljs-attr">email</span>: string
}

interface CheckoutContext {
  cart?: Omit&lt;Cart, <span class="hljs-string">"refundable_amount"</span> | <span class="hljs-string">"refunded_total"</span>&gt;
  shippingMethods: { label?: string; value?: string; price: string }[]
  <span class="hljs-attr">isLoading</span>: boolean
  <span class="hljs-attr">readyToComplete</span>: boolean
  <span class="hljs-attr">sameAsBilling</span>: StateType
  <span class="hljs-attr">editAddresses</span>: StateType
  <span class="hljs-attr">initPayment</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-keyword">void</span>&gt;
  setAddresses: <span class="hljs-function">(<span class="hljs-params">addresses: CheckoutFormValues</span>) =&gt;</span> <span class="hljs-keyword">void</span>
  <span class="hljs-attr">setSavedAddress</span>: <span class="hljs-function">(<span class="hljs-params">address: AddressValues</span>) =&gt;</span> <span class="hljs-keyword">void</span>
  <span class="hljs-attr">setShippingOption</span>: <span class="hljs-function">(<span class="hljs-params">soId: string</span>) =&gt;</span> <span class="hljs-keyword">void</span>
  <span class="hljs-attr">setPaymentSession</span>: <span class="hljs-function">(<span class="hljs-params">providerId: string</span>) =&gt;</span> <span class="hljs-keyword">void</span>
  <span class="hljs-attr">onPaymentCompleted</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span>
}

<span class="hljs-keyword">const</span> CheckoutContext = createContext&lt;CheckoutContext | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>)
</code></pre>
<p>In the above snippet, you define TypeScript types for address values and the overall form structure. The <code>CheckoutContext</code> is also created to serve as a context for sharing checkout-related data and functions with other components.</p>
<pre><code class="lang-javascript">interface CheckoutProviderProps {
  children?: React.ReactNode
}

<span class="hljs-keyword">const</span> IDEMPOTENCY_KEY = <span class="hljs-string">"create_payment_session_key"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> CheckoutProvider = <span class="hljs-function">(<span class="hljs-params">{ children }: CheckoutProviderProps</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> {
    cart,
    setCart,
    <span class="hljs-attr">addShippingMethod</span>: {
      <span class="hljs-attr">mutate</span>: setShippingMethod,
      <span class="hljs-attr">isLoading</span>: addingShippingMethod,
    },
    <span class="hljs-attr">completeCheckout</span>: { <span class="hljs-attr">mutate</span>: complete, <span class="hljs-attr">isLoading</span>: completingCheckout },
  } = useCart()

  <span class="hljs-keyword">const</span> { customer } = useMeCustomer()
  <span class="hljs-keyword">const</span> { countryCode } = useStore()

  <span class="hljs-keyword">const</span> methods = useForm&lt;CheckoutFormValues&gt;({
    <span class="hljs-attr">defaultValues</span>: mapFormValues(customer, cart, countryCode),
    <span class="hljs-attr">reValidateMode</span>: <span class="hljs-string">"onChange"</span>,
  })
</code></pre>
<p>The <code>CheckoutProvider</code> component manages cart data, customer information, form handling, and interactions with payment and shipping methods. It sets up various hooks and functions for these purposes.</p>
<p>You also define an idempotency key which will be used for preventing duplicate requests during payment session creation.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> methods = useForm&lt;CheckoutFormValues&gt;({
    <span class="hljs-attr">defaultValues</span>: mapFormValues(customer, cart, countryCode),
    <span class="hljs-attr">reValidateMode</span>: <span class="hljs-string">"onChange"</span>,
  })

  <span class="hljs-keyword">const</span> {
    <span class="hljs-attr">mutate</span>: setPaymentSessionMutation,
    <span class="hljs-attr">isLoading</span>: settingPaymentSession,
  } = useSetPaymentSession(cart?.id!)

  <span class="hljs-keyword">const</span> { <span class="hljs-attr">mutate</span>: updateCart, <span class="hljs-attr">isLoading</span>: updatingCart } = useUpdateCart(
    cart?.id!
  )

  <span class="hljs-keyword">const</span> { shipping_options } = useCartShippingOptions(cart?.id!, {
    <span class="hljs-attr">enabled</span>: !!cart?.id,
  })

  <span class="hljs-keyword">const</span> { regions } = useRegions()

  <span class="hljs-keyword">const</span> { resetCart, setRegion } = useStore()
  <span class="hljs-keyword">const</span> { push } = useRouter()

  <span class="hljs-keyword">const</span> editAddresses = useToggleState()
  <span class="hljs-keyword">const</span> sameAsBilling = useToggleState(
    cart?.billing_address &amp;&amp; cart?.shipping_address
      ? isEqual(cart.billing_address, cart.shipping_address)
      : <span class="hljs-literal">true</span>
  )
</code></pre>
<p>In this section of code, several variables and hooks are initialized to facilitate the management of a checkout process. </p>
<p>We use the <code>methods</code> variable to manage the checkout form, with initial values populated by the <code>mapFormValues</code> function. The code also sets up mutation functions for updating the payment session and the cart (<code>setPaymentSessionMutation</code> and <code>updateCart</code>) and tracks their loading states. It retrieves available shipping options and regions using hooks, and it also handles cart resets and region selection. </p>
<p>It also employs boolean states (<code>editAddresses</code> and <code>sameAsBilling</code>) to manage whether the user is currently editing addresses and whether the billing address matches the shipping address. </p>
<p>These components collectively ensure smooth navigation and data management in the checkout process.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/**
   * Boolean that indicates if a part of the checkout is loading.
   */</span>
  <span class="hljs-keyword">const</span> isLoading = useMemo(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> (
      addingShippingMethod ||
      settingPaymentSession ||
      updatingCart ||
      completingCheckout
    )
  }, [
    addingShippingMethod,
    completingCheckout,
    settingPaymentSession,
    updatingCart,
  ])

  <span class="hljs-comment">/**
   * Boolean that indicates if the checkout is ready to be completed. A checkout is ready to be completed if
   * the user has supplied a email, shipping address, billing address, shipping method, and a method of payment.
   */</span>
  <span class="hljs-keyword">const</span> readyToComplete = useMemo(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> (
      !!cart &amp;&amp;
      !!cart.email &amp;&amp;
      !!cart.shipping_address &amp;&amp;
      !!cart.billing_address &amp;&amp;
      !!cart.payment_session &amp;&amp;
      cart.shipping_methods?.length &gt; <span class="hljs-number">0</span>
    )
  }, [cart])

  <span class="hljs-keyword">const</span> shippingMethods = useMemo(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (shipping_options &amp;&amp; cart?.region) {
      <span class="hljs-keyword">return</span> shipping_options?.map(<span class="hljs-function">(<span class="hljs-params">option</span>) =&gt;</span> ({
        <span class="hljs-attr">value</span>: option.id,
        <span class="hljs-attr">label</span>: option.name,
        <span class="hljs-attr">price</span>: formatAmount({
          <span class="hljs-attr">amount</span>: option.amount || <span class="hljs-number">0</span>,
          <span class="hljs-attr">region</span>: cart.region,
        }),
      }))
    }

    <span class="hljs-keyword">return</span> []
  }, [shipping_options, cart])
</code></pre>
<p>In the code above, first the <code>isLoading</code> boolean is computed using the <code>useMemo</code> hook. It reflects whether any part of the checkout is in a loading state. </p>
<p>This is determined by observing four loading flags: <code>addingShippingMethod</code>, <code>settingPaymentSession</code>, <code>updatingCart</code>, and <code>completingCheckout</code>. If any of these flags is <code>true</code>, the <code>isLoading</code> flag will also be <code>true</code>. This indicates that some part of the checkout is currently in progress.</p>
<p>The <code>readyToComplete</code> boolean, also computed with <code>useMemo</code>, assesses whether the checkout is prepared for completion. </p>
<p>To be deemed ready, several conditions must be met: there must be a valid <code>cart</code> object, an email address, a shipping address, a billing address, a payment session, and at least one shipping method selected. If all these conditions are satisfied, <code>readyToComplete</code> will be <code>true</code>, signaling that the checkout process is set to be finalized.</p>
<p>Finally, the <code>shippingMethods</code> variable is computed using <code>useMemo</code>. It is an array of available shipping methods with associated information. It maps the <code>shipping_options</code> (if they exist) to an array of objects, each containing a <code>value</code>, <code>label</code>, and <code>price</code>. </p>
<p>These objects represent the shipping options, their names, and prices, formatted using the <code>formatAmount</code> function. This data is used to display and select shipping methods during the checkout process.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/**
   * Resets the form when the cart changed.
   */</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (cart?.id) {
      methods.reset(mapFormValues(customer, cart, countryCode))
    }
  }, [customer, cart, methods, countryCode])

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!cart) {
      editAddresses.open()
      <span class="hljs-keyword">return</span>
    }

    <span class="hljs-keyword">if</span> (cart?.shipping_address &amp;&amp; cart?.billing_address) {
      editAddresses.close()
      <span class="hljs-keyword">return</span>
    }

    editAddresses.open()
    <span class="hljs-comment">// eslint-disable-next-line react-hooks/exhaustive-deps</span>
  }, [cart])

  <span class="hljs-comment">/**
   * Method to set the selected shipping method for the cart. This is called when the user selects a shipping method, such as UPS, FedEx, etc.
   */</span>
  <span class="hljs-keyword">const</span> setShippingOption = <span class="hljs-function">(<span class="hljs-params">soId: string</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (cart) {
      setShippingMethod(
        { <span class="hljs-attr">option_id</span>: soId },
        {
          <span class="hljs-attr">onSuccess</span>: <span class="hljs-function">(<span class="hljs-params">{ cart }</span>) =&gt;</span> setCart(cart),
        }
      )
    }
  }

  <span class="hljs-comment">/**
   * Method to create the payment sessions available for the cart. Uses a idempotency key to prevent duplicate requests.
   */</span>
  <span class="hljs-keyword">const</span> createPaymentSession = <span class="hljs-keyword">async</span> (cartId: string) =&gt; {
    <span class="hljs-keyword">return</span> medusaClient.carts
      .createPaymentSessions(cartId, {
        <span class="hljs-string">"Idempotency-Key"</span>: IDEMPOTENCY_KEY,
      })
      .then(<span class="hljs-function">(<span class="hljs-params">{ cart }</span>) =&gt;</span> cart)
      .catch(<span class="hljs-function">() =&gt;</span> <span class="hljs-literal">null</span>)
  }

  <span class="hljs-comment">/**
   * Method that calls the createPaymentSession method and updates the cart with the payment session.
   */</span>
  <span class="hljs-keyword">const</span> initPayment = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">if</span> (cart?.id &amp;&amp; !cart.payment_sessions?.length &amp;&amp; cart?.items?.length) {
      <span class="hljs-keyword">const</span> paymentSession = <span class="hljs-keyword">await</span> createPaymentSession(cart.id)

      <span class="hljs-keyword">if</span> (!paymentSession) {
        <span class="hljs-built_in">setTimeout</span>(initPayment, <span class="hljs-number">500</span>)
      } <span class="hljs-keyword">else</span> {
        setCart(paymentSession)
        <span class="hljs-keyword">return</span>
      }
    }
  }

  <span class="hljs-comment">/**
   * Method to set the selected payment session for the cart. This is called when the user selects a payment provider, such as Stripe, PayPal, etc.
   */</span>
  <span class="hljs-keyword">const</span> setPaymentSession = <span class="hljs-function">(<span class="hljs-params">providerId: string</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (cart) {
      setPaymentSessionMutation(
        {
          <span class="hljs-attr">provider_id</span>: providerId,
        },
        {
          <span class="hljs-attr">onSuccess</span>: <span class="hljs-function">(<span class="hljs-params">{ cart }</span>) =&gt;</span> {
            setCart(cart)
          },
        }
      )
    }
  }

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

    <span class="hljs-keyword">if</span> (shippingMethods?.length &amp;&amp; shippingMethods?.[<span class="hljs-number">0</span>]?.value) {
      setShippingOption(shippingMethods[<span class="hljs-number">0</span>].value)
    }
  }

  <span class="hljs-keyword">const</span> setSavedAddress = <span class="hljs-function">(<span class="hljs-params">address: AddressValues</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> setValue = methods.setValue

    setValue(<span class="hljs-string">"shipping_address"</span>, {
      <span class="hljs-attr">country_code</span>: address.country_code || <span class="hljs-string">""</span>,
      <span class="hljs-attr">first_name</span>: address.first_name || <span class="hljs-string">""</span>,
      <span class="hljs-attr">last_name</span>: address.last_name || <span class="hljs-string">""</span>,
    })
  }

  <span class="hljs-comment">/**
   * Method that validates if the cart's region matches the shipping address's region. If not, it will update the cart region.
   */</span>
  <span class="hljs-keyword">const</span> validateRegion = <span class="hljs-function">(<span class="hljs-params">countryCode: string</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (regions &amp;&amp; cart) {
      <span class="hljs-keyword">const</span> region = regions.find(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span>
        r.countries.map(<span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> c.iso_2).includes(countryCode)
      )

      <span class="hljs-keyword">if</span> (region &amp;&amp; region.id !== cart.region.id) {
        setRegion(region.id, countryCode)
      }
    }
  }

  <span class="hljs-comment">/**
   * Method that sets the addresses and email on the cart.
   */</span>
  <span class="hljs-keyword">const</span> setAddresses = <span class="hljs-function">(<span class="hljs-params">data: CheckoutFormValues</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { shipping_address, billing_address, email } = data

    <span class="hljs-keyword">const</span> payload: StorePostCartsCartReq = {
      shipping_address,
      email,
    }

    <span class="hljs-keyword">if</span> (isEqual(shipping_address, billing_address)) {
      sameAsBilling.open()
    }

    <span class="hljs-keyword">if</span> (sameAsBilling.state) {
      payload.billing_address = shipping_address
    } <span class="hljs-keyword">else</span> {
      payload.billing_address = billing_address
    }

    updateCart(payload, {
      <span class="hljs-attr">onSuccess</span>: <span class="hljs-function">(<span class="hljs-params">{ cart }</span>) =&gt;</span> {
        setCart(cart)
        prepareFinalSteps()
      },
    })
  }

  <span class="hljs-comment">/**
   * Method to complete the checkout process. This is called when the user clicks the "Complete Checkout" button.
   */</span>
  <span class="hljs-keyword">const</span> onPaymentCompleted = <span class="hljs-function">() =&gt;</span> {
    complete(<span class="hljs-literal">undefined</span>, {
      <span class="hljs-attr">onSuccess</span>: <span class="hljs-function">(<span class="hljs-params">{ data }</span>) =&gt;</span> {
        resetCart()
        push(<span class="hljs-string">`/order/confirmed/<span class="hljs-subst">${data.id}</span>`</span>)
      },
    })
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FormProvider</span> {<span class="hljs-attr">...methods</span>}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">CheckoutContext.Provider</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
          <span class="hljs-attr">cart</span>,
          <span class="hljs-attr">shippingMethods</span>,
          <span class="hljs-attr">isLoading</span>,
          <span class="hljs-attr">readyToComplete</span>,
          <span class="hljs-attr">sameAsBilling</span>,
          <span class="hljs-attr">editAddresses</span>,
          <span class="hljs-attr">initPayment</span>,
          <span class="hljs-attr">setAddresses</span>,
          <span class="hljs-attr">setSavedAddress</span>,
          <span class="hljs-attr">setShippingOption</span>,
          <span class="hljs-attr">setPaymentSession</span>,
          <span class="hljs-attr">onPaymentCompleted</span>,
        }}
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Wrapper</span> <span class="hljs-attr">paymentSession</span>=<span class="hljs-string">{cart?.payment_session}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">Wrapper</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">CheckoutContext.Provider</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">FormProvider</span>&gt;</span></span>
  )
}
</code></pre>
<p>This code section orchestrates various aspects of an e-commerce checkout process. It manages form state, resets the form when the cart changes, and toggles address editing visibility. It handles the selection of shipping methods, the creation and initialization of payment sessions, and the choice of payment providers. And it ensures that shipping addresses, billing addresses, and email information are set appropriately, and validates the cart's region based on the shipping address. </p>
<p>It also coordinates the completion of the checkout process, including payment processing and order confirmation. </p>
<p>All of these functions and data are encapsulated within the <code>CheckoutProvider</code> component.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useCheckout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> context = useContext(CheckoutContext)
  <span class="hljs-keyword">const</span> form = useFormContext&lt;CheckoutFormValues&gt;()
  <span class="hljs-keyword">if</span> (context === <span class="hljs-literal">null</span>) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(
      <span class="hljs-string">"useProductActionContext must be used within a ProductActionProvider"</span>
    )
  }
  <span class="hljs-keyword">return</span> { ...context, ...form }
}

<span class="hljs-comment">/**
 * Method to map the fields of a potential customer and the cart to the checkout form values. Information is assigned with the following priority:
 * 1. Cart information
 * 2. Customer information
 * 3. Default values - null
 */</span>
<span class="hljs-keyword">const</span> mapFormValues = (
  customer?: Omit&lt;Customer, <span class="hljs-string">"password_hash"</span>&gt;,
  cart?: Omit&lt;Cart, <span class="hljs-string">"refundable_amount"</span> | <span class="hljs-string">"refunded_total"</span>&gt;,
  currentCountry?: string
): <span class="hljs-function"><span class="hljs-params">CheckoutFormValues</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> customerShippingAddress = customer?.shipping_addresses?.[<span class="hljs-number">0</span>]
  <span class="hljs-keyword">const</span> customerBillingAddress = customer?.billing_address

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">shipping_address</span>: {
      <span class="hljs-attr">first_name</span>:
        cart?.shipping_address?.first_name ||
        customerShippingAddress?.first_name ||
        <span class="hljs-string">""</span>,
      <span class="hljs-attr">last_name</span>:
        cart?.shipping_address?.last_name ||
        customerShippingAddress?.last_name ||
        <span class="hljs-string">""</span>,
      <span class="hljs-attr">country_code</span>:
        currentCountry ||
        cart?.shipping_address?.country_code ||
        customerShippingAddress?.country_code ||
        <span class="hljs-string">""</span>,
    },
    <span class="hljs-attr">billing_address</span>: {
      <span class="hljs-attr">first_name</span>:
        cart?.billing_address?.first_name ||
        customerBillingAddress?.first_name ||
        <span class="hljs-string">""</span>,
      <span class="hljs-attr">last_name</span>:
        cart?.billing_address?.last_name ||
        customerBillingAddress?.last_name ||
        <span class="hljs-string">""</span>,
      <span class="hljs-attr">country_code</span>:
        cart?.shipping_address?.country_code ||
        customerBillingAddress?.country_code ||
        <span class="hljs-string">""</span>,
    },
    <span class="hljs-attr">email</span>: cart?.email || customer?.email || <span class="hljs-string">""</span>,
  }
}
</code></pre>
<p>The <code>useCheckout</code> hook is used to access the checkout context and form context, typically used in React components. It retrieves the <code>CheckoutContext</code> from the context of the application, and it also gets the form context of the checkout form, allowing components to access and utilize these contexts.</p>
<p>The <code>mapFormValues</code> function is responsible for mapping and prioritizing information for the checkout form. It takes customer and cart data, along with the current country, and generates values for the checkout form fields. </p>
<p>It prioritizes data in this order: 1) Cart information, 2) Customer information, and 3) Default values set to null if no information is available. This function helps populate the checkout form with the most relevant data, ensuring a smoother user experience during the checkout process.</p>
<p>Now that the context is updated, we’ll remove the redundant input fields from the checkout form.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useCheckout } <span class="hljs-keyword">from</span> <span class="hljs-string">"@lib/context/checkout-context"</span>
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"@modules/common/components/button"</span>
<span class="hljs-keyword">import</span> Spinner <span class="hljs-keyword">from</span> <span class="hljs-string">"@modules/common/icons/spinner"</span>
<span class="hljs-keyword">import</span> ShippingAddress <span class="hljs-keyword">from</span> <span class="hljs-string">"../shipping-address"</span>

<span class="hljs-keyword">const</span> Addresses = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> {
    <span class="hljs-attr">editAddresses</span>: { <span class="hljs-attr">state</span>: isEdit, <span class="hljs-attr">toggle</span>: setEdit },
    setAddresses,
    handleSubmit,
    cart,
  } = useCheckout()
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl-semi flex items-center gap-x-4 px-8 pb-6 pt-8"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-gray-900 w-8 h-8 rounded-full text-white flex justify-center items-center text-sm"</span>&gt;</span>
          1
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Shipping address<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      {isEdit ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-8 pb-8"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ShippingAddress</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-[200px] mt-6"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSubmit(setAddresses)}</span>
          &gt;</span>
            Continue to delivery
          <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-gray-50 px-8 py-6 text-small-regular"</span>&gt;</span>
            {cart &amp;&amp; cart.shipping_address ? (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-start gap-x-8"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-green-400 rounded-full min-w-[24px] h-6 flex items-center justify-center text-white text-small-regular"</span>&gt;</span>
                  ✓
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-start justify-between w-full"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
                      {cart.shipping_address.first_name}{" "}
                      {cart.shipping_address.last_name}
                      {cart.shipping_address.country}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4 flex flex-col"</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{cart.email}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{setEdit}</span>&gt;</span>Edit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            ) : (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">""</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Spinner</span> /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            )}
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Addresses
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/t1osg7g86bmd4s8qugdf.png" alt="Image" width="600" height="400" loading="lazy">
<em>Checkout Page</em></p>
<p>In the last step, we'll modify the <code>shipping-details</code> component to show important information after the order is successfully placed. In this situation, we'll remove any extra details and add the buyer's email address for reference.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Address, ShippingMethod } <span class="hljs-keyword">from</span> <span class="hljs-string">"@medusajs/medusa"</span>

type ShippingDetailsProps = {
  <span class="hljs-attr">address</span>: Address
  <span class="hljs-attr">shippingMethods</span>: ShippingMethod[]
  <span class="hljs-attr">email</span>: string
}

<span class="hljs-keyword">const</span> ShippingDetails = <span class="hljs-function">(<span class="hljs-params">{
  address,
  shippingMethods,
  email,
}: ShippingDetailsProps</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-base-regular"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-base-semi"</span>&gt;</span>Delivery<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"my-2"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-small-regular text-gray-700"</span>&gt;</span>Details<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{`${address.first_name} ${address.last_name}`}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{email}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"my-2"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-small-regular text-gray-700"</span>&gt;</span>Delivery method<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          {shippingMethods.map((sm) =&gt; {
            return <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{sm.id}</span>&gt;</span>{sm.shipping_option.name}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          })}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ShippingDetails
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/io66rfgqkr88i1wcojj9.png" alt="Image" width="600" height="400" loading="lazy">
<em>Order Confirmation Page</em></p>
<h2 id="heading-how-to-deliver-digital-products">How to Deliver Digital Products</h2>
<p>There are various ways to get digital products to customers, like sending a download link by email, adding a download button on the order confirmation page, or giving access through their account.</p>
<p>In all these situations, our main goal is to confirm that only those who've purchased the product can get it. </p>
<p>To do this, I've set up the backend to create a special code (token) for each digital item in an order. We can use GET <code>/store/:token</code> to check the token and give the file to the user. But this method shows the file's web address to the user, which isn't great for preventing piracy. </p>
<p>So we are going to make a Next API route at <code>src/app/api/download/main/[token]/route.ts</code>. This route will handle the token, acting as a middleman to provide the file to the user without revealing where it's stored.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { NextRequest, NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/server"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GET</span>(<span class="hljs-params">
  req: NextRequest,
  { params }: { params: Record&lt;string, any&gt; }
</span>) </span>{
  <span class="hljs-comment">// Get the token from the URL</span>
  <span class="hljs-keyword">const</span> { token } = params

  <span class="hljs-comment">// Define the URL to fetch the PDF file data from</span>
  <span class="hljs-keyword">const</span> pdfUrl = <span class="hljs-string">`<span class="hljs-subst">${process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL}</span>/store/product-media/<span class="hljs-subst">${token}</span>`</span>

  <span class="hljs-comment">// Fetch the PDF file data</span>
  <span class="hljs-keyword">const</span> { file, filename } = <span class="hljs-keyword">await</span> fetch(pdfUrl).then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json())

  <span class="hljs-comment">// Handle the case where the token is invalid</span>
  <span class="hljs-keyword">if</span> (!file) <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> NextResponse(<span class="hljs-string">"Invalid token"</span>, { <span class="hljs-attr">status</span>: <span class="hljs-number">401</span> })

  <span class="hljs-comment">// Fetch the PDF file</span>
  <span class="hljs-keyword">const</span> pdfResponse = <span class="hljs-keyword">await</span> fetch(file)

  <span class="hljs-comment">// Handle the case where the PDF could not be fetched</span>
  <span class="hljs-keyword">if</span> (!pdfResponse.ok) <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> NextResponse(<span class="hljs-string">"PDF not found"</span>, { <span class="hljs-attr">status</span>: <span class="hljs-number">404</span> })

  <span class="hljs-comment">// Get the PDF content as a buffer</span>
  <span class="hljs-keyword">const</span> pdfBuffer = <span class="hljs-keyword">await</span> pdfResponse.arrayBuffer()

  <span class="hljs-comment">// Define response headers</span>
  <span class="hljs-keyword">const</span> headers = {
    <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/pdf"</span>,
    <span class="hljs-string">"Content-Disposition"</span>: <span class="hljs-string">`attachment; filename="<span class="hljs-subst">${filename}</span>"`</span>, <span class="hljs-comment">// This sets the file name for the download</span>
  }

  <span class="hljs-comment">// Create a NextResponse with the PDF content and headers</span>
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">new</span> NextResponse(pdfBuffer, {
    <span class="hljs-attr">status</span>: <span class="hljs-number">200</span>,
    headers,
  })

  <span class="hljs-keyword">return</span> response
}
</code></pre>
<p>This code defines a serverless function for handling HTTP GET requests in a Next.js application. It retrieves a PDF file using a token provided in the URL parameters, fetching the file from an external source. The function ensures the token's validity and the availability of the PDF file. If the token is invalid, it returns a "401 Unauthorized" response. If the PDF is not found, it returns a "404 Not Found" response. </p>
<p>When the PDF is successfully fetched, it constructs response headers, including the content type as "application/pdf" and a suggested filename for download, and returns the PDF file to the client as a downloadable attachment. This code is typically used to serve PDF files in response to specific GET requests.</p>
<p>We can now link to this API route from the delivery email like this: <code>{your_store_url}/api/download/main/{token}</code>.</p>
<p>You can add your own logic to invalidate tokens after a certain time or X number of downloads.</p>
<h2 id="heading-mission-accomplished"><strong>Mission Accomplished!</strong></h2>
<p>Congratulations, you've made it! Don't forget to explore more <a target="_blank" href="https://docs.medusajs.com/recipes">Recipes</a> for further ways to make the most of Medusa.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the JSON Module in Python – A Beginner's Guide ]]>
                </title>
                <description>
                    <![CDATA[ JSON (JavaScript Object Notation) is a popular, lightweight data interchange standard. It represents data structures made up of key-value pairs that's quite straightforward and human-readable.  JSON has become the industry standard for data interchan... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-the-json-module-in-python/</link>
                <guid isPermaLink="false">66ba0ea7d14c87384322b695</guid>
                
                    <category>
                        <![CDATA[ json ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 05 Jun 2023 22:51:24 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/json-module.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>JSON (JavaScript Object Notation) is a popular, lightweight data interchange standard. It represents data structures made up of key-value pairs that's quite straightforward and human-readable. </p>
<p>JSON has become the industry standard for data interchange between online services. And it's widely utilized in modern programming languages, including Python.</p>
<p>JSON data is frequently expressed as nested dictionaries, lists, and scalar values such as texts, numbers, booleans, and null. It is named JSON because it closely mimics the syntax used in JavaScript objects.</p>
<p>In this tutorial, you will explore the JSON module in Python and learn how to effectively work with JSON data.</p>
<h2 id="heading-pythons-built-in-json-module">Python's Built-in JSON Module</h2>
<p>JSON plays an important role in Python programming because it allows efficient data serialization and deserialization. It enables Python programs to effortlessly communicate with web services, exchange data, and store structured information. </p>
<p>Developers can use JSON to seamlessly link their Python programs with a variety of APIs, databases, and external systems that use JSON for data representation.</p>
<p>If you're looking to learn how to interact with web services using Python, check out <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-interact-with-web-services-using-python">my tutorial on the requests module</a>.</p>
<p>The built-in JSON module in Python provides a powerful set of methods and classes that make working with JSON data simple. Developers can use it to encode Python objects into JSON strings and decode JSON strings back into Python objects.</p>
<h2 id="heading-how-to-store-json-data-in-a-file">How to Store JSON Data in a File</h2>
<p>When working with JSON data in Python, you'll often need to save the data or share it with others. Storing JSON data in a file enables quick retrieval and data persistence. </p>
<p>In this section, you'll learn how to use Python's <code>json.dump()</code> function to save JSON data to a file. This process involves serializing the JSON data and saving it to a file, which you can subsequently read and use as needed.</p>
<h3 id="heading-the-jsondump-function">The <code>json.dump()</code> function</h3>
<p>The <code>json.dump()</code> function in Python allows you to store JSON data directly into a file. This function takes two parameters: the data to be serialized and the file object where the data will be written.</p>
<p>To write JSON data to a file, you need to follow a few steps. First, you need to open a file in write mode, specifying the file path. Then, you can use the <code>json.dump()</code> function to serialize the data and write it to the file. Finally, you need to close the file to ensure that all the data is properly saved.</p>
<p>Let's learn how to store data in a file using the horoscope API response as an example.</p>
<p>Assume you have made a GET request to the following URL: <a target="_blank" href="https://horoscope-app-api.vercel.app/api/v1/get-horoscope/daily?sign=capricorn&amp;day=today">https://horoscope-app-api.vercel.app/api/v1/get-horoscope/daily?sign=capricorn&amp;day=today</a>, which provides the daily horoscope for the Capricorn sign.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> json

<span class="hljs-comment"># Make the GET request to the horoscope API</span>
response = requests.get(<span class="hljs-string">"https://horoscope-app-api.vercel.app/api/v1/get-horoscope/daily?sign=capricorn&amp;day=today"</span>)
data = response.json()  <span class="hljs-comment"># Convert the response to JSON</span>

<span class="hljs-comment"># Store the JSON data in a file</span>
<span class="hljs-keyword">with</span> open(<span class="hljs-string">"horoscope_data.json"</span>, <span class="hljs-string">"w"</span>) <span class="hljs-keyword">as</span> file:
    json.dump(data, file)

print(<span class="hljs-string">"Data stored successfully!"</span>)
</code></pre>
<p>In the code above, you use the <code>requests</code> library to make a GET request to the <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-create-a-horoscope-api-with-beautiful-soup-and-flask">Horoscope API</a>. You then extract the JSON data from the response using the <code>.json()</code> method. Finally, you open a file named <code>horoscope_data.json</code> in write mode using the <code>with</code> statement, and you use <code>json.dump()</code> to store the data in the file.</p>
<p>Check out <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-know-your-horoscope-using-python">this tutorial</a> to learn how to find out your horoscope using Python.</p>
<p>If you open the <code>horoscope_data.json</code> file, you'll see contents similar to below:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"data"</span>: {
    <span class="hljs-attr">"date"</span>: <span class="hljs-string">"Jun 3, 2023"</span>,
    <span class="hljs-attr">"horoscope_data"</span>: <span class="hljs-string">"The forecast today is stormy. You may have sensed that there was some tension clouding the conversation at home. Resentments were left unsaid and subtle power games were played without resolution. Today, Capricorn, it all becomes too unbearable for you. Regardless of the risks involved, you will take measures to clear things up."</span>
  },
  <span class="hljs-attr">"status"</span>: <span class="hljs-number">200</span>,
  <span class="hljs-attr">"success"</span>: <span class="hljs-literal">true</span>
}
</code></pre>
<h2 id="heading-how-to-retrieve-data-from-a-json-file">How to Retrieve Data from a JSON File</h2>
<p>You'll often need to read data from a JSON file. For example, you may need to read configuration settings from a JSON file. Python's JSON module provides the <code>json.load()</code> function, which allows you to read and deserialize JSON data from a file. </p>
<p>In this section, you will learn how to use the <code>json.load()</code> function to retrieve JSON data from a file and work with it in your Python programs.</p>
<h3 id="heading-the-jsonload-function">The <code>json.load()</code> function</h3>
<p>The <code>json.load()</code> function accepts a file object as an argument and returns deserialized JSON data in the form of Python objects such as dictionaries, lists, strings, numbers, booleans, and null values.</p>
<p>To read JSON data from a file, you need to open the file in read mode, extract the data using the <code>json.load()</code> function, and store it in a variable for further processing. It's important to ensure that the file being read contains valid JSON data – otherwise, it may raise an exception.</p>
<p>Let's see how you can retrieve the data from the previously created <code>horoscope_data.json</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json

<span class="hljs-comment"># Retrieve JSON data from the file</span>
<span class="hljs-keyword">with</span> open(<span class="hljs-string">"horoscope_data.json"</span>, <span class="hljs-string">"r"</span>) <span class="hljs-keyword">as</span> file:
    data = json.load(file)

<span class="hljs-comment"># Access and process the retrieved JSON data</span>
date = data[<span class="hljs-string">"data"</span>][<span class="hljs-string">"date"</span>]
horoscope_data = data[<span class="hljs-string">"data"</span>][<span class="hljs-string">"horoscope_data"</span>]

<span class="hljs-comment"># Print the retrieved data</span>
print(<span class="hljs-string">f"Horoscope for date <span class="hljs-subst">{date}</span>: <span class="hljs-subst">{horoscope_data}</span>"</span>)
</code></pre>
<p>In the code above, you open the file <code>horoscope_data.json</code> in read mode using the <code>with</code> statement. You then use the <code>json.load()</code> function to deserialize the JSON data from the file into the data variable. Finally, you access specific fields of the JSON data (e.g., "date" and "horoscope_data") and process them as needed.</p>
<h2 id="heading-how-to-format-the-json-output">How to Format the JSON Output</h2>
<p>When you read data from a JSON file and print it, the output is displayed as a single line, which may not resemble the structured format of JSON.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json

<span class="hljs-comment"># Retrieve JSON data from the file</span>
<span class="hljs-keyword">with</span> open(<span class="hljs-string">"horoscope_data.json"</span>, <span class="hljs-string">"r"</span>) <span class="hljs-keyword">as</span> file:
    data = json.load(file)

print(data)
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">{<span class="hljs-string">'data'</span>: {<span class="hljs-string">'date'</span>: <span class="hljs-string">'Jun 3, 2023'</span>, <span class="hljs-string">'horoscope_data'</span>: <span class="hljs-string">'The forecast today is stormy. You may have sensed that there was some tension clouding the conversation at home. Resentments were left unsaid and subtle power games were played without resolution. Today, Capricorn, it all becomes too unbearable for you. Regardless of the risks involved, you will take measures to clear things up.'</span>}, <span class="hljs-string">'status'</span>: 200, <span class="hljs-string">'success'</span>: True}
</code></pre>
<h3 id="heading-the-jsondumps-function">The <code>json.dumps()</code> function</h3>
<p>The JSON module provides you with a <code>json.dumps()</code> function to serialize Python objects into a JSON formatted string. It provides various options for customization, including formatting the output to make it more human-readable.</p>
<p>The <code>json.dumps()</code> function provides several <a target="_blank" href="https://docs.python.org/3/library/json.html#json.dumps">options</a> to customize the output. The most commonly used is the <code>indent</code> which allows you to specify the number of spaces used for indentation.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json

<span class="hljs-comment"># Retrieve JSON data from the file</span>
<span class="hljs-keyword">with</span> open(<span class="hljs-string">"horoscope_data.json"</span>, <span class="hljs-string">"r"</span>) <span class="hljs-keyword">as</span> file:
    data = json.load(file)

<span class="hljs-comment"># Format the data</span>
formatted_data = json.dumps(data, indent=<span class="hljs-number">2</span>)

print(formatted_data)
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">{
  <span class="hljs-string">"data"</span>: {
    <span class="hljs-string">"date"</span>: <span class="hljs-string">"Jun 3, 2023"</span>,
    <span class="hljs-string">"horoscope_data"</span>: <span class="hljs-string">"The forecast today is stormy. You may have sensed that there was some tension clouding the conversation at home. Resentments were left unsaid and subtle power games were played without resolution. Today, Capricorn, it all becomes too unbearable for you. Regardless of the risks involved, you will take measures to clear things up."</span>
  },
  <span class="hljs-string">"status"</span>: 200,
  <span class="hljs-string">"success"</span>: <span class="hljs-literal">true</span>
}
</code></pre>
<p>As you can see, the JSON data is now formatted with proper indentation, enhancing its readability. This technique can be applied to any JSON data, allowing you to present JSON output in a more organized and visually appealing way.</p>
<h2 id="heading-the-jsontool-command-line-tool">The <code>json.tool</code> Command Line Tool</h2>
<p>Python's JSON module provides a convenient command line tool called <code>json.tool</code> that allows you to format and pretty-print JSON data directly from the command line. It is a useful utility for quickly visualizing the structure and contents of JSON data in a more readable and organized format.</p>
<p>To use <code>json.tool</code>, you can execute the following command in your command-line interface:</p>
<pre><code class="lang-bash">python -m json.tool &lt;input_file&gt; &lt;output_file&gt;
</code></pre>
<p>where:</p>
<ul>
<li><code>python -m json.tool</code> invokes the <code>json.tool</code> module using the Python interpreter.</li>
<li><code>&lt;input_file&gt;</code> represents the path to the JSON file you want to format.</li>
<li><code>&lt;output_file&gt;</code> is an optional argument that specifies the file to which you want to save the formatted JSON output. If not provided, the formatted output will be displayed on the console.</li>
</ul>
<p>Let's say you have a <code>horoscope_data.json</code> file with the following contents:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"data"</span>: {
    <span class="hljs-attr">"date"</span>: <span class="hljs-string">"Jun 3, 2023"</span>,
    <span class="hljs-attr">"horoscope_data"</span>: <span class="hljs-string">"The forecast today is stormy. You may have sensed that there was some tension clouding the conversation at home. Resentments were left unsaid and subtle power games were played without resolution. Today, Capricorn, it all becomes too unbearable for you. Regardless of the risks involved, you will take measures to clear things up."</span>
  },
  <span class="hljs-attr">"status"</span>: <span class="hljs-number">200</span>,
  <span class="hljs-attr">"success"</span>: <span class="hljs-literal">true</span>
}
</code></pre>
<p>Notice that the above JSON file has an indentation of two spaces.</p>
<p>To pretty-print this JSON file using <code>json.tool</code>, you can execute the following command:</p>
<pre><code class="lang-bash">python -m json.tool horoscope_data.json
</code></pre>
<p>The output will be:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"data"</span>: {
        <span class="hljs-attr">"date"</span>: <span class="hljs-string">"Jun 3, 2023"</span>,
        <span class="hljs-attr">"horoscope_data"</span>: <span class="hljs-string">"The forecast today is stormy. You may have sensed that there was some tension clouding the conversation at home. Resentments were left unsaid and subtle power games were played without resolution. Today, Capricorn, it all becomes too unbearable for you. Regardless of the risks involved, you will take measures to clear things up."</span>
    },
    <span class="hljs-attr">"status"</span>: <span class="hljs-number">200</span>,
    <span class="hljs-attr">"success"</span>: <span class="hljs-literal">true</span>
}
</code></pre>
<p>As you can see in the example, executing the <code>json.tool</code> module with the input file path formats the JSON data and displays the formatted output on the console.</p>
<p>You can also redirect the formatted output to an output file by specifying the output file name as the second argument:</p>
<pre><code class="lang-bash">python -m json.tool horoscope_data.json formatted_data.json
</code></pre>
<p>This command formats the JSON data from <code>horoscope_data.json</code> and saves the formatted output to <code>formatted_data.json</code>.</p>
<h2 id="heading-json-encoding-custom-objects">JSON Encoding Custom Objects</h2>
<p>The JSON module in Python allows you to encode and decode custom objects by using JSON encoder and decoder classes. You can define custom serialization and deserialization logic for your objects using these classes.</p>
<p><code>JSONEncoder</code> class allows you to customize the encoding process. To define how your custom object should be encoded into JSON format, you can extend the <code>JSONEncoder</code> and change its <code>default</code> method.</p>
<p>Here's an example of how you can extend the <code>JSONEncoder</code> class and customize the encoding process for a custom object:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name, age</span>):</span>
        self.name = name
        self.age = age


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PersonEncoder</span>(<span class="hljs-params">json.JSONEncoder</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">default</span>(<span class="hljs-params">self, obj</span>):</span>
        <span class="hljs-keyword">if</span> isinstance(obj, Person):
            <span class="hljs-keyword">return</span> {<span class="hljs-string">"name"</span>: obj.name, <span class="hljs-string">"age"</span>: obj.age}
        <span class="hljs-keyword">return</span> super().default(obj)


<span class="hljs-comment"># Create a custom object</span>
person = Person(<span class="hljs-string">"Ashutosh Krishna"</span>, <span class="hljs-number">23</span>)

<span class="hljs-comment"># Encode the custom object using the custom encoder</span>
json_str = json.dumps(person, cls=PersonEncoder)

<span class="hljs-comment"># Print the encoded JSON string</span>
print(json_str)
</code></pre>
<p>In this example, you define a custom class <code>Person</code> with <code>name</code> and <code>age</code> attributes. You then create a subclass of <code>JSONEncoder</code> called <code>PersonEncoder</code> and override its <code>default</code> method. Within the <code>default</code> method, you check if the object being encoded is an instance of <code>Person</code>. If it is, you provide a JSON-serializable representation of the object by returning a dictionary containing the <code>name</code> and <code>age</code> attributes. If the object is not of type <code>Person</code>, you call the <code>default</code> method of the superclass to handle other types.</p>
<p>By using <code>json.dumps</code> and specifying the <code>cls</code> parameter as your custom encoder class <code>PersonEncoder</code>, you can encode the <code>person</code> object into a JSON string. The output will be:</p>
<pre><code class="lang-bash">{<span class="hljs-string">"name"</span>: <span class="hljs-string">"Ashutosh Krishna"</span>, <span class="hljs-string">"age"</span>: 23}
</code></pre>
<p>Similarly, you can specify custom decoding logic in the JSON decoder class, <code>JSONDecoder</code>. To define how JSON data should be decoded into your custom object, extend the <code>JSONDecoder</code> and override its <code>object_hook</code> function.</p>
<h2 id="heading-how-to-create-json-from-a-python-dictionary">How to Create JSON from a Python Dictionary</h2>
<p>You can use the <code>json.dumps()</code> function provided by the JSON module to create JSON from a <a target="_blank" href="https://blog.ashutoshkrris.in/everything-you-need-to-know-about-python-dictionaries">Python dictionary</a>. This function takes a Python object, typically a dictionary, and converts it into a JSON string representation.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json

<span class="hljs-comment"># Python dictionary</span>
data = {
    <span class="hljs-string">"name"</span>: <span class="hljs-string">"Ashutosh Krishna"</span>,
    <span class="hljs-string">"age"</span>: <span class="hljs-number">23</span>,
    <span class="hljs-string">"email"</span>: <span class="hljs-string">"ashutosh@example.com"</span>
}

<span class="hljs-comment"># Convert dictionary to JSON string</span>
json_str = json.dumps(data)

<span class="hljs-comment"># Print the JSON string</span>
print(json_str)
</code></pre>
<p>In this example, you have a Python dictionary <code>data</code> representing some data. By calling <code>json.dumps(data)</code>, you convert the dictionary into a JSON string. The output will be:</p>
<pre><code class="lang-bash">{<span class="hljs-string">"name"</span>: <span class="hljs-string">"Ashutosh Krishna"</span>, <span class="hljs-string">"age"</span>: 23, <span class="hljs-string">"email"</span>: <span class="hljs-string">"ashutosh@example.com"</span>}
</code></pre>
<h2 id="heading-how-to-create-a-python-dictionary-from-json">How to Create a Python Dictionary from JSON</h2>
<p>To create a Python dictionary from JSON data, you can use the <code>json.loads()</code> function provided by the JSON module. This function takes a JSON string and converts it into a corresponding Python object, typically a dictionary.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json

<span class="hljs-comment"># JSON string</span>
json_str = <span class="hljs-string">'{"name": "Ashutosh Krishna", "age": 23, "email": "ashutosh@example.com"}'</span>

<span class="hljs-comment"># Convert JSON string to Python dictionary</span>
data = json.loads(json_str)

<span class="hljs-comment"># Access the dictionary values</span>
print(data[<span class="hljs-string">"name"</span>])
print(data[<span class="hljs-string">"age"</span>])
print(data[<span class="hljs-string">"email"</span>])
</code></pre>
<p>In this example, you have a JSON string <code>json_str</code> representing some data. By calling <code>json.loads(json_str)</code>, you convert the JSON string into a Python dictionary. You can then access the values in the dictionary using their respective keys.</p>
<p>The output will be:</p>
<pre><code class="lang-bash">Ashutosh Krishna
23
ashutosh@example.com
</code></pre>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Understanding the Python JSON module is necessary for working with JSON data because it is widely used for data exchange and storage in a variety of applications. </p>
<p>You can efficiently handle JSON data, interface with APIs, and deal with configuration files if you learn how to use the JSON module.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A Beginner's Guide to the Strategy Design Pattern ]]>
                </title>
                <description>
                    <![CDATA[ The Strategy Design Pattern is a behavioral design pattern. It allows you to dynamically change the behavior of an object by encapsulating it into different strategies.  This pattern enables an object to choose from multiple algorithms and behaviors ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-beginners-guide-to-the-strategy-design-pattern/</link>
                <guid isPermaLink="false">66ba0e61228e16bed602a88f</guid>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Thu, 04 May 2023 17:43:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/strategy-design-pattern.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The Strategy Design Pattern is a behavioral design pattern. It allows you to dynamically change the behavior of an object by encapsulating it into different strategies. </p>
<p>This pattern enables an object to choose from multiple algorithms and behaviors at runtime, rather than statically choosing a single one.</p>
<p>It is based on the principle of composition over inheritance. It defines a family of algorithms, encapsulates each one, and makes them interchangeable at runtime. The core idea behind this pattern is to separate the algorithms from the main object. This allows the object to delegate the algorithm's behavior to one of its contained strategies.</p>
<p>In simpler terms, the Strategy Design Pattern provides a way to extract the behavior of an object into separate classes that can be swapped in and out at runtime. This enables the object to be more flexible and reusable, as different strategies can be easily added or modified without changing the object's core code.</p>
<h2 id="heading-benefits-of-using-the-strategy-design-pattern">Benefits of Using the Strategy Design Pattern</h2>
<p>Using the Strategy Design Pattern can provide several benefits, including:</p>
<ol>
<li><strong>Improved code flexibility</strong>: By encapsulating the behavior of an object into different strategies, the code becomes more flexible and easier to modify.</li>
<li><strong>Better code reusability</strong>: Since the strategies are encapsulated and interchangeable, they can be reused across different objects and projects.</li>
<li><strong>Encourages better coding practices</strong>: This pattern promotes good coding practices, such as separating concerns and reducing code complexity.</li>
<li><strong>Simplifies testing</strong>: By separating the algorithms and behaviors from the object, testing becomes more straightforward.</li>
</ol>
<h2 id="heading-use-cases-for-the-strategy-design-pattern">Use Cases for the Strategy Design Pattern</h2>
<p>The Strategy Design Pattern can be useful in various scenarios, such as:</p>
<ol>
<li><strong>Sorting algorithms</strong>: Different sorting algorithms can be encapsulated into separate strategies and passed to an object that needs sorting.</li>
<li><strong>Validation rules</strong>: Different validation rules can be encapsulated into separate strategies and passed to an object that needs validation.</li>
<li><strong>Text formatting</strong>: Different formatting strategies can be encapsulated into separate strategies and passed to an object that needs formatting.</li>
<li><strong>Database access</strong>: Different database access strategies can be encapsulated into separate strategies and passed to an object that needs to access data from different sources.</li>
<li><strong>Payment strategy</strong>: Different payment methods can be encapsulated into separate strategies and passed to an object that needs to process payments.</li>
</ol>
<h2 id="heading-understanding-the-strategy-design-pattern">Understanding the Strategy Design Pattern</h2>
<p>The Strategy Design Pattern is a powerful pattern in the world of object-oriented programming. It provides a flexible way to encapsulate and swap the behavior of an object at runtime, enabling code to be more adaptable and easier to maintain. </p>
<p>In this section, we will dive deeper into the Strategy Design Pattern, discussing its definition, components, and how it works.</p>
<h3 id="heading-components-of-the-strategy-design-pattern">Components of the Strategy Design Pattern</h3>
<p>The Strategy Design Pattern consists of three primary components:</p>
<ol>
<li><strong>Context</strong>: The object that will delegate its behavior to one of the contained strategies. The context maintains a reference to a strategy object and interacts with it through a common interface.</li>
<li><strong>Strategy Interface</strong>: The interface that defines the behavior for all strategies. The strategies implement this interface to provide their unique implementation of the behavior.</li>
<li><strong>Concrete Strategies</strong>: The classes that implement the Strategy Interface. Each strategy encapsulates a specific behavior that the context can switch to at runtime.</li>
</ol>
<h3 id="heading-how-the-strategy-design-pattern-works">How the Strategy Design Pattern Works</h3>
<p>The Strategy Design Pattern works by separating the behavior of an object from the object itself. The behavior is encapsulated into different strategies, each with its own implementation of the behavior. </p>
<p>The context maintains a reference to a strategy object and interacts with it through a common interface. At runtime, the context can swap the current strategy with another one, effectively changing the object's behavior.</p>
<h3 id="heading-examples-of-the-strategy-design-pattern-in-action">Examples of the Strategy Design Pattern in Action</h3>
<p>One example of the Strategy Design Pattern in action is in a music streaming service where different subscription tiers have different pricing models. </p>
<p>Each subscription tier could have a different pricing strategy that encapsulates its unique pricing logic. The service's billing system would delegate the pricing calculation to the current subscription's strategy, allowing for easy modification and extension of the pricing logic.</p>
<p>Another example is payment strategies. Different payment methods can be encapsulated into separate strategies, each with its own unique processing logic. </p>
<p>A shopping cart application may use the Strategy Design Pattern to encapsulate credit card, PayPal, and cryptocurrency payment methods into separate strategies that can be swapped at runtime. The application's payment processing system would delegate the payment processing logic to the current payment method's strategy, allowing for easy modification and extension of the payment processing logic.</p>
<h2 id="heading-how-to-implement-the-strategy-design-pattern">How to Implement the Strategy Design Pattern</h2>
<p>In this section, we will discuss how to implement the Strategy Design Pattern. We will start with a code example that violates the Strategy Design Pattern and explain the problems with it. Then, we will refactor the code to demonstrate how to implement the Strategy Design Pattern.</p>
<p>To implement the Strategy Design Pattern in Java, follow these steps:</p>
<ol>
<li>Identify the algorithm or behavior that needs to be encapsulated and made interchangeable.</li>
<li>Define an interface that represents the behavior, with a single method signature that takes in any required parameters.</li>
<li>Implement concrete classes that provide specific implementations of the behavior defined in the interface.</li>
<li>Define a context class that holds a reference to the interface and calls its method when needed.</li>
<li>Modify the context class to allow for the dynamic swapping of the concrete implementations at runtime.</li>
</ol>
<h3 id="heading-code-example">Code Example</h3>
<p>Let's consider the following code example:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> withoutstrategy;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentProcessor</span> </span>{
    <span class="hljs-keyword">private</span> PaymentType paymentType;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processPayment</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        <span class="hljs-keyword">if</span> (paymentType == PaymentType.CREDIT_CARD) {
            System.out.println(<span class="hljs-string">"Processing credit card payment of amount "</span> + amount);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (paymentType == PaymentType.DEBIT_CARD) {
            System.out.println(<span class="hljs-string">"Processing debit card payment of amount "</span> + amount);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (paymentType == PaymentType.PAYPAL) {
            System.out.println(<span class="hljs-string">"Processing PayPal payment of amount "</span> + amount);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"Invalid payment type"</span>);
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setPaymentType</span><span class="hljs-params">(PaymentType paymentType)</span> </span>{
        <span class="hljs-keyword">this</span>.paymentType = paymentType;
    }
}

<span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">PaymentType</span> </span>{
    CREDIT_CARD,
    DEBIT_CARD,
    PAYPAL
}
</code></pre>
<p>In this code, the <code>PaymentProcessor</code> class has a <code>processPayment</code> method that takes a payment amount and processes the payment. The payment type is set using the <code>setPaymentType</code> method, which sets the <code>paymentType</code> field. The <code>processPayment</code> method then checks the value of <code>paymentType</code> and processes the payment accordingly.</p>
<p>The problem with this code is that it violates the <a target="_blank" href="https://www.freecodecamp.org/news/open-closed-principle-solid-architecture-concept-explained/">Open-Closed Principle</a>, which states that classes should be open for extension but closed for modification. In this code, if you want to add a new payment type, you would have to modify the <code>processPayment</code> method, which violates the Open-Closed Principle.</p>
<p>The <code>PaymentProcessor</code> class violates the Strategy pattern by using conditional statements to determine the type of payment and then processing it accordingly. This approach can quickly become unmanageable and inflexible as the number of payment types increases.</p>
<p>To fix this problem, you can use the Strategy Design Pattern. First, you define a common interface for all payment strategies, which in this case is the <code>PaymentStrategy</code> interface:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> withstrategy;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">PaymentStrategy</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">processPayment</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span></span>;
}
</code></pre>
<p>You then define concrete implementations of the <code>PaymentStrategy</code> interface for each payment type. For example, here are the <code>CreditCardPaymentStrategy</code>, <code>DebitCardPaymentStrategy</code>, and <code>PaypalPaymentStrategy</code> classes:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> withstrategy;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CreditCardPaymentStrategy</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">PaymentStrategy</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processPayment</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        System.out.println(<span class="hljs-string">"Processing credit card payment of amount "</span> + amount);
    }
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> withstrategy;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DebitCardPaymentStrategy</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">PaymentStrategy</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processPayment</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        System.out.println(<span class="hljs-string">"Processing debit card payment of amount "</span> + amount);
    }
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> withstrategy;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaypalPaymentStrategy</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">PaymentStrategy</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processPayment</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        System.out.println(<span class="hljs-string">"Processing PayPal payment of amount "</span> + amount);
    }
}
</code></pre>
<p>Finally, you update the <code>PaymentProcessor</code> class to take a <code>PaymentStrategy</code> object in its constructor, which it uses to process the payment:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> withstrategy;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentProcessor</span> </span>{
    <span class="hljs-keyword">private</span> PaymentStrategy paymentStrategy;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PaymentProcessor</span><span class="hljs-params">(PaymentStrategy paymentStrategy)</span> </span>{
        <span class="hljs-keyword">this</span>.paymentStrategy = paymentStrategy;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processPayment</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        paymentStrategy.processPayment(amount);
    }
}
</code></pre>
<p>This implementation follows the Open-Closed Principle as well as Strategy Pattern because you can add new payment types by creating new implementations of the <code>PaymentStrategy</code> interface without modifying the existing code.</p>
<h3 id="heading-best-practices-for-implementing-the-strategy-design-pattern">Best Practices for Implementing the Strategy Design Pattern</h3>
<p>Here are a few best practices to keep in mind when implementing the Strategy Design Pattern:</p>
<ol>
<li>Keep the interface simple and focused on a single responsibility.</li>
<li>Encapsulate any stateful behavior in the concrete strategy classes, rather than in the context class.</li>
<li>Use dependency injection to pass the concrete strategy to the context class, rather than creating it directly in the context class.</li>
<li>Use an enum or a factory class to provide a centralized place for creating and managing concrete strategy objects.</li>
</ol>
<h2 id="heading-real-world-applications-of-the-strategy-design-pattern">Real-World Applications of the Strategy Design Pattern</h2>
<p>The Strategy Design Pattern has been used extensively in various real-world applications. One such example is the <strong>Java Collections Framework</strong>. The Collections Framework provides a set of interfaces and classes to represent collections of objects, such as lists, sets, and maps. The framework allows different strategies to be applied to collections based on their behavior.</p>
<p>For instance, the Collections Framework includes a <code>sort()</code> method that allows the sorting of collections. The <code>sort()</code> method takes a Comparator object as an argument, which is responsible for comparing objects within the collection. The Comparator interface defines a strategy for comparing two objects, and the <code>sort()</code> method uses this strategy to sort the collection.</p>
<p>In addition, the Collections Framework also includes the Iterator interface, which defines a strategy for accessing elements of a collection. The Iterator allows the user to traverse the collection without exposing its internal structure, which can change over time. By using the Iterator interface, the user can switch between different strategies for accessing elements of the collection.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this tutorial, we have explored the Strategy Design Pattern and its implementation in Java. We have seen how the Strategy pattern can be used to separate the behavior of an object from its implementation, providing greater flexibility and maintainability in code.</p>
<p>We discussed the components of the Strategy Design Pattern, including the Context, Strategy Interface, and Concrete Strategies. We also provided an example of how the pattern can be used to implement a payment system, allowing for multiple payment options to be implemented using a single interface.</p>
<p>By separating the behavior of an object from its implementation, the Strategy pattern provides greater flexibility and adaptability to changing requirements.</p>
<h3 id="heading-additional-resources">Additional Resources</h3>
<ul>
<li><a target="_blank" href="https://www.freecodecamp.org/news/solid-principles-for-better-software-design/">SOLID Principles for Better Software Design</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/a-beginners-guide-to-the-strategy-design-pattern/freecodecamp.org/news/javascript-design-patterns-explained/">Design Patterns explained</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is SOLID? Principles for Better Software Design ]]>
                </title>
                <description>
                    <![CDATA[ The SOLID principles are a set of guidelines for writing high-quality, maintainable, and scalable software.  They were introduced by Robert C. Martin in his 2000 paper “Design Principles and Design Patterns” to help developers write software that is ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/solid-principles-for-better-software-design/</link>
                <guid isPermaLink="false">66ba0ec7439ed06e055759f0</guid>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ solid ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Wed, 03 May 2023 14:00:01 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/solid-principles.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The SOLID principles are a set of guidelines for writing high-quality, maintainable, and scalable software. </p>
<p>They were introduced by Robert C. Martin in his 2000 paper <a target="_blank" href="https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf">“Design Principles and Design Patterns”</a> to help developers write software that is easy to understand, modify, and extend. </p>
<p>These concepts were later built upon by Michael Feathers, who introduced us to the SOLID acronym.</p>
<p>The SOLID acronym stands for:</p>
<ul>
<li><strong>S</strong>ingle Responsibility Principle (SRP)</li>
<li><strong>O</strong>pen-Closed Principle (OCP)</li>
<li><strong>L</strong>iskov Substitution Principle (LSP)</li>
<li><strong>I</strong>nterface Segregation Principle (ISP)</li>
<li><strong>D</strong>ependency Inversion Principle (DIP)</li>
</ul>
<p>These principles provide a way for developers to organize their code and create software that is flexible, easy to change, and testable. Applying SOLID principles can lead to code that is more modular, maintainable, and extensible, and it can make it easier for developers to work collaboratively on a codebase.</p>
<p>In this tutorial, we will explore each of the SOLID principles in detail, explain why they are important, and provide examples of how you can apply them in practice. By the end of this tutorial, you should have a good understanding of the SOLID principles and how to apply them to your software development projects.</p>
<h2 id="heading-what-is-the-single-responsibility-principle"><strong>What is the Single Responsibility Principle?</strong></h2>
<p>The Single Responsibility Principle (SRP) states that <strong>a class should have only one reason to change</strong>, or in other words, <strong>it should have only one responsibility</strong>. This means that a class should have only one job to do, and it should do it well.</p>
<p>If a class has too many responsibilities, it can become hard to understand, maintain, and modify. Changes to one responsibility can inadvertently affect another responsibility, leading to unintended consequences and bugs. By following SRP, we can create code that is more modular, easier to understand, and less prone to errors.</p>
<p>Let's take an example that violates the SRP:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Marker</span> </span>{
    String name;
    String color;
    <span class="hljs-keyword">int</span> price;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Marker</span><span class="hljs-params">(String name, String color, <span class="hljs-keyword">int</span> price)</span> </span>{
        <span class="hljs-keyword">this</span>.name = name;
        <span class="hljs-keyword">this</span>.color = color;
        <span class="hljs-keyword">this</span>.price = price;
    }
}
</code></pre>
<p>The above code defines a simple <code>Marker</code> class having three instance variables – <code>name</code>, <code>color</code> and <code>price</code>.</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Invoice</span> </span>{
    <span class="hljs-keyword">private</span> Marker marker;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> quantity;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Invoice</span><span class="hljs-params">(Marker marker, <span class="hljs-keyword">int</span> quantity)</span> </span>{
        <span class="hljs-keyword">this</span>.marker = marker;
        <span class="hljs-keyword">this</span>.quantity = quantity;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">calculateTotal</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> marker.price * <span class="hljs-keyword">this</span>.quantity;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printInvoice</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// printing implementation</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">saveToDb</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// save to database implementation</span>
    }
}
</code></pre>
<p>The above <code>Invoice</code> class violates the SRP because it has multiple responsibilities – it is responsible for calculating the total amount, printing the invoice, and saving the invoice to the database. As a result, if the calculation logic changes, such as the addition of taxes, the <code>calculateTotal()</code> method would require modification. Similarly, if the printing or database-saving implementation changes at any point, the class would need to be changed. </p>
<p>There are several reasons for the class to be modified, which could lead to increased maintenance costs and complexity.</p>
<p>Here's how you can modify the code to follow the SRP:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Invoice</span> </span>{
    <span class="hljs-keyword">private</span> Marker marker;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> quantity;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Invoice</span><span class="hljs-params">(Marker marker, <span class="hljs-keyword">int</span> quantity)</span> </span>{
        <span class="hljs-keyword">this</span>.marker = marker;
        <span class="hljs-keyword">this</span>.quantity = quantity;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">calculateTotal</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> marker.price * <span class="hljs-keyword">this</span>.quantity;
    }
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InvoiceDao</span> </span>{
    <span class="hljs-keyword">private</span> Invoice invoice;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">InvoiceDao</span><span class="hljs-params">(Invoice invoice)</span> </span>{
        <span class="hljs-keyword">this</span>.invoice = invoice;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">saveToDb</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// save to database implementation</span>
    }
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InvoicePrinter</span> </span>{
    <span class="hljs-keyword">private</span> Invoice invoice;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">InvoicePrinter</span><span class="hljs-params">(Invoice invoice)</span> </span>{
        <span class="hljs-keyword">this</span>.invoice = invoice;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printInvoice</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// printing implementation</span>
    }
}
</code></pre>
<p>In this refactored example, we have split the responsibilities of the <code>Invoice</code> class into three separate classes: <code>Invoice</code>, <code>InvoiceDao</code>, and <code>InvoicePrinter</code>. </p>
<p>The <code>Invoice</code> class is responsible only for calculating the total amount, and the printing and saving responsibilities have been delegated to separate classes. This makes the code more modular, easier to understand, and less prone to errors.</p>
<h2 id="heading-what-is-the-open-closed-principle"><strong>What is the Open-Closed Principle?</strong></h2>
<p>The Open-Closed Principle (OCP) states that <strong>software entities (classes, modules, functions, and so on) should be open for extension but closed for modification</strong>. This means that the behavior of a software entity can be extended without modifying its source code.</p>
<p>The OCP is essential because it promotes software extensibility and maintainability. By allowing software entities to be extended without modification, developers can add new functionality without the risk of breaking existing code. This results in code that is easier to maintain, extend, and reuse.</p>
<p>Let's take the previous example again.</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InvoiceDao</span> </span>{
    <span class="hljs-keyword">private</span> Invoice invoice;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">InvoiceDao</span><span class="hljs-params">(Invoice invoice)</span> </span>{
        <span class="hljs-keyword">this</span>.invoice = invoice;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">saveToDb</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// save to database implementation</span>
    }
}
</code></pre>
<p>The <code>InvoiceDao</code> class has a single responsibility of saving the invoice to the database. But, suppose there's a new requirement to save the invoice to a file as well. One way to implement this requirement would be to modify the existing <code>InvoiceDao</code> class by adding a <code>saveToFile()</code> method. But this violates the Open-Closed Principle because it modifies the existing code that has already been tested and is live in production.</p>
<p>To follow the OCP, a better solution would be to create an <code>InvoiceDao</code> interface and implement it separately for database and file saving as shown below:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">InvoiceDao</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">save</span><span class="hljs-params">(Invoice invoice)</span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DatabaseInvoiceDao</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">InvoiceDao</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">save</span><span class="hljs-params">(Invoice invoice)</span> </span>{
        <span class="hljs-comment">// save to database implementation</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FileInvoiceDao</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">InvoiceDao</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">save</span><span class="hljs-params">(Invoice invoice)</span> </span>{
        <span class="hljs-comment">// save to file implementation</span>
    }
}
</code></pre>
<p>This way, if there's a new requirement to save the invoice to another data store, you can implement a new <code>InvoiceDao</code> implementation without modifying the existing code. Now the <code>InvoiceDao</code> interface is open for extension and closed for modification, which follows the OCP.</p>
<h2 id="heading-what-is-the-liskov-substitution-principle"><strong>What is the </strong>L<strong>iskov Substitution Principle?</strong></h2>
<p>The Liskov Substitution Principle (LSP) states that <strong>any instance of a derived class should be substitutable for an instance of its base class without affecting the correctness of the program</strong>. </p>
<p>In other words, a derived class should behave like its base class in all contexts. In more simple terms, if class A is a subtype of class B, you should be able to replace B with A without breaking the behavior of your program.</p>
<p>The importance of the LSP lies in its ability to ensure that the behavior of a program remains consistent and predictable when substituting objects of different classes. Violating the LSP can lead to unexpected behavior, bugs, and maintainability issues.</p>
<p>Let's take an example.</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Bike</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">turnOnEngine</span><span class="hljs-params">()</span></span>;

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">accelerate</span><span class="hljs-params">()</span></span>;
}
</code></pre>
<p>In the given example, the interface <code>Bike</code> has two methods, <code>turnOnEngine()</code> and <code>accelerate()</code>. Two classes implement this interface, <code>Motorbike</code> and <code>Bicycle</code>.</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Motorbike</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Bike</span> </span>{

    <span class="hljs-keyword">boolean</span> isEngineOn;
    <span class="hljs-keyword">int</span> speed;

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">turnOnEngine</span><span class="hljs-params">()</span> </span>{
        isEngineOn = <span class="hljs-keyword">true</span>;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">accelerate</span><span class="hljs-params">()</span> </span>{
        speed += <span class="hljs-number">5</span>;
    }
}
</code></pre>
<p><code>Motorbike</code> correctly implements the <code>turnOnEngine()</code> method, as it sets the <code>isEngineOn</code> boolean to true. It also correctly implements the <code>accelerate()</code> method by increasing the <code>speed</code> by 5.</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Bicycle</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Bike</span> </span>{

    <span class="hljs-keyword">boolean</span> isEngineOn;
    <span class="hljs-keyword">int</span> speed;

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">turnOnEngine</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> AssertionError(<span class="hljs-string">"There is no engine!"</span>);
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">accelerate</span><span class="hljs-params">()</span> </span>{
        speed += <span class="hljs-number">5</span>;
    }
}
</code></pre>
<p>However, the <code>Bicycle</code> class throws an <code>AssertionError</code> in the <code>turnOnEngine()</code> method because it has no engine. This means that an instance of <code>Bicycle</code> cannot be substituted for an instance of <code>Bike</code> without breaking the behavior of the program.</p>
<p>In other words, if the <code>Bicycle</code> class is considered a subtype of the <code>Bike</code> interface, then according to the LSP, any instance of <code>Bike</code> should be replaceable with an instance of <code>Bicycle</code> without altering the correctness of the program. </p>
<p>But in this case, it's not true because <code>Bicycle</code> throws an <code>AssertionError</code> while trying to turn on the engine. Therefore, the code violates the LSP.</p>
<h2 id="heading-what-is-the-interface-segregation-principle"><strong>What is the </strong>I<strong>nterface Segregation Principle?</strong></h2>
<p>The Interface Segregation Principle (ISP) focuses on designing interfaces that are specific to their client's needs. It states that no client should be forced to depend on methods it does not use.</p>
<p>The principle suggests that <strong>instead of creating a large interface that covers all the possible methods, it's better to create smaller, more focused interfaces for specific use cases</strong>. This approach results in interfaces that are more cohesive and less coupled.</p>
<p>Consider a <code>Vehicle</code> interface as below:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Vehicle</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">startEngine</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">stopEngine</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">fly</span><span class="hljs-params">()</span></span>;
}
</code></pre>
<p>And then you have a class called <code>Car</code> that implements the <code>Vehicle</code> interface:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Vehicle</span> </span>{

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startEngine</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stopEngine</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">fly</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnsupportedOperationException(<span class="hljs-string">"This vehicle cannot fly."</span>);
    }
}
</code></pre>
<p>In this example, the <code>Vehicle</code> interface has too many methods. The <code>Car</code> class is forced to implement all of them, even though they cannot fly. This violates the ISP because the <code>Vehicle</code> interface is not properly segregated into smaller interfaces based on related functionality.</p>
<p>Let's understand how you can follow the ISP here. Suppose you refactor the <code>Vehicle</code> interface into smaller, more focused interfaces:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Drivable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">startEngine</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">stopEngine</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Flyable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">fly</span><span class="hljs-params">()</span></span>;
}
</code></pre>
<p>Now, you can have a class called <code>Car</code> that only implements the <code>Drivable</code> interface:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Drivable</span> </span>{

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startEngine</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stopEngine</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }
}
</code></pre>
<p>And, thanks to interface segregation, you can have another class called <code>Airplane</code> that implements both the <code>Drivable</code> and <code>Flyable</code> interfaces:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Airplane</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Drivable</span>, <span class="hljs-title">Flyable</span> </span>{

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startEngine</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stopEngine</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drive</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">fly</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }
}
</code></pre>
<p>In this example, you have properly segregated the <code>Vehicle</code> interface into smaller interfaces based on related functionality. This adheres to the ISP and makes your code more flexible and maintainable.</p>
<h2 id="heading-what-is-the-dependency-inversion-principle"><strong>What is the Dependency Inversion Principle?</strong></h2>
<p>The Dependency Inversion Principle (DIP) states that <strong>high-level modules should not depend on low-level modules, but both should depend on abstractions</strong>. Abstractions should not depend on details – details should depend on abstractions. </p>
<p>This principle aims to reduce coupling between modules, increase modularity, and make the code easier to maintain, test, and extend.</p>
<p>For example, consider a scenario where you have a class that needs to use an instance of another class. In the traditional approach, the first class would directly create an instance of the second class, leading to a tight coupling between them. This makes it difficult to change the implementation of the second class or to test the first class independently. </p>
<p>But if you apply the DIP, the first class would depend on an abstraction of the second class instead of the implementation. This would make it possible to easily change the implementation and test the first class independently.</p>
<p>Here is an example that violates the DIP:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WeatherTracker</span> </span>{
    <span class="hljs-keyword">private</span> String currentConditions;
    <span class="hljs-keyword">private</span> Emailer emailer;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WeatherTracker</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">this</span>.emailer = <span class="hljs-keyword">new</span> Emailer();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setCurrentConditions</span><span class="hljs-params">(String weatherDescription)</span> </span>{
        <span class="hljs-keyword">this</span>.currentConditions = weatherDescription;
        <span class="hljs-keyword">if</span> (weatherDescription == <span class="hljs-string">"rainy"</span>) {
            emailer.sendEmail(<span class="hljs-string">"It is rainy"</span>);
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Emailer</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendEmail</span><span class="hljs-params">(String message)</span> </span>{
        System.out.println(<span class="hljs-string">"Email sent: "</span> + message);
    }
}
</code></pre>
<p>In this example, the <code>WeatherTracker</code> class directly creates an instance of the <code>Emailer</code> class, making it tightly coupled to the implementation. This makes it difficult to change the implementation of the <code>Emailer</code> class or to test the <code>WeatherTracker</code> class independently.</p>
<p>Here is an example of how to apply the DIP to the above code:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Notifier</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">alertWeatherConditions</span><span class="hljs-params">(String weatherDescription)</span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WeatherTracker</span> </span>{
    <span class="hljs-keyword">private</span> String currentConditions;
    <span class="hljs-keyword">private</span> Notifier notifier;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WeatherTracker</span><span class="hljs-params">(Notifier notifier)</span> </span>{
        <span class="hljs-keyword">this</span>.notifier = notifier;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setCurrentConditions</span><span class="hljs-params">(String weatherDescription)</span> </span>{
        <span class="hljs-keyword">this</span>.currentConditions = weatherDescription;
        <span class="hljs-keyword">if</span> (weatherDescription == <span class="hljs-string">"rainy"</span>) {
            notifier.alertWeatherConditions(<span class="hljs-string">"It is rainy"</span>);
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Emailer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Notifier</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">alertWeatherConditions</span><span class="hljs-params">(String weatherDescription)</span> </span>{
        System.out.println(<span class="hljs-string">"Email sent: "</span> + weatherDescription);
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SMS</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Notifier</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">alertWeatherConditions</span><span class="hljs-params">(String weatherDescription)</span> </span>{
        System.out.println(<span class="hljs-string">"SMS sent: "</span> + weatherDescription);
    }
}
</code></pre>
<p>In this example, we created a <code>Notifier</code> interface that defines the <code>alertWeatherConditions</code> method. The <code>WeatherTracker</code> class now depends on this interface instead of the <code>Emailer</code> class, making it possible to easily change the implementation and test the <code>WeatherTracker</code> class independently. </p>
<p>We also created two implementations of the <code>Notifier</code> interface, <code>Emailer</code>, and <code>SMS</code>, to demonstrate how you can change the implementation of the <code>WeatherTracker</code> class without affecting its behavior.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In this article, you learned about the SOLID principles which are a very important part of general Design Principles. </p>
<p>By applying these principles in your software development projects, you can create code that is easier to maintain, extend, and modify, leading to more robust, flexible, and reusable software. This will also lead to better collaboration among team members, as the code becomes more modular and easier to work with.</p>
<blockquote>
<p>For more such tutorials, you can follow <a target="_blank" href="https://blog.ashutoshkrris.in/">my personal blog</a>.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Currency Converter GUI with Tkinter ]]>
                </title>
                <description>
                    <![CDATA[ Tkinter is a built-in Python library for creating graphical user interfaces (GUIs). It provides a set of tools for building windows, frames, buttons, textboxes, and other GUI elements.  It is easy to use and widely available, making it a popular choi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-currency-converter-gui-with-tkinter/</link>
                <guid isPermaLink="false">66ba0e7a79b7f411df58dea5</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 10 Apr 2023 16:44:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/currency-converter.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Tkinter is a built-in Python library for creating graphical user interfaces (GUIs). It provides a set of tools for building windows, frames, buttons, textboxes, and other GUI elements. </p>
<p>It is easy to use and widely available, making it a popular choice for building GUI applications in Python. It is also highly customizable, allowing developers to create unique and visually appealing user interfaces.</p>
<p>In this tutorial, you'll build a Currency Converter GUI application using Tkinter. Before you dive into the tutorial, it's worth noting that this is not the first time we're building a GUI application with Tkinter. In a previous tutorial, we built a <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-build-a-gui-quiz-application-using-tkinter-and-open-trivia-db">GUI Quiz App using Tkinter</a>, and in another tutorial series, we built a <a target="_blank" href="https://blog.ashutoshkrris.in/password-generator-using-python-and-tkinter-part-i">Password Manager</a>. I encourage you to check out those tutorials as well.</p>
<p>Here's how your end result will look:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/Converter.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You can find the code for the tutorial in <a target="_blank" href="https://github.com/ashutoshkrris/currency-converter-gui">this repository</a>.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial and build the application, you should have the following:</p>
<ul>
<li>Basic knowledge of the Python programming language</li>
<li>Python 3.8+ installed on your system</li>
<li>Familiarity with the <a target="_blank" href="https://docs.python.org/3/library/tkinter.html">Tkinter</a> and <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-interact-with-web-services-using-python">Requests</a> libraries</li>
</ul>
<h2 id="heading-how-to-set-up-your-virtual-environment">How to Set Up Your Virtual Environment</h2>
<p>Before you start coding, you'll need to make sure you have all the necessary tools and libraries installed. To ensure that you have a clean and isolated environment, you'll create a virtual environment using <code>venv</code>.</p>
<p>Create a project directory and navigate to it in the terminal:</p>
<pre><code class="lang-bash">mkdir currency-converter
<span class="hljs-built_in">cd</span> currency-converter
</code></pre>
<p>Create a virtual environment named <code>env</code> using the following command:</p>
<pre><code class="lang-bash">python -m venv env
</code></pre>
<p>Python now ships with the pre-installed <code>venv</code> library to create virtual environments.</p>
<p>Activate the virtual environment like this:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> env/bin/activate
</code></pre>
<p>Note: if you're on Windows, you'll need to use <code>source env/Scripts/activate</code> to activate the environment.</p>
<p>You should see <code>(env)</code> in your terminal prompt, indicating that the virtual environment has been activated.</p>
<h3 id="heading-how-to-install-the-libraries">How to Install the Libraries</h3>
<p>Now that you've created the virtual environment, you can install the following libraries:</p>
<ul>
<li><code>requests</code>: The library helps you send requests on API endpoints.</li>
<li><code>python-decouple</code>: The library helps you read the values of environment variables.</li>
<li><code>pillow</code>: The library adds image processing capabilities to your Python interpreter.</li>
</ul>
<p>To install the libraries, run the following command:</p>
<pre><code class="lang-bash">pip install requests python-decouple pillow
</code></pre>
<h2 id="heading-how-to-build-the-currency-converter-utility-functions">How to Build the Currency Converter Utility Functions</h2>
<p>In this section, you will start building the core functionality of our Currency Converter GUI. You will create two utility functions that will be used to convert currencies and retrieve currency codes from a JSON file.</p>
<p>To define the utility functions, you will create a new file called <code>utils.py</code> in the project. This file will contain all of your utility functions for the Currency Converter GUI.</p>
<h3 id="heading-utility-function-to-get-currency-codes-from-the-json-file">Utility Function to Get Currency Codes from the JSON File</h3>
<p>This utility function will retrieve currency codes from a JSON file. This function will allow you to populate the GUI with a list of available currencies that the user can select from.</p>
<p>Create a <code>currency.json</code> file that includes the currency code and name of various currencies. The JSON file has the following structure:</p>
<pre><code class="lang-json">[
  { <span class="hljs-attr">"AED"</span>: <span class="hljs-string">"United Arab Emirates Dirham"</span> },
  { <span class="hljs-attr">"AFN"</span>: <span class="hljs-string">"Afghan Afghani"</span> },
  { <span class="hljs-attr">"ALL"</span>: <span class="hljs-string">"Albanian Lek"</span> },
  ...
]
</code></pre>
<p>You can obtain the content of the <code>currency.json</code> file from <a target="_blank" href="https://github.com/ashutoshkrris/currency-converter-gui/blob/main/currency.json">this link</a> and copy it into the <code>currency.json</code> file in your project.</p>
<p>Add the following code to define the first utility function:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_currencies</span>() -&gt; list:</span>
    currency_codes = []
    <span class="hljs-keyword">with</span> open(<span class="hljs-string">'currency.json'</span>) <span class="hljs-keyword">as</span> f:
        currency_data = json.load(f)
        <span class="hljs-keyword">for</span> currency <span class="hljs-keyword">in</span> currency_data:
            code, _ = list(currency.items())[<span class="hljs-number">0</span>]
            currency_codes.append(code)
    <span class="hljs-keyword">return</span> sorted(currency_codes)
</code></pre>
<p>In the above code, you define a <code>get_currencies()</code> function that returns a list of currency codes. Inside the function, you create an empty list called <code>currency_codes</code> which you will use to store the currency codes. Then, you open the <code>currency.json</code> file in read mode and use the <code>json.load()</code> method to load the contents of the file into a Python dictionary called <code>currency_data</code>.</p>
<p>Next, you loop through each item in the <code>currency_data</code> dictionary using a <code>for</code> loop. Each item in the <code>currency_data</code> dictionary is a dictionary itself, with a single key-value pair representing a currency code and its name. Inside the <code>for</code> loop, you use the <code>list()</code> function to convert the key-value pair of each currency into a list. </p>
<p>Since each dictionary contains only one key-value pair, we can use the <code>items()</code> method to convert the dictionary into a list of tuples containing the key-value pairs.</p>
<p>You then use <a target="_blank" href="https://blog.ashutoshkrris.in/mastering-list-destructuring-and-packing-in-python-a-comprehensive-guide">tuple unpacking</a> to assign the first element of the list to the <code>code</code> variable and ignore the second element using <code>_</code>. </p>
<p>Finally, you append the <code>code</code> variable, representing the currency code, to the <code>currency_codes</code> list. After looping through all the currencies in <code>currency_data</code>, you sort the <code>currency_codes</code> list in ascending order using the <code>sorted()</code> function and return it from the function.</p>
<p>If you call the function and print its result, you'll get the following output:</p>
<pre><code class="lang-bash">[<span class="hljs-string">'ADA'</span>, <span class="hljs-string">'AED'</span>, <span class="hljs-string">'AFN'</span>, <span class="hljs-string">'ALL'</span>, <span class="hljs-string">'AMD'</span>, <span class="hljs-string">'ANG'</span>, <span class="hljs-string">'AOA'</span>, <span class="hljs-string">'ARS'</span>, <span class="hljs-string">'AUD'</span>, <span class="hljs-string">'AVAX'</span>, <span class="hljs-string">'AWG'</span>, <span class="hljs-string">'AZN'</span>, <span class="hljs-string">'BAM'</span>, <span class="hljs-string">'BBD'</span>, <span class="hljs-string">'BDT'</span>, <span class="hljs-string">'BGN'</span>, <span class="hljs-string">'BHD'</span>, <span class="hljs-string">'BIF'</span>, <span class="hljs-string">'BMD'</span>, <span class="hljs-string">'BNB'</span>, <span class="hljs-string">'BND'</span>, <span class="hljs-string">'BOB'</span>, <span class="hljs-string">'BRL'</span>, <span class="hljs-string">'BSD'</span>, <span class="hljs-string">'BTC'</span>, <span class="hljs-string">'BTN'</span>, <span class="hljs-string">'BWP'</span>, <span class="hljs-string">'BYN'</span>, <span class="hljs-string">'BYR'</span>, <span class="hljs-string">'BZD'</span>, <span class="hljs-string">'CAD'</span>, <span class="hljs-string">'CDF'</span>, <span class="hljs-string">'CHF'</span>, <span class="hljs-string">'CLF'</span>, <span class="hljs-string">'CLP'</span>, <span class="hljs-string">'CNY'</span>, <span class="hljs-string">'COP'</span>, <span class="hljs-string">'CRC'</span>, <span class="hljs-string">'CUC'</span>, <span class="hljs-string">'CUP'</span>, <span class="hljs-string">'CVE'</span>, <span class="hljs-string">'CZK'</span>, <span class="hljs-string">'DJF'</span>, <span class="hljs-string">'DKK'</span>, <span class="hljs-string">'DOP'</span>, <span class="hljs-string">'DOT'</span>, <span class="hljs-string">'DZD'</span>, <span class="hljs-string">'EGP'</span>, <span class="hljs-string">'ERN'</span>, <span class="hljs-string">'ETB'</span>, <span class="hljs-string">'ETH'</span>, <span class="hljs-string">'EUR'</span>, <span class="hljs-string">'FJD'</span>, <span class="hljs-string">'FKP'</span>, <span class="hljs-string">'GBP'</span>, <span class="hljs-string">'GEL'</span>, <span class="hljs-string">'GGP'</span>, <span class="hljs-string">'GHS'</span>, <span class="hljs-string">'GIP'</span>, <span class="hljs-string">'GMD'</span>, <span class="hljs-string">'GNF'</span>, <span class="hljs-string">'GTQ'</span>, <span class="hljs-string">'GYD'</span>, <span class="hljs-string">'HKD'</span>, <span class="hljs-string">'HNL'</span>, <span class="hljs-string">'HRK'</span>, <span class="hljs-string">'HTG'</span>, <span class="hljs-string">'HUF'</span>, <span class="hljs-string">'IDR'</span>, <span class="hljs-string">'ILS'</span>, <span class="hljs-string">'IMP'</span>, <span class="hljs-string">'INR'</span>, <span class="hljs-string">'IQD'</span>, <span class="hljs-string">'IRR'</span>, <span class="hljs-string">'ISK'</span>, <span class="hljs-string">'JEP'</span>, <span class="hljs-string">'JMD'</span>, <span class="hljs-string">'JOD'</span>, <span class="hljs-string">'JPY'</span>, <span class="hljs-string">'KES'</span>, <span class="hljs-string">'KGS'</span>, <span class="hljs-string">'KHR'</span>, <span class="hljs-string">'KMF'</span>, <span class="hljs-string">'KPW'</span>, <span class="hljs-string">'KRW'</span>, <span class="hljs-string">'KWD'</span>, <span class="hljs-string">'KYD'</span>, <span class="hljs-string">'KZT'</span>, <span class="hljs-string">'LAK'</span>, <span class="hljs-string">'LBP'</span>, <span class="hljs-string">'LKR'</span>, <span class="hljs-string">'LRD'</span>, <span class="hljs-string">'LSL'</span>, <span class="hljs-string">'LTC'</span>, <span class="hljs-string">'LTL'</span>, <span class="hljs-string">'LVL'</span>, <span class="hljs-string">'LYD'</span>, <span class="hljs-string">'MAD'</span>, <span class="hljs-string">'MATIC'</span>, <span class="hljs-string">'MDL'</span>, <span class="hljs-string">'MGA'</span>, <span class="hljs-string">'MKD'</span>, <span class="hljs-string">'MMK'</span>, <span class="hljs-string">'MNT'</span>, <span class="hljs-string">'MOP'</span>, <span class="hljs-string">'MRO'</span>, <span class="hljs-string">'MUR'</span>, <span class="hljs-string">'MVR'</span>, <span class="hljs-string">'MWK'</span>, <span class="hljs-string">'MXN'</span>, <span class="hljs-string">'MYR'</span>, <span class="hljs-string">'MZN'</span>, <span class="hljs-string">'NAD'</span>, <span class="hljs-string">'NGN'</span>, <span class="hljs-string">'NIO'</span>, <span class="hljs-string">'NOK'</span>, <span class="hljs-string">'NPR'</span>, <span class="hljs-string">'NZD'</span>, <span class="hljs-string">'OMR'</span>, <span class="hljs-string">'PAB'</span>, <span class="hljs-string">'PEN'</span>, <span class="hljs-string">'PGK'</span>, <span class="hljs-string">'PHP'</span>, <span class="hljs-string">'PKR'</span>, <span class="hljs-string">'PLN'</span>, <span class="hljs-string">'PYG'</span>, <span class="hljs-string">'QAR'</span>, <span class="hljs-string">'RON'</span>, <span class="hljs-string">'RSD'</span>, <span class="hljs-string">'RUB'</span>, <span class="hljs-string">'RWF'</span>, <span class="hljs-string">'SAR'</span>, <span class="hljs-string">'SBD'</span>, <span class="hljs-string">'SCR'</span>, <span class="hljs-string">'SDG'</span>, <span class="hljs-string">'SEK'</span>, <span class="hljs-string">'SGD'</span>, <span class="hljs-string">'SHP'</span>, <span class="hljs-string">'SLL'</span>, <span class="hljs-string">'SOL'</span>, <span class="hljs-string">'SOS'</span>, <span class="hljs-string">'SRD'</span>, <span class="hljs-string">'STD'</span>, <span class="hljs-string">'SVC'</span>, <span class="hljs-string">'SYP'</span>, <span class="hljs-string">'SZL'</span>, <span class="hljs-string">'THB'</span>, <span class="hljs-string">'TJS'</span>, <span class="hljs-string">'TMT'</span>, <span class="hljs-string">'TND'</span>, <span class="hljs-string">'TOP'</span>, <span class="hljs-string">'TRY'</span>, <span class="hljs-string">'TTD'</span>, <span class="hljs-string">'TWD'</span>, <span class="hljs-string">'TZS'</span>, <span class="hljs-string">'UAH'</span>, <span class="hljs-string">'UGX'</span>, <span class="hljs-string">'USD'</span>, <span class="hljs-string">'UYU'</span>, <span class="hljs-string">'UZS'</span>, <span class="hljs-string">'VEF'</span>, <span class="hljs-string">'VND'</span>, <span class="hljs-string">'VUV'</span>, <span class="hljs-string">'WST'</span>, <span class="hljs-string">'XAF'</span>, <span class="hljs-string">'XAG'</span>, <span class="hljs-string">'XAU'</span>, <span class="hljs-string">'XCD'</span>, <span class="hljs-string">'XDR'</span>, <span class="hljs-string">'XOF'</span>, <span class="hljs-string">'XPF'</span>, <span class="hljs-string">'XRP'</span>, <span class="hljs-string">'YER'</span>, <span class="hljs-string">'ZAR'</span>, <span class="hljs-string">'ZMK'</span>, <span class="hljs-string">'ZMW'</span>, <span class="hljs-string">'ZWL'</span>]
</code></pre>
<h3 id="heading-utility-function-to-convert-currencies">Utility Function to Convert Currencies</h3>
<p>In order to build the currency converter, you need a utility function that can convert one currency to another. For this purpose, you'll use an external API to fetch the latest currency exchange value. While there are many currency exchange APIs available such as <a target="_blank" href="https://api.forex/">API Forex</a>, <a target="_blank" href="https://fxapi.com/">Forex API</a>, and so on, you're going to use the <a target="_blank" href="https://currencyapi.com/">Currency Conversion API</a>. </p>
<p>You can integrate the API in your code either by using the <code>requests</code> module or its own <code>[currencyapi-python](https://github.com/everapihq/currencyapi-python)</code> library. As already mentioned, you'll use the <code>requests</code> module in this tutorial.</p>
<p>To use the API, you will need to sign up for an API key. You can sign up for a free account at <a target="_blank" href="https://app.currencyapi.com/register">https://app.currencyapi.com/register</a>. Once you have signed up, you can find your API key (highlighted in black) on the dashboard page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/Screenshot-2023-03-31-140705.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Create a <code>.env</code> file and add the following code to set the environment variable:</p>
<pre><code><span class="hljs-keyword">export</span> API_KEY=<span class="hljs-string">'your-api-key-here'</span>
</code></pre><p>Copy your API Key from the dashboard and replace the <code>your-api-key-here</code> in the above file. Then run the following command to set the environment variables:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> .env
</code></pre>
<p>You then use the <code>python-decouple</code> library to read the API key values in the Python code. </p>
<p>Next, in the same <code>utils.py</code> file, add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config


API_KEY = config(<span class="hljs-string">'API_KEY'</span>)
API_ENDPOINT = <span class="hljs-string">'https://api.currencyapi.com/v3/latest'</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">convert_currency</span>(<span class="hljs-params">from_currency: str, to_currency: str, amount: float</span>) -&gt; float:</span>
    query_params = {
        <span class="hljs-string">'apikey'</span>: API_KEY,
        <span class="hljs-string">'base_currency'</span>: from_currency,
        <span class="hljs-string">'currencies'</span>: to_currency
    }
    response = requests.get(API_ENDPOINT, params=query_params)
    currency_data = response.json()
    exchange_rate = currency_data[<span class="hljs-string">'data'</span>][to_currency][<span class="hljs-string">'value'</span>]
    exchanged_value = exchange_rate * amount
    <span class="hljs-keyword">return</span> exchanged_value
</code></pre>
<p>The <code>convert_currency</code> function takes three arguments: <code>from_currency</code>, <code>to_currency</code>, and <code>amount</code>. <code>from_currency</code> and <code>to_currency</code> are the ISO currency codes for the currencies being converted and <code>amount</code> is the amount of the <code>from_currency</code> that you want to convert.</p>
<p>The function sends a GET request to the <code>API_ENDPOINT</code> URL with the <code>API_KEY</code>, <code>from_currency</code>, and <code>to_currency</code> as query parameters. The <code>requests.get()</code> function from the <code>requests</code> module is used to send the request and the <code>params</code> argument is used to pass the query parameters.</p>
<p>Once the response is received, we convert it into a Python dictionary using the <code>json()</code> method of the <code>response</code> object. A sample successful response looks like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"meta"</span>:{
    <span class="hljs-attr">"last_updated_at"</span>:<span class="hljs-string">"2023-03-30T23:59:59Z"</span>
  },
  <span class="hljs-attr">"data"</span>:{
    <span class="hljs-attr">"INR"</span>:{
      <span class="hljs-attr">"code"</span>:<span class="hljs-string">"INR"</span>,
      <span class="hljs-attr">"value"</span>:<span class="hljs-number">82.100841</span>
    }
  }
}
</code></pre>
<p>You then extract the exchange rate from the response dictionary and calculate the exchanged value using the <code>amount</code> and <code>exchange_rate</code>. Finally, you return the exchanged value.</p>
<h2 id="heading-how-to-design-the-currency-converter-gui-with-tkinter">How to Design the Currency Converter GUI with Tkinter</h2>
<p>Now that you have the utility functions ready, you can design the GUI using Tkinter. Here's what the application will look like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/Screenshot-2023-03-31-203154.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The design includes a window of 300 X 320 size with a top frame and a main frame. The top frame contains the icon and title of the application. The main frame includes labels, combo boxes, entry widget, and button for currency conversion.</p>
<p>Let's build the application step by step. Create a <code>main.py</code> file in the project directory. First, import the necessary modules and functions, as well as define some color constants.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> tkinter <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> tkinter <span class="hljs-keyword">import</span> Tk, ttk

<span class="hljs-keyword">from</span> PIL <span class="hljs-keyword">import</span> Image, ImageTk

<span class="hljs-keyword">from</span> utils <span class="hljs-keyword">import</span> convert_currency, get_currencies

<span class="hljs-comment"># Colors</span>
WHITE_COLOR = <span class="hljs-string">"#FFFFFF"</span>
BLACK_COLOR = <span class="hljs-string">"#333333"</span>
BLUE_COLOR = <span class="hljs-string">"#0000FF"</span>
</code></pre>
<h3 id="heading-how-to-create-the-window">How to Create the Window</h3>
<p>When creating a GUI app with Tkinter, the first step is to create a window with a specific size and title. In this case, the window size should be set to 300x320 and the title should be "Currency Converter". By default, the window background color is white, and it should not be resizable. Here's the code:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Window Configuration</span>
window = Tk()
window.geometry(<span class="hljs-string">"300x320"</span>)
window.title(<span class="hljs-string">"Currency Converter"</span>)
window.configure(bg=WHITE_COLOR)
window.resizable(height=FALSE, width=FALSE)
</code></pre>
<h3 id="heading-how-to-create-the-frames">How to Create the Frames</h3>
<p>As mentioned earlier, you need to create two frames – a top frame and a main frame. The top frame will contain the application icon and title, while the main frame will include essential widgets such as labels, entry widgets, combo boxes, and the conversion button. The following code accomplishes this:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create top and main frames</span>
top_frame = Frame(window, width=<span class="hljs-number">300</span>, height=<span class="hljs-number">60</span>, bg=BLUE_COLOR)
top_frame.grid(row=<span class="hljs-number">0</span>, column=<span class="hljs-number">0</span>)

main_frame = Frame(window, width=<span class="hljs-number">300</span>, height=<span class="hljs-number">260</span>, bg=WHITE_COLOR)
main_frame.grid(row=<span class="hljs-number">1</span>, column=<span class="hljs-number">0</span>)
</code></pre>
<p>Here, the <code>Frame()</code> function is used to create the two frames. The first argument is the parent window (which is <code>window</code> in this case), followed by the width, height and background color of the frames. You can then use the <code>grid()</code> method to place the frames in the window by specifying their row and column positions.</p>
<p>You place the <code>top_frame</code> widget in the first row and first column of the grid, while the <code>main_frame</code> widget in the second row and first column of the grid.</p>
<h3 id="heading-how-to-add-widgets-in-the-top-frame">How to Add Widgets in the Top Frame</h3>
<p>Afterwards, you can create the widgets that belong to the top frame. The top frame should have an app icon and app title, as previously mentioned. You can obtain an icon from <a target="_blank" href="https://icons8.com/icons/set/exchange">Icons8</a> (or from <a target="_blank" href="https://github.com/ashutoshkrris/currency-converter-gui/blob/main/icon.png">here</a>) and save it in your project directory under the name <code>icon.png</code>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Top Frame Widgets</span>
icon_image = Image.open(<span class="hljs-string">'icon.png'</span>)
icon_image = icon_image.resize((<span class="hljs-number">40</span>, <span class="hljs-number">40</span>))
icon_image = ImageTk.PhotoImage(icon_image)
app_name_label = Label(top_frame, image=icon_image, compound=LEFT, text=<span class="hljs-string">"Currency Converter"</span>, height=<span class="hljs-number">3</span>, padx=<span class="hljs-number">13</span>, pady=<span class="hljs-number">30</span>, anchor=CENTER, font=(<span class="hljs-string">'Arial 16 bold'</span>), bg=BLUE_COLOR, fg=WHITE_COLOR)
app_name_label.place(x=<span class="hljs-number">0</span>, y=<span class="hljs-number">0</span>)
</code></pre>
<p>The code first opens the image file <code>icon.png</code> using the PIL (Python Imaging Library) module's <code>Image</code> class. It then resizes the image to a size of 40x40 using the <code>resize()</code> method. Next, it converts the image to a format that can be displayed in the GUI using the <code>ImageTk</code> module's <code>PhotoImage</code> class.</p>
<p>The next line creates a <code>Label</code> widget that displays the app icon and title. You create the widget inside the top frame. The widget takes several parameters to configure its appearance.</p>
<p>The parameters include the following:</p>
<ul>
<li>the <code>image</code> of the app icon</li>
<li>the <code>text</code> to be displayed ("Currency Converter")</li>
<li>the <code>height</code> of the label (set to 3)</li>
<li>padding on the left and top sides (set to 13 and 30, respectively)</li>
<li>the anchor point of the label (set to the center) </li>
<li>the font style (<code>Arial 16 bold</code>)</li>
<li>the background color (set to <code>BLUE_COLOR</code>)</li>
<li>the foreground color (set to <code>WHITE_COLOR</code>)</li>
</ul>
<p>Finally, we use the <code>place()</code> method to set the position of the label within the top frame. </p>
<h3 id="heading-how-to-add-widgets-in-the-main-frame">How to Add Widgets in the Main Frame</h3>
<p>As mentioned, the main frame will contain the essential widgets. Let's create them step by step.</p>
<p>The following code creates a Label widget named <code>result_label</code> inside the <code>main_frame</code> Frame. This label will display the result of the currency conversion. </p>
<pre><code class="lang-python">result_label = Label(main_frame, text=<span class="hljs-string">" "</span>, width=<span class="hljs-number">15</span>, height=<span class="hljs-number">2</span>, pady=<span class="hljs-number">7</span>, padx=<span class="hljs-number">0</span>, anchor=CENTER, font=(<span class="hljs-string">'Ivy 16 bold'</span>), bg=WHITE_COLOR, fg=BLACK_COLOR, relief=SOLID)
result_label.place(x=<span class="hljs-number">50</span>, y=<span class="hljs-number">10</span>)
</code></pre>
<p>The label has text set to an empty string (" "), a width of 15, a height of 2 lines, and padding of 7 pixels on the y-axis and 0 pixels on the x-axis. The text will be centered using the <code>anchor=CENTER</code> option, and the font used is <code>Ivy 16 bold</code>. The background color of the label is set to white (<code>bg=WHITE_COLOR</code>), and the text color is black (<code>fg=BLACK_COLOR</code>). The <code>relief</code> option is set to SOLID to give the label a border. Finally, the label is placed at the coordinates (50, 10) using the <code>place()</code> method.</p>
<p>Next, in the application design, there are two labels – "From" and "To", each followed by a <code>ComboBox</code> below it.</p>
<pre><code class="lang-python">from_label = Label(main_frame, text=<span class="hljs-string">"From"</span>, width=<span class="hljs-number">8</span>, height=<span class="hljs-number">1</span>, pady=<span class="hljs-number">0</span>, padx=<span class="hljs-number">0</span>, anchor=NW, font=(<span class="hljs-string">'Ivy 10 bold'</span>), bg=WHITE_COLOR, fg=BLACK_COLOR, relief=FLAT)
from_label.place(x=<span class="hljs-number">48</span>, y=<span class="hljs-number">90</span>)
from_combo = ttk.Combobox(main_frame, width=<span class="hljs-number">8</span>, justify=CENTER, font=(<span class="hljs-string">'Ivy 12 bold'</span>),)
from_combo[<span class="hljs-string">'values'</span>] = (get_currencies())
from_combo.current(<span class="hljs-number">0</span>)
from_combo.place(x=<span class="hljs-number">50</span>, y=<span class="hljs-number">115</span>)


to_label = Label(main_frame, text=<span class="hljs-string">"To"</span>, width=<span class="hljs-number">8</span>, height=<span class="hljs-number">1</span>, pady=<span class="hljs-number">0</span>, padx=<span class="hljs-number">0</span>, anchor=NW, font=(<span class="hljs-string">'Ivy 10 bold'</span>), bg=WHITE_COLOR, fg=BLACK_COLOR, relief=FLAT)
to_label.place(x=<span class="hljs-number">158</span>, y=<span class="hljs-number">90</span>)
to_combo = ttk.Combobox(main_frame, width=<span class="hljs-number">8</span>, justify=CENTER, font=(<span class="hljs-string">'Ivy 12 bold'</span>),)
to_combo[<span class="hljs-string">'values'</span>] = (get_currencies())
to_combo.current(<span class="hljs-number">1</span>)
to_combo.place(x=<span class="hljs-number">160</span>, y=<span class="hljs-number">115</span>)
</code></pre>
<p>The first <code>Label</code> and <code>ComboBox</code> are for the currency to convert from. You create the label using the <code>Label()</code> function with the specified text, width, height, padding, font, and color settings. The Label is then placed in the main frame at the specified coordinates using the place() function. </p>
<p>You then create a <code>ComboBox</code> using the <code>ttk.Combobox()</code> function with the specified width, font, and justification settings. The available values for the <code>ComboBox</code> are set using the <code>get_currencies()</code> function (imported from <code>utils.py</code>), and the default value is set to the first item in the list using the <code>current()</code> function. The <code>ComboBox</code> is also placed in the main frame at the specified coordinates using the <code>place()</code> function.</p>
<p>The second Label and ComboBox are for the currency to convert to. The Label and ComboBox are created and placed in a similar way to the first Label and ComboBox, with the only difference being the text and placement coordinates.</p>
<p>The last two widgets in the application design are the input field and the convert button. You can use the <code>Entry()</code> method to create the input field. It takes several parameters including <code>width</code>, <code>justify</code>, <code>font</code>, and <code>relief</code>. The created widget is then placed using the <code>place()</code> method with specific coordinates on the main frame.</p>
<p>Similarly, the convert button is created using the <code>Button()</code> method. It takes several parameters such as <code>text</code>, <code>width</code>, <code>height</code>, <code>bg</code>, <code>fg</code>, <code>font</code>, and <code>command</code>. The created button is then placed using the <code>place()</code> method with specific coordinates on the main frame.</p>
<p>Here's the code to create the input field and convert button:</p>
<pre><code class="lang-python">amount_entry = Entry(main_frame, width=<span class="hljs-number">22</span>, justify=CENTER,
                    font=(<span class="hljs-string">'Ivy 12 bold'</span>), relief=SOLID)
amount_entry.place(x=<span class="hljs-number">50</span>, y=<span class="hljs-number">155</span>)

convert_button = Button(main_frame, text=<span class="hljs-string">"Convert"</span>, width=<span class="hljs-number">19</span>, padx=<span class="hljs-number">5</span>,
                        height=<span class="hljs-number">1</span>, bg=BLUE_COLOR, fg=WHITE_COLOR, font=(<span class="hljs-string">'Ivy 12 bold'</span>), command=convert)
convert_button.place(x=<span class="hljs-number">50</span>, y=<span class="hljs-number">210</span>)
</code></pre>
<p>The <code>command</code> parameter in the <code>convert_button</code> widget takes a function name. In this case, it's set to <code>convert</code>. But the <code>convert</code> function has not been defined yet. To define it, you can add the following code just before the window is defined:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">convert</span>():</span>
    amount = float(amount_entry.get())
    from_currency = from_combo.get()
    to_currency = to_combo.get()
    converted_amount = convert_currency(from_currency, to_currency, amount)

    result_label[<span class="hljs-string">'text'</span>] = <span class="hljs-string">f'<span class="hljs-subst">{to_currency}</span> <span class="hljs-subst">{converted_amount:<span class="hljs-number">.2</span>f}</span>'</span>
</code></pre>
<p>The <code>convert</code> function takes the user input from the <code>amount_entry</code> widget and the selected currencies from the <code>from_combo</code> and <code>to_combo</code> widgets, and passes them to the <code>convert_currency</code> function(imported from <code>utils.py</code>) to obtain the converted amount. It then sets the value of  <code>text</code> to the exchanged value in the <code>result_label</code> widget.</p>
<p>Finally, you call the <code>mainloop()</code> method at the end of the file. The method is responsible for running the application and continuously checking for user events, such as mouse clicks, keyboard inputs, and window resizing, and updating the window as necessary. </p>
<p>Once the <code>mainloop()</code> method is called, the program enters into the event loop and starts waiting for user events. The window will remain open and active until the user closes the window or the program is terminated.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Mainloop</span>
window.mainloop()
</code></pre>
<h2 id="heading-final-code">Final Code</h2>
<p>Here is the final code for the Currency Converter GUI application that you have been building. This code incorporates all the different components we have discussed so far, including creating frames, labels, combo boxes, entry fields, and buttons.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> tkinter <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> tkinter <span class="hljs-keyword">import</span> Tk, ttk

<span class="hljs-keyword">from</span> PIL <span class="hljs-keyword">import</span> Image, ImageTk

<span class="hljs-keyword">from</span> utils <span class="hljs-keyword">import</span> convert_currency, get_currencies

<span class="hljs-comment"># Colors</span>
WHITE_COLOR = <span class="hljs-string">"#FFFFFF"</span>
BLACK_COLOR = <span class="hljs-string">"#333333"</span>
BLUE_COLOR = <span class="hljs-string">"#0000FF"</span>


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">convert</span>():</span>
    amount = float(amount_entry.get())
    from_currency = from_combo.get()
    to_currency = to_combo.get()
    converted_amount = convert_currency(from_currency, to_currency, amount)

    result_label[<span class="hljs-string">'text'</span>] = <span class="hljs-string">f'<span class="hljs-subst">{to_currency}</span> <span class="hljs-subst">{converted_amount:<span class="hljs-number">.2</span>f}</span>'</span>


<span class="hljs-comment"># Window Configuration</span>
window = Tk()
window.geometry(<span class="hljs-string">"300x320"</span>)
window.title(<span class="hljs-string">"Currency Converter"</span>)
window.configure(bg=WHITE_COLOR)
window.resizable(height=FALSE, width=FALSE)


<span class="hljs-comment"># Frames</span>
top_frame = Frame(window, width=<span class="hljs-number">300</span>, height=<span class="hljs-number">60</span>, bg=BLUE_COLOR)
top_frame.grid(row=<span class="hljs-number">0</span>, column=<span class="hljs-number">0</span>)

main_frame = Frame(window, width=<span class="hljs-number">300</span>, height=<span class="hljs-number">260</span>, bg=WHITE_COLOR)
main_frame.grid(row=<span class="hljs-number">1</span>, column=<span class="hljs-number">0</span>)


<span class="hljs-comment"># Top Frame Widgets</span>
icon_image = Image.open(<span class="hljs-string">'icon.png'</span>)
icon_image = icon_image.resize((<span class="hljs-number">40</span>, <span class="hljs-number">40</span>))
icon_image = ImageTk.PhotoImage(icon_image)
app_name_label = Label(top_frame, image=icon_image, compound=LEFT, text=<span class="hljs-string">"Currency Converter"</span>, height=<span class="hljs-number">3</span>, padx=<span class="hljs-number">13</span>, pady=<span class="hljs-number">30</span>, anchor=CENTER, font=(<span class="hljs-string">'Arial 16 bold'</span>), bg=BLUE_COLOR, fg=WHITE_COLOR)
app_name_label.place(x=<span class="hljs-number">0</span>, y=<span class="hljs-number">0</span>)

<span class="hljs-comment"># Main Frame Widgets</span>
result_label = Label(main_frame, text=<span class="hljs-string">" "</span>, width=<span class="hljs-number">15</span>, height=<span class="hljs-number">2</span>, pady=<span class="hljs-number">7</span>, padx=<span class="hljs-number">0</span>, anchor=CENTER, font=(<span class="hljs-string">'Ivy 16 bold'</span>), bg=WHITE_COLOR, fg=BLACK_COLOR, relief=SOLID)
result_label.place(x=<span class="hljs-number">50</span>, y=<span class="hljs-number">10</span>)

from_label = Label(main_frame, text=<span class="hljs-string">"From"</span>, width=<span class="hljs-number">8</span>, height=<span class="hljs-number">1</span>, pady=<span class="hljs-number">0</span>, padx=<span class="hljs-number">0</span>, anchor=NW, font=(<span class="hljs-string">'Ivy 10 bold'</span>), bg=WHITE_COLOR, fg=BLACK_COLOR, relief=FLAT)
from_label.place(x=<span class="hljs-number">48</span>, y=<span class="hljs-number">90</span>)
from_combo = ttk.Combobox(main_frame, width=<span class="hljs-number">8</span>, justify=CENTER, font=(<span class="hljs-string">'Ivy 12 bold'</span>),)
from_combo[<span class="hljs-string">'values'</span>] = (get_currencies())
from_combo.current(<span class="hljs-number">0</span>)
from_combo.place(x=<span class="hljs-number">50</span>, y=<span class="hljs-number">115</span>)

to_label = Label(main_frame, text=<span class="hljs-string">"To"</span>, width=<span class="hljs-number">8</span>, height=<span class="hljs-number">1</span>, pady=<span class="hljs-number">0</span>, padx=<span class="hljs-number">0</span>, anchor=NW, font=(<span class="hljs-string">'Ivy 10 bold'</span>), bg=WHITE_COLOR, fg=BLACK_COLOR, relief=FLAT)
to_label.place(x=<span class="hljs-number">158</span>, y=<span class="hljs-number">90</span>)
to_combo = ttk.Combobox(main_frame, width=<span class="hljs-number">8</span>, justify=CENTER, font=(<span class="hljs-string">'Ivy 12 bold'</span>),)
to_combo[<span class="hljs-string">'values'</span>] = (get_currencies())
to_combo.current(<span class="hljs-number">1</span>)
to_combo.place(x=<span class="hljs-number">160</span>, y=<span class="hljs-number">115</span>)

amount_entry = Entry(main_frame, width=<span class="hljs-number">22</span>, justify=CENTER,
                    font=(<span class="hljs-string">'Ivy 12 bold'</span>), relief=SOLID)
amount_entry.place(x=<span class="hljs-number">50</span>, y=<span class="hljs-number">155</span>)

convert_button = Button(main_frame, text=<span class="hljs-string">"Convert"</span>, width=<span class="hljs-number">19</span>, padx=<span class="hljs-number">5</span>,
                        height=<span class="hljs-number">1</span>, bg=BLUE_COLOR, fg=WHITE_COLOR, font=(<span class="hljs-string">'Ivy 12 bold'</span>), command=convert)
convert_button.place(x=<span class="hljs-number">50</span>, y=<span class="hljs-number">210</span>)

<span class="hljs-comment"># Mainloop</span>
window.mainloop()
</code></pre>
<p>You can finally run the application and start converting currencies!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to create a simple currency converter application using Python and Tkinter. We covered topics such as creating frames, labels, entry widgets, combo boxes, and buttons. You also created a function to convert currencies based on the user's input. </p>
<p>There are several ways to improve this application. You can improve the user interface to look more attractive, add a feature to save the conversion history, and much more.</p>
<p>If you've followed along with this tutorial and built your own Currency Converter application, I encourage you to share your creation with the world! Take a screenshot or record a video of your application in action, and share it on Twitter. Be sure to tag me, <a target="_blank" href="https://twitter.com/ashutoshkrris">@ashutoshkrris</a>, so that I can see your work and share it with my followers.</p>
<p>I can't wait to see what you've created! Happy coding!</p>
<h3 id="heading-additional-resources">Additional Resources</h3>
<ul>
<li><a target="_blank" href="https://github.com/ashutoshkrris/currency-converter-gui">Github repository</a> for the tutorial</li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=YXPyB4XeYLA">Create Graphic User Interfaces in Python Tutorial</a></li>
<li><a target="_blank" href="https://blog.ashutoshkrris.in/how-to-interact-with-web-services-using-python">How to interact with web services in Python</a></li>
<li><a target="_blank" href="https://currencyapi.com/docs">Currency Conversion API Documentation</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
