<?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[Sabin Chapagain Blog]]></title><description><![CDATA[Sabin Chapagain Blog]]></description><link>https://blog.sabinchapagain.com.np</link><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 09:00:24 GMT</lastBuildDate><atom:link href="https://blog.sabinchapagain.com.np/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[🚀 Migrating to Firebase Topic Messaging for Scalable Chat Notifications]]></title><description><![CDATA[A practical guide to replacing legacy Firebase token-based messaging with topic-based messaging

🔥 The Problem
When building a real-time chat system, push notifications are crucial. Initially, it’s common to send messages to multiple device tokens u...]]></description><link>https://blog.sabinchapagain.com.np/migrating-to-firebase-topic-messaging-for-scalable-chat-notifications</link><guid isPermaLink="true">https://blog.sabinchapagain.com.np/migrating-to-firebase-topic-messaging-for-scalable-chat-notifications</guid><dc:creator><![CDATA[Sabin Chapagain]]></dc:creator><pubDate>Thu, 03 Jul 2025 16:25:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751559897962/05260576-9d1f-4ae2-9f01-d730092f515e.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A practical guide to replacing legacy Firebase token-based messaging with topic-based messaging</p>
<hr />
<h2 id="heading-the-problem">🔥 The Problem</h2>
<p>When building a real-time chat system, push notifications are crucial. Initially, it’s common to send messages to <strong>multiple device tokens</strong> using Firebase’s <strong>legacy API</strong>.</p>
<p>However, Firebase has <strong>deprecated this functionality</strong> — it no longer allows sending messages to multiple device tokens in a single API call.</p>
<p>This introduces a problem:<br />What if your system has <strong>thousands of users</strong>? Looping through tokens to send messages one by one isn’t efficient — it consumes memory and slows down delivery.</p>
<hr />
<h2 id="heading-the-solution-firebase-topic-messaging">💡 The Solution: <strong>Firebase Topic Messaging</strong></h2>
<p>A great alternative is to use <strong>Firebase Topic Messaging</strong>.</p>
<p>In many chat systems, users participate in <strong>channels or rooms</strong>. These channels map perfectly to <strong>topics</strong> in Firebase.</p>
<ul>
<li><p>You <strong>subscribe a device</strong> to a topic (channel).</p>
</li>
<li><p>When a message is sent to that topic, <strong>all subscribed devices</strong> receive it.</p>
</li>
<li><p>No need to manually manage and loop over tokens.</p>
</li>
</ul>
<p>It's scalable and aligns with how group chat features work.</p>
<hr />
<h2 id="heading-requirements">✅ Requirements</h2>
<p>Here’s what you need:</p>
<ul>
<li><p>A Firebase project</p>
</li>
<li><p>A service account JSON file</p>
</li>
<li><p>Node.js and the <code>firebase-admin</code> package</p>
</li>
<li><p>A socket-based system (like Socket.IO) to track user activity</p>
</li>
</ul>
<hr />
<h2 id="heading-step-by-step-setup">🔧 Step-by-Step Setup</h2>
<h3 id="heading-1-get-firebase-service-account">1. 🔐 Get Firebase Service Account</h3>
<ul>
<li><p>Go to <a target="_blank" href="https://console.firebase.google.com/">Firebase Console</a></p>
</li>
<li><p>Project settings &gt; <strong>Service accounts</strong></p>
</li>
<li><p>Click <strong>“Generate new private key”</strong></p>
</li>
<li><p>Save the file in a local <code>.firebase/</code> folder</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751559564196/9a31b913-99a0-4319-a1f5-db538439477a.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-2-keep-credentials-secure">2. 🛡️ Keep Credentials Secure</h3>
<p>Add the folder to your <code>.gitignore</code>:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># .gitignore</span>
.firebase/
</code></pre>
<hr />
<h3 id="heading-3-initialize-firebase-admin-sdk">3. 📦 Initialize Firebase Admin SDK</h3>
<p><strong>Install the package:</strong></p>
<pre><code class="lang-bash">npm install firebase-admin
</code></pre>
<p><strong>Use environment variables and initialize Firebase:</strong></p>
<pre><code class="lang-python"><span class="hljs-comment"># .env</span>
FIREBASE_CREDENTIAL_PATH=.firebase/firebase-adminsdk.json
</code></pre>
<pre><code class="lang-js"><span class="hljs-comment">// firebase.js</span>
<span class="hljs-keyword">const</span> admin = <span class="hljs-built_in">require</span>(<span class="hljs-string">"firebase-admin"</span>);
<span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">"path"</span>);

