<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>Syed Zubyl N | Software Developer - React Native</title>
      <link>https://syedzubyl.space</link>
      <description>Syed Zubyl N — Software Developer focused on Java, Spring Boot, backend development, REST APIs, databases, Flutter and production-oriented applications.</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://syedzubyl.space/tags/react-native/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Fri, 10 Apr 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>Building a Mobile Backend Integration with React Native and TypeScript</title>
          <pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate>
          <author>Syed Zubyl N</author>
          <link>https://syedzubyl.space/blog/react-native-typescript-integration/</link>
          <guid>https://syedzubyl.space/blog/react-native-typescript-integration/</guid>
          <description xml:base="https://syedzubyl.space/blog/react-native-typescript-integration/">&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h3&gt;
&lt;p&gt;While working on the Mercantile Society Onboarding application, we needed to build a seamless onboarding flow that connected a React Native frontend with a Node.js backend, Azure SQL for relational data, and external services like Razorpay for payments and Appwrite&#x2F;Supabase for authentication.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;context&quot;&gt;Context&lt;&#x2F;h3&gt;
&lt;p&gt;Cross-platform mobile applications often struggle with state management during complex, multi-step asynchronous flows. In an onboarding process, a user must authenticate, submit personal data, process a payment, and wait for external webhooks to confirm the transaction before proceeding to the final application state.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-i-tried&quot;&gt;What I Tried&lt;&#x2F;h3&gt;
&lt;p&gt;I initially tried to manage the onboarding state purely in React Native’s local component state (&lt;code&gt;useState&lt;&#x2F;code&gt;), chaining API calls sequentially on button presses.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-failed&quot;&gt;What Failed&lt;&#x2F;h3&gt;
&lt;p&gt;When a user’s network connection dropped midway through a payment process, the local state was lost. When they reopened the app, they had to start the onboarding flow from the beginning, resulting in duplicate payment attempts and a frustrating user experience.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-worked-technical-explanation&quot;&gt;What Worked &amp;amp; Technical Explanation&lt;&#x2F;h3&gt;
&lt;p&gt;The solution required shifting the state management authority from the mobile client to the backend database.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. Database-Driven State Machine&lt;&#x2F;strong&gt;
We designed the Azure SQL database to track an explicit &lt;code&gt;onboarding_status&lt;&#x2F;code&gt; for each user (e.g., &lt;code&gt;REGISTERED&lt;&#x2F;code&gt;, &lt;code&gt;DETAILS_SUBMITTED&lt;&#x2F;code&gt;, &lt;code&gt;PAYMENT_PENDING&lt;&#x2F;code&gt;, &lt;code&gt;COMPLETED&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. Idempotent API Endpoints&lt;&#x2F;strong&gt;
The Node.js (TypeScript) backend was written to be idempotent. If the React Native app sent the “submit details” payload twice due to a network retry, the backend simply acknowledged the existing state rather than duplicating rows.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;3. Webhook Integration&lt;&#x2F;strong&gt;
Instead of the mobile app waiting for a synchronous response from Razorpay, the mobile app initiated the payment and immediately polled a backend endpoint (or connected via WebSockets). The backend listened for Razorpay webhooks securely, updated the Azure SQL &lt;code&gt;onboarding_status&lt;&#x2F;code&gt;, and pushed the update to the client.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;4. React Native Architecture&lt;&#x2F;strong&gt;
In TypeScript, we defined strict interfaces shared (conceptually) between the backend and frontend.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; Shared Interface&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;interface&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; OnboardingStatus&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;  userId&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;  step&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;REGISTERED&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;PAYMENT_PENDING&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;COMPLETED&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;  isLocked&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; boolean&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The React Native application simply queried the &lt;code&gt;&#x2F;api&#x2F;user&#x2F;status&lt;&#x2F;code&gt; endpoint on mount and rendered the corresponding screen based on the backend’s source of truth.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;&#x2F;h3&gt;
&lt;p&gt;The mobile device is an unreliable environment. Never trust local memory to maintain critical business state (like payment processing steps). The backend database must act as the absolute source of truth, and the mobile app should function as a dumb terminal that simply renders whatever state the server returns.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-i-would-do-differently&quot;&gt;What I Would Do Differently&lt;&#x2F;h3&gt;
&lt;p&gt;I would implement an offline-first queuing system using a tool like WatermelonDB or Redux Offline. While the backend state machine solved the data integrity problem, the UX still suffered when users hit dead zones. A proper queue would allow users to submit onboarding documents offline and seamlessly sync them when connectivity returned.&lt;&#x2F;p&gt;
</description>
      </item>
    </channel>
</rss>
