<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The Infinity Reads!]]></title><description><![CDATA[The Infinity Reads!]]></description><link>https://tech.anantdubey.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Apr 2026 05:25:11 GMT</lastBuildDate><atom:link href="https://tech.anantdubey.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Git Merge: A to Z]]></title><description><![CDATA[Merging in Git sounds simple, and it can be…but if you've ever ended up in a weird conflict, a detached HEAD, or a tangled rebase, you know it's not always smooth.
This post is a practical guide to merging in Git, covering what it actually does, when...]]></description><link>https://tech.anantdubey.com/git-merge</link><guid isPermaLink="true">https://tech.anantdubey.com/git-merge</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Git]]></category><category><![CDATA[GitLab]]></category><category><![CDATA[merge-conflict]]></category><dc:creator><![CDATA[Anant Dubey]]></dc:creator><pubDate>Wed, 02 Apr 2025 02:30:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743532930968/ba288a00-1d21-4ca3-8c8c-2c214219c378.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Merging in Git sounds simple, and it <em>can</em> be…but if you've ever ended up in a weird conflict, a detached HEAD, or a tangled rebase, you know it's not always smooth.</p>
<p>This post is a practical guide to <strong>merging in Git</strong>, covering what it actually does, when to use it, how it compares to rebase, and what to do when things go wrong.</p>
<h2 id="heading-what-is-a-merge-really">What is a Merge, really? 🤨</h2>
<p>In Git, merging is how you take changes from one branch and combine them into another.</p>
<pre><code class="lang-bash">git checkout main
git merge feature/login-page
</code></pre>
<p>This tells Git: “Take everything from <code>feature/login-page</code> and bring it into <code>main</code>.”</p>
<p>Behind the scenes, Git tries to find a <strong>common ancestor</strong> of the two branches, figures out the differences, and applies the changes. If nothing conflicts — <mark>you're golden</mark>.</p>
<hr />
<h2 id="heading-types-of-merges">Types of Merges</h2>
<h3 id="heading-1-fast-forward-merge">1. Fast-Forward Merge</h3>
<p>Happens when the branch you're merging into is directly behind the other one. No actual “merge commit” is needed.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># main is behind feature</span>
git checkout main
git merge feature
</code></pre>
<p>Result: <code>main</code> just moves its pointer forward. That’s it.</p>
<blockquote>
<p>🔍 Tip: You can force Git to <em>not</em> fast-forward and create a merge commit:</p>
</blockquote>
<pre><code class="lang-bash">git merge --no-ff feature
</code></pre>
<p>Useful for preserving the branch history explicitly.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Preserving branch history</strong> means keeping a clear, visible record of where a branch came from and how it was merged into the main codebase, usually by creating a merge commit instead of squashing or fast-forwarding, so the full development path stays in the Git log.</div>
</div>

<h3 id="heading-2-three-way-merge">2. <strong>Three-Way Merge</strong></h3>
<p>If the target branch has diverged, Git creates a merge commit. This is what you usually see in shared repos:</p>
<pre><code class="lang-bash">git checkout main
git merge feature
<span class="hljs-comment"># creates a merge commit</span>
</code></pre>
<p>This merge commit has <strong>two parents</strong>, connecting the branches.</p>
<p><strong><mark>A bit more on three-way merge in detail:</mark></strong></p>
<p>When you do a <strong>three-way merge</strong> in Git, it means the two branches you're trying to combine, for example, <code>main</code> and <code>feature</code>, have diverged. They’ve both had new commits since their common ancestor.</p>
<p>Git then performs a three-way comparison:</p>
<ol>
<li><p>The common ancestor commits</p>
</li>
<li><p>The latest commit on <code>main</code></p>
</li>
<li><p>The latest commit on <code>feature</code></p>
</li>
</ol>
<p>It uses these to generate a new commit that brings both branches together. This is the <strong>merge commit</strong>, and it has <strong>two parent commits</strong>: one from <code>main</code>, one from <code>feature</code>.</p>
<p>This merge commit acts as a clear record in the Git history that the two lines of development were combined at that point, preserving the full history of both branches. This is especially useful in collaborative projects, where seeing the origin of a feature or bugfix matters later on.</p>
<p>It’s the opposite of a <strong>fast-forward merge</strong>, which just moves the pointer forward and skips the merge commit because there was no divergence.</p>
<hr />
<h2 id="heading-merge-rebase">Merge 🆚 Rebase</h2>
<h3 id="heading-what-is-rebase-really">What is Rebase (Really)?</h3>
<p><code>git rebase</code> lets you <strong>move the base of your current branch to a new starting point</strong>, usually to sync with the latest changes from another branch like <code>main</code>.</p>
<p>Instead of merging and creating a new commit that combines both histories (like <code>git merge</code>), rebase <strong>replays your commits one by one</strong> on top of the latest changes.</p>
<h3 id="heading-example">Example</h3>
<p>Let’s say your branch history looks like this:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">A---B---C</span>  (<span class="hljs-selector-tag">main</span>)
     \
      <span class="hljs-selector-tag">D---E---F</span>  (<span class="hljs-selector-tag">feature</span>)
</code></pre>
<p>You run:</p>
<pre><code class="lang-bash">git checkout feature
git rebase main
</code></pre>
<p>Now Git will:</p>
<ol>
<li><p>Take your commits <code>D</code>, <code>E</code>, and <code>F</code></p>
</li>
<li><p>“Replay” them on top of <code>C</code> (the latest on <code>main</code>)</p>
</li>
</ol>
<p>Result:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">A---B---C---D</span>'<span class="hljs-selector-tag">---E</span>'<span class="hljs-selector-tag">---F</span>'  (<span class="hljs-selector-tag">feature</span>)
</code></pre>
<p>Your feature branch is now cleaner and sits <em>on top</em> of <code>main</code>, as if you started from the latest <code>main</code> from the beginning.</p>
<p><em>Let’s clear this up ——— same goal, different methods:</em></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Command</strong></td><td><strong>What It Does</strong></td><td><strong>History</strong></td></tr>
</thead>
<tbody>
<tr>
<td><code>git merge</code></td><td>Combines branches with a new merge commit</td><td>Keeps both branch histories</td></tr>
<tr>
<td><code>git rebase</code></td><td>Moves your commits on top of another branch</td><td>Creates linear history, rewrites commit</td></tr>
</tbody>
</table>
</div><h3 id="heading-why-rebase"><strong>Why Rebase?</strong></h3>
<ul>
<li><p><strong>Keeps history clean</strong> and linear</p>
</li>
<li><p><strong>No extra merge commits</strong></p>
</li>
<li><p>Makes it look like your work was built on top of the latest code all along</p>
</li>
</ul>
<p>Great for personal branches or PRs you haven’t pushed yet.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Rebasing <strong>changes commit hashes</strong>, because it’s creating <em>new</em> commits with the same changes. So: 1. Never rebase a branch that other people are already working off of or have pulled. 2. Use it for local cleanup, not for shared history.</div>
</div>