<span class="hljs-keyword">const</span> serviceAccount = <span class="hljs-built_in">require</span>(path.resolve(process.env.FIREBASE_CREDENTIAL_PATH));

admin.initializeApp({
  <span class="hljs-attr">credential</span>: admin.credential.cert(serviceAccount)
});

<span class="hljs-built_in">module</span>.exports = admin;
</code></pre>
<hr />
<h2 id="heading-topic-subscription-logic">🔄 Topic Subscription Logic</h2>
<p>When a user connects via socket and joins channels, subscribe their device token to the corresponding topics:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> subscribeToChannels = <span class="hljs-keyword">async</span> (deviceToken, channelIds) =&gt; {
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> channelId <span class="hljs-keyword">of</span> channelIds) {
    <span class="hljs-keyword">await</span> admin.messaging().subscribeToTopic(deviceToken, channelId);
  }
};
</code></pre>
<p>When the user logs out or disconnects:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> unsubscribeFromChannels = <span class="hljs-keyword">async</span> (deviceToken, channelIds) =&gt; {
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> channelId <span class="hljs-keyword">of</span> channelIds) {
    <span class="hljs-keyword">await</span> admin.messaging().unsubscribeFromTopic(deviceToken, channelId);
  }
};
</code></pre>
<hr />
<h2 id="heading-sending-a-message-to-a-topic">📩 Sending a Message to a Topic</h2>
<p>Here’s how to broadcast a message to all users in a channel:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> sendToTopic = <span class="hljs-keyword">async</span> (channelId, messageText) =&gt; {
  <span class="hljs-keyword">const</span> message = {
    <span class="hljs-attr">notification</span>: {
      <span class="hljs-attr">title</span>: <span class="hljs-string">"New Message"</span>,
      <span class="hljs-attr">body</span>: messageText,
    },
    <span class="hljs-attr">topic</span>: channelId,
  };

  <span class="hljs-keyword">await</span> admin.messaging().send(message);
};
</code></pre>
<p>This sends the message to <strong>all devices subscribed</strong> to the topic.</p>
<hr />
<h2 id="heading-why-this-works">🧠 Why This Works</h2>
<ul>
<li><p>It’s <strong>scalable</strong>: One message to many users.</p>
</li>
<li><p>It’s <strong>clean</strong>: No need to track tokens manually.</p>
</li>
<li><p>It’s <strong>flexible</strong>: You can dynamically subscribe/unsubscribe users as they join or leave channels.</p>
</li>
</ul>
<hr />
<h2 id="heading-final-thoughts">📌 Final Thoughts</h2>
<p>Using Firebase Topic Messaging helped us <strong>scale</strong> and <strong>simplify</strong> notification delivery in a chat system architecture. If you're still using the old token-based multi-send method, now’s a good time to switch.</p>
<p>This approach works especially well if:</p>
<ul>
<li><p>You have <strong>group-based features</strong> (like chat rooms, teams, or event channels)</p>
</li>
<li><p>You want to <strong>reduce memory usage</strong> and <strong>API calls</strong></p>
</li>
</ul>
<hr />
<h2 id="heading-want-to-try-it-yourself">🗨️ Want to Try It Yourself?</h2>
<p>Give it a shot! If you're working on a chat app or anything with groups or channels, topic messaging is worth exploring.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[N+1 Queries: The Simple Fix for Django APIs]]></title><description><![CDATA[Are your Django Rest Framework APIs feeling slow? Is your database groaning under the weight of too many queries? You might be facing the infamous N+1 query problem, a common performance bottleneck in ORM-based applications. In this post, we'll demys...]]></description><link>https://blog.sabinchapagain.com.np/n1-queries-the-simple-fix-for-django-apis</link><guid isPermaLink="true">https://blog.sabinchapagain.com.np/n1-queries-the-simple-fix-for-django-apis</guid><category><![CDATA[N+1]]></category><category><![CDATA[Django]]></category><category><![CDATA[drf]]></category><category><![CDATA[PostgreSQL]]></category><dc:creator><![CDATA[Sabin Chapagain]]></dc:creator><pubDate>Mon, 16 Jun 2025 13:18:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750260284294/20598920-a367-49d6-bd00-3e4b678e3293.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Are your Django Rest Framework APIs feeling slow? Is your database groaning under the weight of too many queries? You might be facing the infamous N+1 query problem, a common performance bottleneck in ORM-based applications. In this post, we'll demystify this issue and show you how to elegantly solve it using Django's powerful</strong> <code>select_related</code> and <code>prefetch_related</code> methods, turning slow APIs into speedy ones.</p>
<h3 id="heading-the-n1-query-problem-a-performance-killer">The N+1 Query Problem: A Performance Killer</h3>
<p>Imagine you have a <code>Book</code> model and an <code>Author</code> model, where each book has one author. When you try to list all books and display each book's author information, a naive approach might look something like this:</p>
<ol>
<li><p>Query for all <code>Book</code> objects (1 query).</p>
</li>
<li><p>For <em>each</em> <code>Book</code> object, query for its related <code>Author</code> (N queries, where N is the number of books).</p>
</li>
</ol>
<p>This quickly adds up, leading to N+1 queries for a seemingly simple operation. The problem becomes even more pronounced when you have nested serializers in Django Rest Framework (DRF), where a serializer might be calling other serializers, which in turn fetch more related data, creating a cascading N+1 nightmare.</p>
<p><strong>How we spotted it:</strong> We personally experienced this performance hit. Our API endpoints, particularly those involving deeply nested data structures returned by DRF serializers, were making an excessive number of database calls. Tools like the Django Debug Toolbar were invaluable in visualizing these redundant queries and pinpointing the exact areas causing the slowdown.</p>
<h3 id="heading-the-solution-selectrelated-and-prefetchrelated-to-the-rescue">The Solution: <code>select_related</code> and <code>prefetch_related</code> to the Rescue!</h3>
<p>Django provides two incredibly powerful tools to combat the N+1 problem:</p>
<h4 id="heading-1-selectrelated-for-one-to-one-and-many-to-one-relationships">1. <code>select_related()</code>: For One-to-One and Many-to-One Relationships</h4>
<p><code>select_related</code> performs an SQL JOIN and includes the fields of the related object in the <em>initial query</em>. This means that when you access the related object later, it's already available without needing an extra database hit. It's ideal for "forward" relationships (like <code>Book</code> to <code>Author</code>).</p>
<p><strong>Before (N+1 query):</strong></p>
<pre><code class="lang-python"><span class="hljs-comment"># views.py</span>
<span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> generics
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Book
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span> BookSerializer

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookListView</span>(<span class="hljs-params">generics.ListAPIView</span>):</span>
    queryset = Book.objects.all()
    serializer_class = BookSerializer