<hr />
<h2 id="heading-handling-merge-conflicts">Handling Merge Conflicts 🧨</h2>
<p>You’ll eventually hit this:</p>
<pre><code class="lang-bash">CONFLICT (content): Merge conflict <span class="hljs-keyword">in</span> lib/ui.dart
Automatic merge failed; fix conflicts and commit the result.
</code></pre>
<h3 id="heading-steps">Steps:</h3>
<p>Git marks conflict areas like this:</p>
<pre><code class="lang-diff">&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
code from current branch
<span class="hljs-comment">=======</span>
code from merging branch
&gt;&gt;&gt;&gt;&gt;&gt;&gt; feature-branch
</code></pre>
<p>Manually fix the file.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Stage it:</span>
git add lib/ui.dart
<span class="hljs-comment"># Complete the merge:</span>
git commit
</code></pre>
<p><strong>!</strong> You can also abort a merge entirely:</p>
<pre><code class="lang-bash">git merge --abort
</code></pre>
<h3 id="heading-merge-strategy-options">Merge Strategy Options</h3>
<p>Rarely used, but good to know:</p>
<ul>
<li><p><code>--strategy=recursive</code> (default)</p>
</li>
<li><p><code>--strategy=ours</code> – Favor your branch in conflicts</p>
</li>
<li><p><code>--strategy=theirs</code> – Favor incoming branch (use with caution)</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-bash">git merge feature --strategy=ours
</code></pre>
<hr />
<h2 id="heading-merge-workflows-in-real-projects">Merge Workflows in Real Projects</h2>
<h3 id="heading-feature-branch-flow">🚀 Feature Branch Flow</h3>
<ul>
<li><p>Devs create a feature branch</p>
</li>
<li><p>Open PRs</p>
</li>
<li><p>Merge to <code>main</code> (with <code>--no-ff</code> or via GitHub squash/merge)</p>
</li>
</ul>
<p>This keeps <code>main</code> clean and stable.</p>
<h3 id="heading-release-branch-flow">📦 Release Branch Flow</h3>
<ul>
<li><p>Merge <code>main</code> into <code>release-v1.0</code></p>
</li>
<li><p>Cherry-pick hotfixes into both <code>main</code> and <code>release-v1.0</code></p>
</li>
</ul>
<hr />
<h2 id="heading-merge-vs-squash-vs-rebase-in-prs">Merge vs Squash vs Rebase in PRs</h2>
<p>On GitHub, you’ll see:</p>
<ul>
<li><p><strong>Merge Commit</strong>: Keeps full branch history</p>
</li>
<li><p><strong>Squash and Merge</strong>: Combines all feature branch commits into one</p>
</li>
<li><p><strong>Rebase and Merge</strong>: Replays commits for linear history</p>
</li>
</ul>
<p>Each has trade-offs. Squashing keeps history clean but loses individual commits. Rebase keeps order but changes hashes.</p>
<hr />
<h2 id="heading-merge-mistakes-and-how-to-fix">Merge Mistakes and How to Fix</h2>
<h3 id="heading-1-merged-the-wrong-branch">1. <strong>Merged the wrong branch?</strong></h3>
<pre><code class="lang-bash">git reset HEAD~1
</code></pre>
<h3 id="heading-2-conflict-hell">2. <strong>Conflict hell?</strong></h3>
<pre><code class="lang-bash">git merge --abort
</code></pre>
<p>Or nuke and pull fresh:</p>
<pre><code class="lang-bash">git reset --hard origin/main
</code></pre>
<h3 id="heading-3-stuck-in-merge-with-uncommitted-changes">3. <strong>Stuck in merge with uncommitted changes?</strong></h3>
<pre><code class="lang-bash">git stash
git merge branch
</code></pre>
<hr />
<h2 id="heading-heres-a-complementary-git-cheat-sheet">Here’s a complementary Git Cheat Sheet 🎀</h2>
<p><a target="_blank" href="https://education.github.com/git-cheat-sheet-education.pdf"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743532126046/60449ea3-1251-4741-ad60-eb1816535aeb.jpeg" alt="Git Cheat Sheet" class="image--center mx-auto" /></a></p>
<p><a target="_blank" href="https://education.github.com/git-cheat-sheet-education.pdf"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743532167579/cf65973c-aa22-41f2-8ed2-11ad8ceb82e0.jpeg" alt="Git Cheat Sheet" class="image--center mx-auto" /></a></p>
<p><a target="_blank" href="https://education.github.com/git-cheat-sheet-education.pdf">Link</a> 👈 to the original PDF in case these images don’t load.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Merging in Git isn’t rocket science…but it gets tricky fast when you're juggling branches, features, hotfixes, and multiple devs.</p>
<p>If you keep these things in mind:</p>
<ul>
<li><p>Know when to merge vs rebase</p>
</li>
<li><p>Don’t fear merge conflicts, just learn to resolve them</p>
</li>
<li><p>Use <code>--no-ff</code> to make merge history explicit</p>
</li>
<li><p>And always keep your <code>main</code> branch clean and deployable</p>
</li>
</ul>
<p>…you’ll be fine.</p>
<p><strong>Got a Git horror story or a tip? Drop it in the comments.</strong></p>
<p>Happy merging 👊</p>
<hr />
<h2 id="heading-thank-you"><strong>Thank you</strong></h2>
<p>Did you reach the bottom? <strong><em><mark>Thank you for reading!</mark></em></strong></p>
<p>Feel free to <a target="_blank" href="https://www.anantdubey.com/"><strong>connect with me</strong></a>. 👋</p>
]]></content:encoded></item><item><title><![CDATA[Why I Use Supabase for MVPs (and beyond)]]></title><description><![CDATA[When you’re building MVPs, speed matters — but so does flexibility. You want a backend that’s fast to set up but doesn’t fall apart the moment your product grows.
Over the last couple of years, I’ve built several MVPs using Flutter for mobile and Rea...]]></description><link>https://tech.anantdubey.com/why-i-use-supabase</link><guid isPermaLink="true">https://tech.anantdubey.com/why-i-use-supabase</guid><category><![CDATA[tech ]]></category><category><![CDATA[supabase]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Databases]]></category><category><![CDATA[mvp]]></category><category><![CDATA[Firebase]]></category><category><![CDATA[Flutter]]></category><dc:creator><![CDATA[Anant Dubey]]></dc:creator><pubDate>Mon, 31 Mar 2025 06:31:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743401938804/b8803e60-4d1e-4b95-8618-362674411771.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you’re building MVPs, <em><mark>speed</mark></em> matters — but so does flexibility. You want a backend that’s fast to set up but doesn’t fall apart the moment your product grows.</p>
<p>Over the last couple of years, I’ve built several MVPs using Flutter for mobile and React/Next.js for web. And after trying Firebase, Hasura, and even rolling my own Express APIs, I eventually settled into a rhythm with <strong>Supabase</strong>. <strong>✨</strong></p>
<p>Here’s why.</p>
<h2 id="heading-the-real-need-fast-flexible-and-reliable">The Real Need: Fast, Flexible, and Reliable</h2>
<p>As a solo dev or small team, I don’t want to spend weeks managing auth flows or spinning up a custom backend just to persist a list of data.</p>
<p>At the same time, I also want:</p>
<ul>
<li><p>Full control over data relationships</p>
</li>
<li><p>SQL-style querying</p>
</li>
<li><p>Auth with RLS (Row-Level Security)</p>
</li>
<li><p>Built-in Realtime (for live lists, chats, etc.)</p>
</li>
<li><p>A database I can export and query like a grown-up (Postgres)</p>
</li>
</ul>
<p>Supabase hits that sweet spot.</p>
<h2 id="heading-the-stack-i-usually-work-with">The Stack I Usually Work With</h2>
<ul>
<li><p><strong>Frontend (Web)</strong>: React + Next.js</p>
</li>
<li><p><strong>Frontend (Mobile)</strong>: Flutter</p>
</li>
<li><p><strong>Backend</strong>: Supabase (Auth + Postgres + Realtime + Edge Functions)</p>
</li>
<li><p><strong>Deployment</strong>: Vercel (for Web), Play Store/TestFlight (for Flutter)</p>
</li>
</ul>
<p>Let’s look at how Supabase fits into that, with a practical example.</p>
<hr />
<h2 id="heading-real-example-a-real-time-list-app">Real Example: A Real-Time List App</h2>
<p>Let’s say I’m building a “Live Guest List” web-app.</p>
<ul>
<li><p>Anyone can add their name to a shared list.</p>
</li>
<li><p>The list updates in real time for all users.</p>
</li>
<li><p>Items expire after 7 days.</p>
</li>
</ul>
<p>With Supabase, the backend is almost entirely done out-of-the-box.</p>
<h3 id="heading-backend-supabase-setup">Backend: Supabase Setup</h3>
<h4 id="heading-1-database-table">1. <strong>Database Table</strong></h4>
<p>We create a <code>guests</code> table in Postgres:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Column</strong></td><td><strong>Type</strong></td></tr>
</thead>
<tbody>
<tr>
<td>id</td><td>UUID</td></tr>
<tr>
<td>name</td><td>TEXT</td></tr>
<tr>
<td>created_at</td><td>TIMESTAMP</td></tr>
</tbody>
</table>
</div><p>Set a policy to auto-delete rows after 7 days using PostgreSQL's <code>ttl</code> cron or a scheduled function (Supabase supports this).</p>
<h4 id="heading-2-row-level-security-rls">2. <strong>Row-Level Security (RLS)</strong></h4>
<p>We enable RLS and create a simple policy:</p>
<pre><code class="lang-pgsql"><span class="hljs-comment">-- Anyone can insert</span>
<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> "Public insert" <span class="hljs-keyword">on</span> guests
<span class="hljs-keyword">for</span> <span class="hljs-keyword">insert</span>
<span class="hljs-keyword">using</span> (<span class="hljs-keyword">true</span>);
</code></pre>
<h4 id="heading-3-enable-realtime">3. <strong>Enable Realtime</strong></h4>
<p>Turn on "Realtime" for the <code>guests</code> table in the Supabase dashboard — this allows us to listen to any <code>INSERT</code> events and push updates to clients in real time.</p>
<h3 id="heading-frontend-nextjs-live-list-display">Frontend (Next.js) – Live List Display</h3>
<p>Let’s walk through how data flows, using a simplified version of my actual MVP.</p>
<p>The core hook is <code>useListData.js</code>, which:</p>
<ul>
<li><p>Fetches the initial list from Supabase</p>
</li>
<li><p>Subscribes to real-time updates</p>
</li>
<li><p>Updates the UI accordingly</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">'./supabase'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useListData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [list, setList] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetchInitial();

    <span class="hljs-keyword">const</span> sub = supabase
      .channel(<span class="hljs-string">'public:guests'</span>)
      .on(<span class="hljs-string">'postgres_changes'</span>, { <span class="hljs-attr">event</span>: <span class="hljs-string">'INSERT'</span>, <span class="hljs-attr">schema</span>: <span class="hljs-string">'public'</span>, <span class="hljs-attr">table</span>: <span class="hljs-string">'guests'</span> }, <span class="hljs-function">(<span class="hljs-params">payload</span>) =&gt;</span> {
        setList(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> [payload.new, ...prev]);
      })
      .subscribe();

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      supabase.removeChannel(sub);
    };
  }, []);

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchInitial</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> supabase.from(<span class="hljs-string">'guests'</span>).select(<span class="hljs-string">'*'</span>).order(<span class="hljs-string">'created_at'</span>, { <span class="hljs-attr">ascending</span>: <span class="hljs-literal">false</span> });
    setList(data);
  }

  <span class="hljs-keyword">return</span> list;
}
</code></pre>
<p>In the <code>page.js</code> file (or <code>[id].js</code> in Next’s route), we simply call <code>useListData()</code> and map it to components like <code>NamesList.jsx</code>.</p>
<p>The beauty is: <strong>no need to manage sockets yourself</strong>. Supabase handles it.</p>
<p>Here’s the full version of my MVPs data flow:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743400831277/c86a6ccb-caa0-43fb-bd06-df8f8ea04561.png" alt class="image--center mx-auto" /></p>
<p>No Firebase Firestore triggers, no polling. Just clean Postgres + WebSocket events.</p>
<p>You can check out its <a target="_blank" href="https://github.com/dubeyanant/link-list">GitHub</a> and <a target="_blank" href="https://linklist.anant.ink/">live hosted link</a>.</p>
<hr />
<h2 id="heading-firebase-vs-supabase-in-the-mvp-world">Firebase vs Supabase: In the MVP World</h2>
<p>Firebase is great for:</p>
<ul>
<li><p>Fast auth integration</p>
</li>
<li><p>Push notifications (out-of-the-box with Firebase Messaging)</p>
</li>
<li><p>Small prototypes that don’t need relational querying</p>
</li>
</ul>
<p>But here’s where it didn’t scale for my use:</p>
<ul>
<li><p><strong>No SQL</strong>: Firestore’s querying is shallow. Deep filters or joins get messy fast.</p>
</li>
<li><p><strong>Pricing surprises</strong>: You get billed per read — real-time features spike usage.</p>
</li>
<li><p><strong>Data modeling</strong>: Firestore pushes you into NoSQL patterns, which are harder to maintain if your schema grows.</p>
</li>
</ul>
<h2 id="heading-what-supabase-gets-right">What Supabase Gets Right</h2>
<p>✅ <strong>Postgres, not NoSQL</strong><br />I can design my schema like I would in a production app. Joins, indexes, foreign keys — everything works as expected.</p>
<p>✅ <strong>Row-Level Security</strong><br />Secure your app directly in SQL. No extra backend logic needed.</p>
<p>✅ <strong>Realtime Built-In</strong><br />Turn it on per table. No extra infra or Firebase-style "watchDocument" logic.</p>
<p>✅ <strong>One SDK, Multi-Platform</strong><br />Supabase works equally well in web and mobile. You can even use it from a server or CLI tool.</p>
<p>✅ <strong>Edge Functions</strong><br />Need to send an email or call an external API? Edge functions make it easy — no extra backend server required.</p>
<p>✅ <strong>Self-Hosting Option</strong><br />If I need to move off Supabase for compliance or scaling, I can take the whole stack with me. It’s just Postgres + some open-source tooling.</p>
<h2 id="heading-what-could-be-better">What Could Be Better</h2>
<p>🔸 <strong>Built-in Push Notifications</strong><br />Firebase handles push with FCM. Supabase doesn’t have this out of the box — you’ll need to integrate a service like OneSignal or Firebase Cloud Messaging separately.</p>
<p>🔸 <strong>Docs for Advanced Features</strong><br />Sometimes edge cases (especially around auth + RLS + Realtime) need digging through GitHub issues to fully understand.</p>
<hr />
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Supabase is not just a Firebase alternative — it’s a solid choice in its own right, especially if you come from a SQL background or want more control over your backend.</p>
<p>For MVPs, it removes the need to spin up a server or write repetitive boilerplate just to handle auth or data.</p>
<p>For production apps, it’s robust enough to grow with you — and flexible enough to take with you if you ever need to scale out.</p>
<p>If you're building apps with Flutter or React/Next.js and want a backend that handles real-time data, secure auth, and doesn’t get in your way — Supabase is worth your time.</p>
<hr />
<h2 id="heading-thank-you"><strong>Thank you</strong></h2>
<p>Did you reach the bottom? <strong><em><mark>Thank you for reading!</mark></em></strong></p>
<p>Feel free to <a target="_blank" href="https://www.anantdubey.com/">connect with me</a>. 👋</p>
]]></content:encoded></item><item><title><![CDATA[Creating pinned shortcuts in Flutter!]]></title><description><![CDATA[Introduction
There are three types of shortcuts in Android that can be implemented in Flutter: static, dynamic, and pinned. You can read more about these shortcuts in the Android documentation by clicking here.

In this article, we are going to creat...]]></description><link>https://tech.anantdubey.com/pinned-shortcuts-in-flutter</link><guid isPermaLink="true">https://tech.anantdubey.com/pinned-shortcuts-in-flutter</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Android]]></category><category><![CDATA[Kotlin]]></category><dc:creator><![CDATA[Anant Dubey]]></dc:creator><pubDate>Thu, 21 Mar 2024 11:42:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743618413036/c6ed8561-78b9-4a79-a37f-e8e883225be1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>There are three types of shortcuts in Android that can be implemented in Flutter: static, dynamic, and pinned. You can read more about these shortcuts in the Android documentation by clicking <a target="_blank" href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts">here</a>.</p>
<p><img src="https://developer.android.com/static/images/guide/topics/ui/shortcuts/pinned-shortcuts.png" alt class="image--center mx-auto" /></p>
<p>In this article, we are going to create pinned shortcuts in Flutter. We will see this example for the use case where we'll launch a different screen if clicked on the pinned shortcut instead of the home screen, which opens by default in the app.</p>
<p>As there is no direct provision for creating pinned shortcuts in Flutter, we are going to use native bridge (platform channels) between Flutter and Android Native to establish two-way communication. I'll not be going in depth on the creation of platform channels for data transfer, but you can see the full approach with code in my previous article <a target="_blank" href="https://anantdubey.hashnode.dev/native-bridge">here</a>.</p>
<p><strong>Note</strong> that I'll be using Kotlin as my native Android language.</p>
<h2 id="heading-approach">Approach</h2>
<ol>
<li><p>Establish a native bridge between Flutter and Android.</p>
</li>
<li><p>Send an identifier from Flutter to Android.</p>
</li>
<li><p>Create a pinned shortcut using the previous identifier.</p>
</li>
<li><p>Send a call back to Flutter if the pinned shortcut is clicked.</p>
</li>
<li><p>Inflate a screen using that callback in Flutter.</p>
</li>
</ol>
<h3 id="heading-steps-in-detail">Steps in detail</h3>
<p><strong>Step 0: Project starting point</strong></p>
<p>Before creating any pinned shortcuts, we will essentially create a starting point. Click <a target="_blank" href="https://github.com/dubeyanant/pinned_shortcuts/tree/a50a56850ded99e957705b654786b4ef79aa8841">here</a> for the initial code I will be using. Don't worry if you do not want to fork the repository; its lib folder only has the files <code>main.dart</code> and <code>home.dart</code>.</p>
<p>The <code>main.dart</code> file contains the basic structure of the <code>MaterialApp</code>.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="58a43263745085ebbe513ac6fbe56f60"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/inanant/58a43263745085ebbe513ac6fbe56f60" class="embed-card">https://gist.github.com/inanant/58a43263745085ebbe513ac6fbe56f60</a></div><p> </p>
<p>The <code>home.dart</code> files contain the <code>HomeScreen</code> widget, which has a button whose <code>onTap</code> takes users to an <code>AnotherScreen</code> widget with plain text; <code>onLongPress</code> is currently an empty function.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="82fb0db54832e2b14859a83020d9022f"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/inanant/82fb0db54832e2b14859a83020d9022f" class="embed-card">https://gist.github.com/inanant/82fb0db54832e2b14859a83020d9022f</a></div><p> </p>
<p><strong>Step 1 &amp; 2: Create platform channels and send an identifier</strong></p>
<p>To determine which screen to open, we will transfer a string using a native bridge that connects Flutter and Android. You can use any type of identifier, such as a string, integer, or bool, based on your use case. Although we only have one screen at the moment, sending distinct identifiers when making distinct pinned shortcuts is crucial to determining what action should happen when a given shortcut is clicked.</p>
<p>We'll be manipulating <code>MainActivity.kt</code> and <code>home.dart</code> files in order to do this.</p>
<p>In <code>MainActivity.kt</code>, we'll write a method channel to receive the information that is passed from Flutter. It is done by overriding the <code>configureFlutterEngine</code> function to receive the data and creating a function to actually use that data to create a pinned shortcut. For now, we'll use the <code>getNativeData</code> function just to return the data we received.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="cb0179b5e738a1f0dccf279728c32e61"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/inanant/cb0179b5e738a1f0dccf279728c32e61" class="embed-card">https://gist.github.com/inanant/cb0179b5e738a1f0dccf279728c32e61</a></div><p> </p>
<p>Also, we will create a <code>NativeBridge</code> class in the <code>home.dart</code> file to transfer the data to the Kotlin file. In the <code>onLongPress</code> method call, don't forget to call the <code>getNativeData</code> method to send string data to Android by writing <code>NativeBridge.getNativeData('Another Screen')</code>. Here, "<em>Another Screen</em>" string will act as our identifer.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="ca0d6157d0d29d14236f7442349fbf05"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/inanant/ca0d6157d0d29d14236f7442349fbf05" class="embed-card">https://gist.github.com/inanant/ca0d6157d0d29d14236f7442349fbf05</a></div><p> </p>
<p>This causes the console to display a print log statement that reads, "<em>From Native: Another Screen</em>." This indicates that, up until now, everything has been going well.</p>
<p>Click <a target="_blank" href="https://github.com/dubeyanant/pinned_shortcuts/tree/f43437c9305f90e721095597758c6ece307ebefe">here</a> to get the complete source code up to this point.</p>
<p><strong>Step 2.5: Adding some additional files</strong></p>
<p>There are some other things that you might want to do if something doesn't work. The first is adding dependencies to <code>app/build.gradle</code>.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="dfa23eb188b487bfd42c4e32e1ce6ce6"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/inanant/dfa23eb188b487bfd42c4e32e1ce6ce6" class="embed-card">https://gist.github.com/inanant/dfa23eb188b487bfd42c4e32e1ce6ce6</a></div><p> </p>
<p>Another thing you should do is add a png file to the <code>drawable</code> folder in the <code>android/app/src/main/res/</code> folder so that it can be used as the shortcut's icon. I've used <a target="_blank" href="https://github.com/dubeyanant/pinned_shortcuts/blob/main/android/app/src/main/res/drawable/page.png">this</a> file.</p>
<p><strong>Step 3 &amp; 4: Create a pinned shortcut</strong></p>
<p>We'll be creating <code>Shortcuts.kt</code>, and changing <code>MainActivity.kt</code> a little bit to create pinned shortcuts.</p>
<p>In <code>Shortcuts.kt</code>, we're doing two things. First is creating an actual shortcut item by passing a shortcut name to <code>setShortLabel</code>, a short description to <code>setLongLabel</code>, and an icon to <code>setIcon</code>, these will be sent to <code>ShortcutInfo.Builder</code>. We'll use the icon image we've put in the <code>drawable/</code> folder.</p>
<p>The second thing is sending the identifier string back to <code>MainActivity.kt</code> using <code>intent.putExtra</code>, which will be later used to send a callback to Flutter.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="3d10e525cf3de66ac28e4547c8f54124"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/inanant/3d10e525cf3de66ac28e4547c8f54124" class="embed-card">https://gist.github.com/inanant/3d10e525cf3de66ac28e4547c8f54124</a></div><p> </p>
<p>After this, we will change the <code>MainActivity.kt</code> to call the <code>setUp</code> function in the <code>Shortcuts.kt</code>. Here, I've changed the method name from <code>getNativeData</code> to <code>sendNativeData</code> and created another <code>getNativeData</code> to reflect a better naming convention from the Flutter perspective.</p>
<p><code>sendNativeData</code> gets the data that is sent from Flutter and uses it to create pinned shortcuts by first calling the <code>Shortcuts.setUp</code> function and then calling the <code>shortcutPin</code> function for the <code>shortcutManager</code> initialization. <code>getNativeData</code> basically sends the callback to Flutter with the identifier <code>screenNames</code>.</p>
<p>Here I've created <code>screenNames</code> as a mutable list, but you can also create it as a string because, at the end, we're fetching the callback data with the help of <code>screenNames[0]</code>.</p>
<p>Because <code>FlutterActivity</code> runs before <code>onCreate</code>, it should also be noted that <code>intent.extras</code> is called in <code>FlutterActivity</code> and not in <code>onCreate</code>. The original data that is associated with that specific pinned shortcut is stored in the <code>intent.extras</code> variable before being saved in the <code>screenNames</code> variable.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="6cf3e8dc4d1614adbea8d3334be4e4c5"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/inanant/6cf3e8dc4d1614adbea8d3334be4e4c5" class="embed-card">https://gist.github.com/inanant/6cf3e8dc4d1614adbea8d3334be4e4c5</a></div><p> </p>
<p><strong>Step 5: Inflate another screen</strong></p>
<p>To accommodate two functions, we will now modify the <code>home.dart</code> file. <code>sendNativeData</code>, which will only send string data, and <code>getNativeData</code>, which will receive the callback from Android and have the screen launch code.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="cbc941b31edd35f25c047dfd74f87edd"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/inanant/cbc941b31edd35f25c047dfd74f87edd" class="embed-card">https://gist.github.com/inanant/cbc941b31edd35f25c047dfd74f87edd</a></div><p> </p>
<p><strong>Note</strong> that <code>onLongPress</code> has been changed to <code>NativeBridge.sendNativeData('Another Screen'),</code> and we'll need to call the <code>NativeBridge.getNativeData(context);</code> function just before the <code>return Scaffold</code> statement to get the callback and do the necessary actions.</p>
<hr />
<p>Now, if you long press on the button in the app, it will prompt you to create a pinned shortcut with the name "<em>Another Screen</em>" and it'll be placed on the mobile home screen. After you terminate the app, clicking on that shortcut from the home screen will take you to the <code>AnotherScreen</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711020770851/2ea341ef-1743-4ce2-8bec-53efd403c665.gif" alt class="image--center mx-auto" /></p>
<p>You now know how to create pinned shortcuts in Flutter. If you require the full source code of the project, you can click <a target="_blank" href="https://github.com/dubeyanant/pinned_shortcuts">here</a>. It also contains an additional feature, which is to send a dynamic image for the shortcut icon from Flutter.</p>
<hr />
<h2 id="heading-thank-you"><strong>Thank you</strong></h2>
<p>Did you reach the bottom? <strong><em><mark>Thank you for reading!</mark></em></strong></p>
<p>Feel free to <a target="_blank" href="https://bio.link/aanant">connect with me</a>. 👋</p>
]]></content:encoded></item><item><title><![CDATA[Native Bridge between Flutter and Android]]></title><description><![CDATA[Introduction
We will look at how to create a native bridge between Flutter and Android Native (Kotlin) in this article. I will make this brief and straight to the point.
It should be noted that this bridge will transfer integer data from Flutter to A...]]></description><link>https://tech.anantdubey.com/native-bridge</link><guid isPermaLink="true">https://tech.anantdubey.com/native-bridge</guid><category><![CDATA[platform channels]]></category><category><![CDATA[Flutter]]></category><category><![CDATA[Android]]></category><category><![CDATA[Native bridge]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[Dart]]></category><dc:creator><![CDATA[Anant Dubey]]></dc:creator><pubDate>Tue, 19 Mar 2024 10:28:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1711041216130/c39a09a0-026a-491c-94b9-65da253a2f82.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>We will look at how to create a native bridge between Flutter and Android Native (Kotlin) in this article. I will make this brief and straight to the point.</p>
<p><mark>It should be noted that this bridge will transfer integer data from Flutter to Android and string data from Android to Flutter, but you can use this to transfer other data as well.</mark></p>
<h2 id="heading-building-native-bridge">Building Native Bridge</h2>
<h3 id="heading-one-way-communication">One-way communication</h3>
<ol>
<li><p>Build a native bridge in Flutter</p>
<ol>
<li><p>Add <code>services.dart</code> import</p>
<pre><code class="lang-dart"> <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/services.dart'</span>;
</code></pre>
</li>
<li><p>Add <code>NativeBridge</code> class</p>
<pre><code class="lang-dart"> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NativeBridge</span> </span>{
   <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> MethodChannel _channel = MethodChannel(<span class="hljs-string">'com.example/native'</span>);

   <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> getNativeData() <span class="hljs-keyword">async</span> {
     <span class="hljs-keyword">await</span> _channel.invokeMethod(<span class="hljs-string">'getNativeData'</span>).then((value) =&gt; <span class="hljs-built_in">print</span>(value));
   }
 }
</code></pre>
<p> First, we are going to create a <code>NativeBridge</code> class in which we will write our connection code. The bridge in the native code will be identified by the same name that we are using to create a static <code>MethodChannel</code>. The <code>getNativeData</code> method in our Kotlin file will be called by the static method <code>getNativeData()</code>, which will then print the log statement.</p>
</li>
<li><p>Call <code>getNativeData()</code> method</p>
<pre><code class="lang-dart"> NativeBridge.getNativeData();
</code></pre>
<p> Call the static method <code>getNativeData()</code> anywhere sensible in your Dart code.</p>
</li>
</ol>
</li>
<li><p>Connect it's counterpart in <code>MainActivity.kt</code></p>
<ol>
<li><p>Add necessary imports</p>
<pre><code class="lang-kotlin"> <span class="hljs-keyword">import</span> io.flutter.embedding.engine.FlutterEngine
 <span class="hljs-keyword">import</span> io.flutter.plugin.common.MethodChannel
</code></pre>
</li>
<li><p>Add this code snippet to <code>MainActivity</code> class</p>
<pre><code class="lang-kotlin"> <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> CHANNEL = <span class="hljs-string">"com.example/native"</span>

     <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">configureFlutterEngine</span><span class="hljs-params">(flutterEngine: <span class="hljs-type">FlutterEngine</span>)</span></span> {
         <span class="hljs-keyword">super</span>.configureFlutterEngine(flutterEngine)
         MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
             call, result -&gt;
             <span class="hljs-keyword">if</span> (call.method == <span class="hljs-string">"getNativeData"</span>) {
                 <span class="hljs-keyword">val</span> <span class="hljs-keyword">data</span> = getNativeData()
                 result.success(<span class="hljs-keyword">data</span>)
             } <span class="hljs-keyword">else</span> {
                 result.notImplemented()
             }
         }
     }

     <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getNativeData</span><span class="hljs-params">()</span></span>: String {
         <span class="hljs-comment">// Implement your native code logic here</span>
         <span class="hljs-keyword">return</span> <span class="hljs-string">"Native Data from Android"</span>
     }