<span class="hljs-comment"># serializers.py</span>
<span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> serializers
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Book, Author

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthorSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = Author
        fields = [<span class="hljs-string">'name'</span>, <span class="hljs-string">'email'</span>]

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
    author = AuthorSerializer() <span class="hljs-comment"># This is where the N+1 typically happens</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = Book
        fields = [<span class="hljs-string">'title'</span>, <span class="hljs-string">'publication_date'</span>, <span class="hljs-string">'author'</span>]
</code></pre>
<p><strong>After (Optimized with</strong> <code>select_related</code>):</p>
<pre><code class="lang-python"><span class="hljs-comment"># views.py</span>
<span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> generics
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Book
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span> BookSerializer

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookListView</span>(<span class="hljs-params">generics.ListAPIView</span>):</span>
    <span class="hljs-comment"># Eagerly load the 'author' related object</span>
    queryset = Book.objects.select_related(<span class="hljs-string">'author'</span>).all()
    serializer_class = BookSerializer

<span class="hljs-comment"># serializers.py (no change needed here, as the problem was in the query)</span>
<span class="hljs-comment"># ... same as above ...</span>
</code></pre>
<p>By adding <code>select_related('author')</code>, Django fetches the author data in the same query as the book data, drastically reducing the number of database calls.</p>
<h4 id="heading-2-prefetchrelated-for-many-to-many-and-reverse-one-to-many-relationships">2. <code>prefetch_related()</code>: For Many-to-Many and Reverse One-to-Many Relationships</h4>
<p><code>prefetch_related</code> works differently. It performs a <em>separate lookup</em> for each relationship, and then performs a Python join to link them up. This is useful for "reverse" relationships (e.g., getting all <code>Book</code> objects for a given <code>Author</code>) or Many-to-Many relationships.</p>
<p>Let's say a <code>Book</code> can have multiple <code>Genre</code>s (Many-to-Many relationship).</p>
<p><strong>Before (N+1 query):</strong></p>
<pre><code class="lang-python"><span class="hljs-comment"># views.py</span>
<span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> generics
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Book
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span> BookSerializer

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookListView</span>(<span class="hljs-params">generics.ListAPIView</span>):</span>
    queryset = Book.objects.all()
    serializer_class = BookSerializer