</code></pre>
<p> The <code>CHANNEL</code> name in this case needs to match the <code>MethodChannel</code> name in our dart file in order to connect the two channels. For the purpose of determining which method to execute, we now write a simple if-check statement and then execute the required method.</p>
</li>
</ol>
</li>
<li><p>Final code files for one-way communication between Flutter and Android</p>
<ul>
<li><p><code>main.dart</code></p>
<pre><code class="lang-dart">  <span class="hljs-comment">// ignore_for_file: avoid_print</span>

  <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
  <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/services.dart'</span>;

  <span class="hljs-keyword">void</span> main() =&gt; runApp(<span class="hljs-keyword">const</span> MyApp());

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
    <span class="hljs-keyword">const</span> MyApp({<span class="hljs-keyword">super</span>.key});

    <span class="hljs-meta">@override</span>
    Widget build(BuildContext context) {
      <span class="hljs-keyword">return</span> MaterialApp(
        title: <span class="hljs-string">'My App'</span>,
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
          useMaterial3: <span class="hljs-keyword">true</span>,
        ),
        home: <span class="hljs-keyword">const</span> HomePage(),
      );
    }
  }

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NativeBridge</span> </span>{
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> MethodChannel _channel = MethodChannel(<span class="hljs-string">'com.example/native'</span>);

    <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> getNativeData() <span class="hljs-keyword">async</span> {
      <span class="hljs-keyword">await</span> _channel.invokeMethod(<span class="hljs-string">'getNativeData'</span>).then((value) =&gt; <span class="hljs-built_in">print</span>(value));
    }
  }

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomePage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
    <span class="hljs-keyword">const</span> HomePage({<span class="hljs-keyword">super</span>.key});

    <span class="hljs-meta">@override</span>
    Widget build(BuildContext context) {
      NativeBridge.getNativeData();

      <span class="hljs-keyword">return</span> Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'My App'</span>),
        ),
        body: <span class="hljs-keyword">const</span> Center(
          child: Text(<span class="hljs-string">'data'</span>),
        ),
      );
    }
  }