<span class="hljs-comment"># serializers.py</span>
<span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> serializers
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Book, Author, Genre

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GenreSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = Genre
        fields = [<span class="hljs-string">'name'</span>]

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
    author = AuthorSerializer()
    genres = GenreSerializer(many=<span class="hljs-literal">True</span>) <span class="hljs-comment"># Another N+1 potential</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = Book
        fields = [<span class="hljs-string">'title'</span>, <span class="hljs-string">'publication_date'</span>, <span class="hljs-string">'author'</span>, <span class="hljs-string">'genres'</span>]
</code></pre>
<p><strong>After (Optimized with</strong> <code>prefetch_related</code>):</p>
<pre><code class="lang-python"><span class="hljs-comment"># views.py</span>
<span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> generics
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Book
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span> BookSerializer

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookListView</span>(<span class="hljs-params">generics.ListAPIView</span>):</span>
    <span class="hljs-comment"># Eagerly load 'author' and 'genres'</span>
    queryset = Book.objects.select_related(<span class="hljs-string">'author'</span>).prefetch_related(<span class="hljs-string">'genres'</span>).all()
    serializer_class = BookSerializer

<span class="hljs-comment"># serializers.py (no change needed here)</span>
<span class="hljs-comment"># ... same as above ...</span>
</code></pre>
<p>Here, <code>prefetch_related('genres')</code> fetches all associated genres in a separate, efficient query and then attaches them to the correct books in Python, avoiding N individual queries for each book's genres.</p>
<h3 id="heading-seeing-the-difference-with-django-debug-toolbar">Seeing the Difference with Django Debug Toolbar</h3>
<p>To truly appreciate the impact of these optimizations, tools like the Django Debug Toolbar are indispensable. Before applying <code>select_related</code> and <code>prefetch_related</code>, you'll likely see a large number of database queries for a single API call. After implementing these changes, you'll observe a dramatic reduction in the query count, leading to faster response times and a happier database.</p>
<h3 id="heading-key-takeaways-for-optimizing-your-drf-apis">Key Takeaways for Optimizing Your DRF APIs:</h3>
<ul>
<li><p><strong>Be aware of nested serializers:</strong> They are a common culprit for N+1 issues.</p>
</li>
<li><p><strong>Use</strong> <code>select_related</code> for One-to-One and Many-to-One relationships. It performs a SQL JOIN.</p>
</li>
<li><p><strong>Use</strong> <code>prefetch_related</code> for Many-to-Many and reverse One-to-Many relationships. It performs separate queries and a Python join.</p>
</li>
<li><p><strong>Always debug and profile:</strong> Tools like Django Debug Toolbar are your best friends for identifying and confirming performance bottlenecks.</p>
</li>
<li><p><strong>Start simple:</strong> Don't over-optimize prematurely. Address N+1 issues when you actually observe performance problems.</p>
</li>
</ul>
<p>By strategically applying <code>select_related</code> and <code>prefetch_related</code>, you can significantly boost the performance of your Django Rest Framework APIs, providing a smoother experience for your users and a lighter load on your database. Happy optimizing!</p>
]]></content:encoded></item></channel></rss>