</code></pre>
</li>
<li><p><code>MainActivity.kt</code></p>
<pre><code class="lang-kotlin">  <span class="hljs-keyword">package</span> com.example.bridge

  <span class="hljs-keyword">import</span> io.flutter.embedding.android.FlutterActivity
  <span class="hljs-keyword">import</span> io.flutter.embedding.engine.FlutterEngine
  <span class="hljs-keyword">import</span> io.flutter.plugin.common.MethodChannel

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MainActivity</span>: <span class="hljs-type">FlutterActivity</span></span>() {
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> CHANNEL = <span class="hljs-string">"com.example/native"</span>

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">configureFlutterEngine</span><span class="hljs-params">(flutterEngine: <span class="hljs-type">FlutterEngine</span>)</span></span> {
          <span class="hljs-keyword">super</span>.configureFlutterEngine(flutterEngine)
          MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
              call, result -&gt;
              <span class="hljs-keyword">if</span> (call.method == <span class="hljs-string">"getNativeData"</span>) {
                  <span class="hljs-keyword">val</span> <span class="hljs-keyword">data</span> = getNativeData()
                  result.success(<span class="hljs-keyword">data</span>)
              } <span class="hljs-keyword">else</span> {
                  result.notImplemented()
              }
          }
      }

      <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getNativeData</span><span class="hljs-params">()</span></span>: String {
          <span class="hljs-comment">// Implement your native code logic here</span>
          <span class="hljs-keyword">return</span> <span class="hljs-string">"Native Data from Android"</span>
      }
  }
</code></pre>
</li>
</ul>
</li>
</ol>
<p><mark>Here, </mark> <strong><mark>we have managed to successfully create a one-way connection between Android and Flutter</mark></strong><mark>. In this case, a log statement stating "Native Data from Android," which is coming from Android to Flutter, is printed when the app runs.</mark></p>
<h3 id="heading-two-way-communication">Two-way communication</h3>
<ul>
<li><p>Two-way communication can be achieved by adding a few data type parameters to <code>_channel.invokeMethod</code> and making minor adjustments to <code>getNativeData</code> method. The finished Dart and Kotlin files are below.</p>
<ul>
<li><p><code>main.dart</code></p>
<pre><code class="lang-dart">  <span class="hljs-comment">// ignore_for_file: avoid_print</span>

  <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
  <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/services.dart'</span>;

  <span class="hljs-keyword">void</span> main() =&gt; runApp(<span class="hljs-keyword">const</span> MyApp());

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
    <span class="hljs-keyword">const</span> MyApp({<span class="hljs-keyword">super</span>.key});

    <span class="hljs-meta">@override</span>
    Widget build(BuildContext context) {
      <span class="hljs-keyword">return</span> MaterialApp(
        title: <span class="hljs-string">'My App'</span>,
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
          useMaterial3: <span class="hljs-keyword">true</span>,
        ),
        home: <span class="hljs-keyword">const</span> HomePage(),
      );
    }
  }

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NativeBridge</span> </span>{
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> MethodChannel _channel = MethodChannel(<span class="hljs-string">'com.example/native'</span>);

    <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> getNativeData(<span class="hljs-built_in">int</span> <span class="hljs-built_in">num</span>) <span class="hljs-keyword">async</span> {
      <span class="hljs-keyword">await</span> _channel.invokeMethod(<span class="hljs-string">'getNativeData'</span>, &lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">int</span>&gt;{
        <span class="hljs-string">"num"</span>: <span class="hljs-built_in">num</span>,
      }).then((value) =&gt; <span class="hljs-built_in">print</span>(value));
    }
  }

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomePage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
    <span class="hljs-keyword">const</span> HomePage({<span class="hljs-keyword">super</span>.key});

    <span class="hljs-meta">@override</span>
    Widget build(BuildContext context) {
      <span class="hljs-built_in">int</span> i = <span class="hljs-number">0</span>;

      <span class="hljs-keyword">return</span> Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'My App'</span>),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () {
              NativeBridge.getNativeData(++i);
            },
            child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Click me'</span>),
          ),
        ),
      );
    }
  }
</code></pre>
</li>
<li><p><code>MainActivity.kt</code></p>
<pre><code class="lang-kotlin">  <span class="hljs-keyword">package</span> com.example.bridge

  <span class="hljs-keyword">import</span> io.flutter.embedding.android.FlutterActivity
  <span class="hljs-keyword">import</span> io.flutter.embedding.engine.FlutterEngine
  <span class="hljs-keyword">import</span> io.flutter.plugin.common.MethodChannel

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MainActivity</span>: <span class="hljs-type">FlutterActivity</span></span>() {
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> CHANNEL = <span class="hljs-string">"com.example/native"</span>

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">configureFlutterEngine</span><span class="hljs-params">(flutterEngine: <span class="hljs-type">FlutterEngine</span>)</span></span> {
          <span class="hljs-keyword">super</span>.configureFlutterEngine(flutterEngine)
          MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
              call, result -&gt;
              <span class="hljs-keyword">if</span> (call.method == <span class="hljs-string">"getNativeData"</span>) {
                  <span class="hljs-keyword">if</span> (!call.hasArgument(<span class="hljs-string">"num"</span>)) {
                      result.error(<span class="hljs-string">"MissingArgumentError"</span>, <span class="hljs-string">"You must provide num parameter"</span>, <span class="hljs-literal">null</span>)
                  }
                  <span class="hljs-keyword">val</span> num: <span class="hljs-built_in">Int</span> = call.argument&lt;<span class="hljs-built_in">Int</span>&gt;(<span class="hljs-string">"num"</span>)!!
                  <span class="hljs-keyword">val</span> <span class="hljs-keyword">data</span> = getNativeData(num)
                  result.success(<span class="hljs-keyword">data</span>)
              } <span class="hljs-keyword">else</span> {
                  result.notImplemented()
              }
          }
      }

      <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getNativeData</span><span class="hljs-params">(num: <span class="hljs-type">Int</span>)</span></span>: String {
          <span class="hljs-comment">// Implement your native code logic here</span>
          <span class="hljs-keyword">return</span> <span class="hljs-string">"From Native: <span class="hljs-variable">$num</span>"</span>
      }
  }
</code></pre>
</li>
</ul>
</li>
</ul>
<p><mark>Here, </mark> <strong><mark>we have successfully created a two-way communication channel between Flutter and Android</mark></strong><mark>. When we click the on-screen button, we send integer data to Android and receive a different string each time (in the form of a log statement).</mark></p>
<hr />
<p>The complete project source code for the one-way and two-way communication codes is maintained commit-wise; you can view it by clicking <a target="_blank" href="https://github.com/dubeyanant/native_bridge">this</a> link.</p>
<hr />
<h2 id="heading-thank-you"><strong>Thank you</strong></h2>
<p>Did you reach the bottom? <strong><em><mark>Thank you for reading!</mark></em></strong></p>
<p>Feel free to <a target="_blank" href="https://bio.link/aanant">connect with me</a>. 👋</p>
]]></content:encoded></item><item><title><![CDATA[Taskaro: A Task Prioritization Android App]]></title><description><![CDATA[Introduction
As a busy individual constantly juggling multiple responsibilities, I understand the struggle of staying on top of tasks and deadlines. That's why I'm thrilled to share my journey of building Taskaro with you. Hey there! My name is Anant...]]></description><link>https://tech.anantdubey.com/taskaro-a-task-prioritization-android-app</link><guid isPermaLink="true">https://tech.anantdubey.com/taskaro-a-task-prioritization-android-app</guid><category><![CDATA[Android]]></category><category><![CDATA[Firebase]]></category><category><![CDATA[Material Design]]></category><category><![CDATA[UI]]></category><category><![CDATA[Productivity]]></category><dc:creator><![CDATA[Anant Dubey]]></dc:creator><pubDate>Mon, 29 May 2023 09:17:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1711041247828/5aa7d0c8-81f0-42bd-9801-e7f1fae993de.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>As a busy individual constantly juggling multiple responsibilities, I understand the struggle of staying on top of tasks and deadlines. That's why I'm thrilled to share my journey of building Taskaro with you. Hey there! My name is <a target="_blank" href="https://bio.link/aanant">Anant</a>, and in this article, we'll delve into how Taskaro came to be and explore its ins and outs.</p>
<p>Taskaro is built upon the principles of the Eisenhower matrix, with a simple yet powerful purpose — to help individuals like myself reclaim control over their busy lives. In today's fast-paced world, the demands and responsibilities can quickly become overwhelming. Whether you're a student with assignment deadlines, a professional managing numerous projects, or a homemaker handling household chores, Taskaro is designed to be your trusted companion, ensuring you never miss a beat. Taskaro empowers you to effortlessly organize, prioritize, and execute tasks, allowing you to navigate through your responsibilities with ease.</p>
<h2 id="heading-problem-statement">Problem Statement</h2>
<p>Have you ever found yourself overwhelmed by a lengthy list of tasks that require completion, each with varying levels of importance, urgency and different deadlines? It can be quite challenging to determine which task to prioritize, resulting in confusion and anxiety. Recognizing the significance of undertaking the right task at the right time cannot be emphasized enough.</p>
<p>This is precisely why this app came into existence and the vision behind it drove its development. In a nutshell, this app can be described as <mark>a tool that simplifies the complexities of everyday life</mark>.</p>
<p>Existing solutions in the market have their limitations. Traditional to-do lists or basic task management apps often lack a comprehensive approach to organizing tasks. Some existing apps may have a steep learning curve or an overwhelming interface, limiting their accessibility to a wide range of users.</p>
<h2 id="heading-the-application">The Application</h2>
<h3 id="heading-working">Working</h3>
<p>Taskaro organizes its home screen into four distinct sections: "Do it," "Schedule it," "Delegate it," and "Delete it." As the names imply, tasks placed within each section should be approached accordingly.</p>
<p>Distinguishing itself from typical to-do list applications, Taskaro incorporates a simple yet sophisticated algorithm that assesses task priorities and categorizes them accordingly. This backend functionality enables the application to determine which tasks require immediate attention and which ones can be postponed without compromising overall productivity.</p>
<p>The app relies on two inputs from users to prioritize tasks: Urgency and Importance. <strong>When entering a task, users indicate whether it is urgent and/or important. Based on this information, Taskaro assigns a priority to the task accordingly.</strong></p>
<p>On the technical side, Taskaro is built using Java and developed in Android Studio by leveraging Firebase as its backend infrastructure.</p>
<h3 id="heading-features-and-functionality">Features and Functionality</h3>
<p><strong>Login/Signup</strong>: Users can log in or sign up on the app, ensuring the security of their data on the online server, which they can retrieve whenever they wish.</p>
<p><strong>Task Prioritization</strong>: One of Taskaro's key features is its task prioritization functionality. When a user enters multiple tasks into the app, Taskaro automatically categorizes them into four distinct groups based on different priorities. This is achieved through colour coding and prompt headings. By doing so, Taskaro encourages users to focus on tasks that are both urgent and important, while leaving tasks that are neither urgent nor important to be addressed later or possibly deleted.</p>
<p><strong>Note Taking</strong>: Taskaro offers a simple and minimalist note-taking feature. Users can conveniently enter and store notes within the same application system as their tasks. The notes feature allows users to add, edit, and delete notes as needed, providing a practical way to keep important information alongside their tasks.</p>
<p><strong>User Profile</strong>: Taskaro includes a user profile screen, where users can easily personalize their accounts. Users can set a profile photo and make changes to their names if they were initially entered incorrectly. The profile screen also provides the option to log out of the app. If desired, users can delete their profiles, resulting in the deletion of their data, tasks, and notes from the app.</p>
<h3 id="heading-user-interface-amp-experience">User Interface &amp; Experience</h3>
<p>The app starts with onboarding screens to familiarize the user with its purpose. Subsequently, users are prompted to either login or sign up using their email address.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685343334247/4e5d5767-36af-466c-8657-56a8bc5318ba.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685345404108/a1d13a25-b94a-4b6e-85b0-c3642f071bc5.jpeg" alt class="image--center mx-auto" /></p>
<p>Upon successful login, users can explore every section of the app through the bottom navigation bar. The bar comprises the home screen, notes screen, and user profile screen.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685343379988/1efdc09d-5c06-4f39-9674-a0ec316aca95.jpeg" alt class="image--center mx-auto" /></p>
<p>The bottom navbar also includes a floating action button. Clicking it on the home screen creates a new task, while on the notes screen, it creates a new note.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685345409889/673d7901-0098-4829-a481-124d46824e42.jpeg" alt class="image--center mx-auto" /></p>
<p>The home screen organizes tasks into different sections, each colour-coded for easier browsing and workflow.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685345414613/0f902998-f365-4255-a292-1a6bed08081e.jpeg" alt class="image--center mx-auto" /></p>
<p>The notes and user profile screens consist of a minimalistic and soothing appearance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685345417289/fabbb2b1-c0ee-469e-b952-e1dbb1499d4f.jpeg" alt class="image--center mx-auto" /></p>
<p>Taskaro incorporates <a target="_blank" href="https://m3.material.io/">Material 3</a> design components, utilizes the <a target="_blank" href="https://fonts.google.com/specimen/Inter?query=inter">Inter</a> font family, and maintains a side margin of 20dp throughout the app.</p>
<p>The app's front end is created using Figma, taking into consideration various <a target="_blank" href="https://tusharsrivastava.hashnode.dev/5-key-ui-design-principles-for-beginners">UI principles</a> and <a target="_blank" href="https://blog.adarshdubey.com/ux-design-laws-every-developer-should-know">UX laws</a> to enhance user navigation. <a target="_blank" href="https://www.figma.com/file/aYi39I9W6tRWavWJU2Gydo/Screens?type=design&amp;t=rFQyq3jIy6djkbko-1">Click here</a> 👈 to view app screens on Figma.</p>
<p>Any feedback on the app would be greatly appreciated! 🙏</p>
<h3 id="heading-how-to-use-the-app">How to Use the App</h3>
<ol>
<li><p>Taskaro is only available for Android devices and can be downloaded either from <a target="_blank" href="https://github.com/dubeyanant/Taskaro/releases/tag/v0.1.0-alpha">GitHub</a> or by <a target="_blank" href="https://github.com/dubeyanant/Taskaro/releases/download/v0.1.0-alpha/Taskaro.apk">clicking here</a>👈 for a direct download.</p>
</li>
<li><p>To begin using the app, simply sign up.</p>
</li>
<li><p>Once signed in, you will be directed to the home screen, where you can create a task by clicking on the plus button.</p>
</li>
<li><p>Explore the app through the bottom navigation bar. 🚀</p>
</li>
</ol>
<h3 id="heading-benefits">Benefits</h3>
<p>By utilizing this app and adhering to the task order provided, you can tackle the tasks that have a significant impact on your overall productivity and life. As the saying goes, "Eat the biggest frog first 🐸", prioritize the larger tasks that require the most effort at the start of your day. Taskaro is designed to assist you in accomplishing precisely that.</p>
<p>If you follow the recommended task sequence within different sections, your day will become more productive and efficient. Tasks marked for deletion can be completed towards the end of the list, or they can be eliminated 🚮, as they will have minimal to no impact on your productivity.</p>
<h3 id="heading-resources">Resources</h3>
<p>Here are some resources that I utilized:</p>
<ul>
<li><p><a target="_blank" href="https://m3.material.io/theme-builder#/custom">Material Design</a></p>
</li>
<li><p><a target="_blank" href="https://www.drawkit.com/">DrawKit</a></p>
</li>
<li><p><a target="_blank" href="https://www.freepik.com/">Freepik</a></p>
</li>
<li><p><a target="_blank" href="https://icons8.com/">icons8</a></p>
</li>
</ul>
<h3 id="heading-future-updates">Future Updates</h3>
<p>Roadmap for the upcoming features and improvement:</p>
<ol>
<li><p><strong>Notifications</strong>: Implement a notification system to alert users about their pending tasks.</p>
</li>
<li><p><strong>Edit task</strong>: Allow users to make edits to their tasks even after saving them.</p>
</li>
<li><p><strong>Google login</strong>: Enable users to conveniently sign up and log in using their Google accounts.</p>
</li>
<li><p><strong>Offline data storage</strong>: Implement offline data storage capability, allowing users to access and sync their data when an internet connection is unavailable.</p>
</li>
<li><p><strong>Data encryption</strong>: Enhance security by encrypting user data stored in the online cloud storage.</p>
</li>
<li><p><strong>Enhanced UI/UX</strong>: Improve the app's user interface and experience to ensure easy navigation and a seamless user journey.</p>
</li>
<li><p><strong>Analytics screen</strong>: Provide users with an analytics screen where they can gain insights into their task patterns, time allocation, and other relevant metrics.</p>
</li>
</ol>
<p>My ultimate vision for the app is to transform it into <em>one of the most accessible open-source task prioritization tools, widely used by students, professionals, and individuals from diverse backgrounds</em>.</p>
<p><strong><mark>I highly value your feedback</mark></strong> and encourage you to share your thoughts in the comments section or on the <a target="_blank" href="https://github.com/dubeyanant/Taskaro">GitHub page</a>. Your feedback will help improve the app further.</p>
<p>Also, <strong><mark>I greatly appreciate any contributions</mark></strong> made to enhance the usability of the app. You can contribute in various ways:</p>
<ul>
<li><p><strong>Open issues</strong>: Identify and report any bugs, suggest improvements, or request changes by creating new issues on GitHub.</p>
</li>
<li><p><strong>README pages</strong>: Contribute by creating informative README pages on topics such as contributions, licenses, or any other relevant areas. You can also enhance existing README pages to provide better documentation.</p>
</li>
<li><p><strong>Bug fixes and UI enhancements</strong>: Help improve the app by fixing bugs, enhancing the user interface, or integrating suggested changes.</p>
</li>
<li><p><strong>Translation</strong>: Contribute by translating the app into different languages, making it more accessible to users worldwide.</p>
</li>
<li><p><strong>Feature integration</strong>: Implement any of the above-mentioned features in the app.</p>
</li>
<li><p><strong>GitHub page maintenance</strong>: You can also assist in maintaining the GitHub page, keeping it up to date with the latest information and improvements.</p>
</li>
</ul>
<p>Any other contributions you may have in mind are welcome. Your support and contributions are highly valued and will contribute to making the app even better.</p>
<h2 id="heading-my-journey">My Journey</h2>
<h3 id="heading-problems-i-faced">Problems I Faced</h3>
<ol>
<li><p><strong>Overwhelmed with Complexities and Lack of Knowledge</strong>: Having a background solely in development and lacking knowledge in designing and managing an extensive app, I was uncertain where to start. To overcome this, I adopted a systematic approach, breaking down the process into manageable tasks and focusing on one component at a time. I actively sought resources such as online tutorials, developer forums, and documentation. I also reached out to experienced professionals on platforms like Twitter and Discord.</p>
</li>
<li><p><strong>Integrating Features</strong>: My goal was to provide a modern and intuitive user interface by implementing the latest design principles, such as Material Design 3. However, integrating these design elements and ensuring a seamless user experience presented their own set of challenges. Additionally, incorporating functionalities like a runnable class for recurring tasks or background services for notifications required careful implementation and thorough testing. Through experimentation, iteration, and testing, I successfully integrated some of these features, while others are still pending.</p>
</li>
<li><p><strong>Managing My Team</strong>: While developing Taskaro, I also encountered the challenge of managing a small team of developers. Coordinating efforts, assigning tasks, and ensuring effective communication were vital to maintaining productivity and achieving project milestones. Regular team meetings, progress tracking, and open channels of communication helped with this.</p>
</li>
<li><p><strong>Managing Deadlines</strong>: Balancing multiple responsibilities and ensuring the timely completion of tasks posed a significant challenge. To manage deadlines effectively, I employed project management techniques, such as creating a detailed timeline, breaking down tasks into smaller subtasks with their respective deadlines, and regularly monitoring progress. Tools like Todoist and Slack helped me achieve this.</p>
</li>
<li><p><strong>GitHub Workflow</strong>: Developing Taskaro involved implementing an efficient GitHub workflow with a team and effectively managing the source code, both of which were crucial. Initially, I encountered difficulties in establishing a clear workflow. But I started learning and adopting best practices, seeking guidance from experienced individuals. This enabled me to effectively manage the expanding codebase. I also implemented coding standards and started with regular code reviews to ensure code quality and consistency.</p>
</li>
</ol>
<h3 id="heading-my-learnings">My Learnings</h3>
<ol>
<li><p><strong>Searching for Solutions</strong>: One of the most valuable lessons I learned during my development journey was how to effectively find solutions. I faced numerous challenges that demanded my ability to seek answers. Here are some approaches that proved helpful:</p>
<ol>
<li><p><strong><em>Online Resources</em></strong>: I found great value in seeking developer forums, coding communities, and technical documentation to find solutions. Websites such as Stack Overflow, GitHub, and official documentation were very useful.</p>
</li>
<li><p><strong><em>Online Tutorials</em></strong>: I greatly benefited from online tutorials and different YouTube videos when dealing with complex issues and bugs.</p>
</li>
</ol>
</li>
<li><p><strong>Debugging Techniques</strong>: When faced with errors or unexpected behaviour during the app development process, I employed the following methods to identify and resolve issues:</p>
<ol>
<li><p><strong><em>Logging</em></strong>: To track the execution flow and pinpoint potential problems, I strategically inserted log statements at crucial points in the code. By analyzing the logs, I was able to narrow down the source of the problem.</p>
</li>
<li><p><strong><em>Divide and Conquer</em></strong>: When dealing with complex issues, I broke down the problem into smaller, manageable parts and isolated the specific issue. This method helped me narrow down and focus on the problem at hand.</p>
</li>
</ol>
</li>
<li><p><strong>Collaboration and Communication</strong>: This played a vital role in the development of Taskaro. I scheduled regular meetings with the development team to discuss progress, challenges, and next steps. These meetings provided a platform for exchanging ideas, clarifying requirements, and aligning our efforts.</p>
</li>
<li><p><strong>UI/UX development</strong>: Creating an intuitive and visually appealing user interface (UI) was my key focus. Here are some practices I followed for UI/UX development:</p>
<ol>
<li><p><strong><em>User Research</em></strong>: I conducted user research to understand the preferences, colour theory, and pain points of the audience. This research informed the design decisions, ensuring the UI met user expectations.</p>
</li>
<li><p><strong><em>Consistency and Simplicity</em></strong>: I aimed for a consistent and simple UI design throughout Taskaro. By using a cohesive colour palette, typography, and layout, I created a visually harmonious experience.</p>
</li>
</ol>
</li>
<li><p><strong>How to Seek Help</strong>: You'll not get help if you don't ask for it, and there is no shame in doing so. I learned the following best practices when seeking assistance:</p>
<ol>
<li><p><strong><em>Research First</em></strong>: Before asking for help, I made sure to conduct thorough research on the issue. By showing that I had already attempted to find a solution, I increased the likelihood of receiving help and avoided duplicating efforts.</p>
</li>
<li><p><strong><em>Be Specific and Clear</em></strong>: When asking for help, I provided detailed information about the problem, including error messages, relevant code snippets, and steps to reproduce the issue. Clear communication helped others understand the problem and provide targeted assistance.</p>
</li>
<li><p><strong><em>Show Respect</em></strong>: When seeking help on online forums or communities, I followed the guidelines and rules of the community. I maintained a respectful attitude, displayed patience, and expressed gratitude for any support I received.</p>
</li>
</ol>
</li>
</ol>
<h3 id="heading-my-future-goals">My Future Goals</h3>
<p>One of the goals is to keep enhancing this app and making it even more useful.</p>
<p>Here are some other future goals:</p>
<ul>
<li><p>Develop additional Android apps incorporating various technologies.</p>
</li>
<li><p>Learn JavaScript and create web apps.</p>
</li>
<li><p>Expand understanding of team management and explore related areas.</p>
</li>
<li><p>Produce more technical blog posts.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, Taskaro is the result of my journey to address the challenges of managing tasks and deadlines in today's fast-paced world. It is a tool designed to simplify the complexities of everyday life, helping users prioritize tasks and maximize their productivity.</p>
<p>Through the development process, I faced various challenges, however, I learned valuable lessons along the way, including the importance of seeking solutions, effective collaboration and communication.</p>
<p>I greatly value your feedback and contributions to enhance the app further.</p>
<h3 id="heading-thank-you"><strong>Thank you</strong></h3>
<p>Did you reach the bottom? <strong><em><mark>Thank you for reading!</mark></em></strong></p>
<p>Feel free to <a target="_blank" href="https://bio.link/aanant">connect with me</a>. 👋</p>
]]></content:encoded></item><item><title><![CDATA[CRUD application with MongoDB and Python]]></title><description><![CDATA[Introduction
In this article, we will explore how to build a CRUD (Create, Read, Update, Delete) application using MongoDB and Python. We will start by discussing what a CRUD application is and why it is useful. Then, we will look at the technologies...]]></description><link>https://tech.anantdubey.com/crud-application-with-mongodb-and-python</link><guid isPermaLink="true">https://tech.anantdubey.com/crud-application-with-mongodb-and-python</guid><category><![CDATA[MongoDB]]></category><category><![CDATA[Python]]></category><category><![CDATA[crud]]></category><dc:creator><![CDATA[Anant Dubey]]></dc:creator><pubDate>Fri, 24 Mar 2023 10:36:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1711041280350/144c7588-f267-48ee-8297-b93ba508f64f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction"><strong>Introduction</strong></h2>
<p>In this article, we will explore how to build a CRUD (Create, Read, Update, Delete) application using MongoDB and Python. We will start by discussing what a CRUD application is and why it is useful. Then, we will look at the technologies we will be using to build our application, namely MongoDB and Python. After that, we will dive into the step-by-step process of building our CRUD application.</p>
<h2 id="heading-understanding-crud-applications"><strong>Understanding CRUD Applications</strong></h2>
<p>A CRUD application is a type of software application that allows users to perform four basic operations on a dataset: create, read, update, and delete. These four operations correspond to the acronym CRUD.</p>
<p>CRUD applications are useful because they allow users to easily manipulate and interact with data. They are commonly used in web applications, content management systems, and other data-driven software.</p>
<h2 id="heading-technologies-used"><strong>Technologies Used</strong></h2>
<p>In this tutorial, we will be using two technologies to build our CRUD application: MongoDB and Python.</p>
<p>MongoDB is a popular NoSQL database that is well-suited for storing and managing large amounts of unstructured or semi-structured data. It is known for its ease of use and scalability.</p>
<p>Python is a popular programming language that is often used for web development, data analysis, and scientific computing. It is easy to learn and has a large and active community.</p>
<h2 id="heading-setting-up-the-environment"><strong>Setting Up the Environment</strong></h2>
<p>Before we start building our CRUD application, we need to set up our environment. This involves installing and configuring MongoDB and Python.</p>
<h3 id="heading-installing-mongodb"><strong>Installing MongoDB</strong></h3>
<p>To install MongoDB, follow these steps:</p>
<ol>
<li><p>Go to the <a target="_blank" href="https://www.mongodb.com/try/download/community"><strong>MongoDB website</strong></a> and download the appropriate version for your operating system.</p>
</li>
<li><p>Follow the installation instructions provided by MongoDB.</p>
</li>
</ol>
<h3 id="heading-installing-python"><strong>Installing Python</strong></h3>
<p>To install Python, follow these steps:</p>
<ol>
<li><p>Go to the <a target="_blank" href="https://www.python.org/downloads/"><strong>Python website</strong></a> and download the appropriate version for your operating system.</p>
</li>
<li><p>Follow the installation instructions provided by Python.</p>
</li>
</ol>
<h2 id="heading-building-the-crud-application"><strong>Building the CRUD Application</strong></h2>
<p>Now that our environment is set up, we can start building our CRUD application. We will be using Python and the PyMongo library to interact with MongoDB.</p>
<h3 id="heading-creating-a-connection-to-mongodb"><strong>Creating a Connection to MongoDB</strong></h3>
<p>To start, we need to create a connection to our MongoDB instance. We can do this using the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> pymongo <span class="hljs-keyword">import</span> MongoClient

client = MongoClient(<span class="hljs-string">'localhost'</span>, <span class="hljs-number">27017</span>)
db = client[<span class="hljs-string">'mydatabase'</span>]
</code></pre>
<p>This code creates a connection to a MongoDB instance running on the local machine on port 27017. It also creates a database called "mydatabase".</p>
<h3 id="heading-creating-the-data-model"><strong>Creating the Data Model</strong></h3>
<p>Next, we need to define the data model for our application. In this example, we will be creating a simple data model for storing information about books.</p>
<pre><code class="lang-python">book = {
    <span class="hljs-string">'title'</span>: <span class="hljs-string">'The Great Gatsby'</span>,
    <span class="hljs-string">'author'</span>: <span class="hljs-string">'F. Scott Fitzgerald'</span>,
    <span class="hljs-string">'published_date'</span>: <span class="hljs-string">'1925-04-10'</span>
}
</code></pre>
<p>This code defines a dictionary that represents a book. It has three fields: title, author, and published_date.</p>
<h3 id="heading-inserting-data-into-mongodb"><strong>Inserting Data into MongoDB</strong></h3>
<p>Now that we have defined our data model, we can insert some data into MongoDB. We can do this using the following code:</p>
<pre><code class="lang-python">result = db.books.insert_one(book)
print(result.inserted_id)
</code></pre>
<p>This code inserts a single book into the "books" collection in our MongoDB database. It then prints the ID of the inserted document.</p>
<h3 id="heading-retrieving-data-from-mongodb"><strong>Retrieving Data from MongoDB</strong></h3>
<p>Next, we can retrieve data from MongoDB using the following code:</p>
<pre><code class="lang-python">result = db.books.find_one({<span class="hljs-string">'title'</span>: <span class="hljs-string">'The Great Gatsby'</span>})
print(result)
</code></pre>
<p>This code retrieves the first document from the "books" collection where the title field matches "The Great Gatsby". It then prints the result to the console.</p>
<h3 id="heading-updating-data-in-mongodb"><strong>Updating Data in MongoDB</strong></h3>
<p>To update data in MongoDB, we can use the <code>update_one()</code> method. For example, to update the published date of a book, we can use the following code:</p>
<pre><code class="lang-python">query = {<span class="hljs-string">'title'</span>: <span class="hljs-string">'The Great Gatsby'</span>}
new_values = {<span class="hljs-string">'$set'</span>: {<span class="hljs-string">'published_date'</span>: <span class="hljs-string">'1925-04-11'</span>}}
result = db.books.update_one(query, new_values)
print(result.modified_count)
</code></pre>
<p>This code updates the published date of the book with the title "The Great Gatsby" to "1925-04-11". It then prints the number of documents that were modified (which should be 1 in this case).</p>
<h3 id="heading-deleting-data-from-mongodb"><strong>Deleting Data from MongoDB</strong></h3>
<p>To delete data from MongoDB, we can use the <code>delete_one()</code> method. For example, to delete a book from the "books" collection, we can use the following code:</p>
<pre><code class="lang-python">result = db.books.delete_one({<span class="hljs-string">'title'</span>: <span class="hljs-string">'The Great Gatsby'</span>})
print(result.deleted_count)
</code></pre>
<p>This code deletes the first document from the "books" collection where the title field matches "The Great Gatsby". It then prints the number of documents that were deleted (which should be 1 in this case).</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In this article, we have explored how to build a CRUD application using MongoDB and Python. We started by discussing what a CRUD application is and why it is useful. Then, we looked at the technologies we would be using to build our application, namely MongoDB and Python. We then walked through the step-by-step process of building a CRUD application, including creating a connection to MongoDB, defining a data model, and inserting, retrieving, updating, and deleting data.</p>
<p>By following this tutorial, you should now have a good understanding of how to build a CRUD application using MongoDB and Python.</p>
<h2 id="heading-thank-you">Thank you</h2>
<p>Did you reach the bottom? <em>Thank you for reading!</em></p>
<p>👋 Hello again! Feel free to connect with me here: <a target="_blank" href="https://bio.link/aanant">Anant's socials</a></p>
]]></content:encoded></item></channel></rss>