<?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 - API</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/api/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Mon, 18 May 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>What I Learned Building Flutter Applications Around Real APIs</title>
          <pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate>
          <author>Syed Zubyl N</author>
          <link>https://syedzubyl.space/blog/building-flutter-apps-around-apis/</link>
          <guid>https://syedzubyl.space/blog/building-flutter-apps-around-apis/</guid>
          <description xml:base="https://syedzubyl.space/blog/building-flutter-apps-around-apis/">&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h3&gt;
&lt;p&gt;Building a UI in Flutter is relatively straightforward. The real complexity begins when you connect that beautiful UI to a real-world, unpredictable REST API. Handling token expiration, offline states, local caching, and malformed JSON payloads quickly turns a simple app into a debugging nightmare.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;context&quot;&gt;Context&lt;&#x2F;h3&gt;
&lt;p&gt;While building a mobile LMS (Learning Management System) application in Flutter, I needed to fetch course catalogs, stream videos, and issue certificates. This required robust communication with a backend API while ensuring the app remained responsive even when the user’s internet connection was spotty.&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 relied solely on the network. Every time a user opened a screen, a &lt;code&gt;FutureBuilder&lt;&#x2F;code&gt; would fire off an HTTP request and display a loading spinner until the data arrived.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-failed&quot;&gt;What Failed&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Poor UX:&lt;&#x2F;strong&gt; Users stared at loading spinners constantly.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Offline Experience:&lt;&#x2F;strong&gt; If a user boarded a subway, the app became completely useless. It crashed or showed generic error screens.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;API Rate Limiting:&lt;&#x2F;strong&gt; Spamming the backend with requests every time a user switched tabs was highly inefficient.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;what-worked-technical-explanation&quot;&gt;What Worked &amp;amp; Technical Explanation&lt;&#x2F;h3&gt;
&lt;p&gt;I shifted to a &lt;strong&gt;Local-First Architecture&lt;&#x2F;strong&gt; using SQLite (via the &lt;code&gt;sqflite&lt;&#x2F;code&gt; package).&lt;&#x2F;p&gt;
&lt;p&gt;Instead of the UI talking directly to the API, the UI only talks to the local SQLite database. A separate background synchronization engine talks to the API.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The Flow:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;User opens the Course List screen.&lt;&#x2F;li&gt;
&lt;li&gt;The UI reads immediately from SQLite and displays cached data (instant load).&lt;&#x2F;li&gt;
&lt;li&gt;In the background, the app fires an API request to check for updates.&lt;&#x2F;li&gt;
&lt;li&gt;If the API returns new data, it updates the SQLite database.&lt;&#x2F;li&gt;
&lt;li&gt;The UI, listening to a stream from the database, automatically rebuilds with the fresh data.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;Handling API Failures:&lt;&#x2F;strong&gt;
If an API request fails (e.g., user is offline, or the server returns a 500 error), the app simply logs the failure silently. The user is still looking at the cached data from SQLite and can continue interacting with the app.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Never trust the network.&lt;&#x2F;strong&gt; The network will fail, it will be slow, and it will return unexpected data.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Defensive Parsing:&lt;&#x2F;strong&gt; Always wrap JSON parsing in try-catch blocks or use robust code-generation tools. One unexpected &lt;code&gt;null&lt;&#x2F;code&gt; field from the backend can crash the entire Flutter isolate.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Local State is King:&lt;&#x2F;strong&gt; For an app to feel fast and native, data must be available locally on the device the millisecond the screen renders.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;what-i-would-do-differently&quot;&gt;What I Would Do Differently&lt;&#x2F;h3&gt;
&lt;p&gt;Instead of writing raw SQL queries for SQLite, I would adopt a higher-level reactive database like Isar or ObjectBox. They provide out-of-the-box stream capabilities that make tying local database updates directly to Flutter’s reactive UI significantly easier than building custom &lt;code&gt;StreamControllers&lt;&#x2F;code&gt; over &lt;code&gt;sqflite&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Designing a Reliable API Layer for a Mobile Application</title>
          <pubDate>Sun, 22 Mar 2026 00:00:00 +0000</pubDate>
          <author>Syed Zubyl N</author>
          <link>https://syedzubyl.space/blog/designing-reliable-api-layer/</link>
          <guid>https://syedzubyl.space/blog/designing-reliable-api-layer/</guid>
          <description xml:base="https://syedzubyl.space/blog/designing-reliable-api-layer/">&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h3&gt;
&lt;p&gt;In the early stages of a mobile LMS application, HTTP requests were scattered directly inside UI widgets. Buttons would execute &lt;code&gt;http.get&lt;&#x2F;code&gt;, parse JSON inline, and call &lt;code&gt;setState&lt;&#x2F;code&gt;. This quickly became unmaintainable. Token expiration caused random crashes, error handling was inconsistent, and mocking data for tests was impossible.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;context&quot;&gt;Context&lt;&#x2F;h3&gt;
&lt;p&gt;A robust mobile application requires a strict separation of concerns. The UI should only care about &lt;em&gt;displaying&lt;&#x2F;em&gt; state, not fetching it. The networking layer must handle token injection, timeouts, retries, and error standardization before the data ever reaches the UI.&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 create a single massive &lt;code&gt;ApiService&lt;&#x2F;code&gt; class that contained every single endpoint in the application.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-failed&quot;&gt;What Failed&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;ApiService&lt;&#x2F;code&gt; file grew to thousands of lines. When multiple developers worked on different features (Authentication, Courses, User Profile), merge conflicts became a daily nightmare. Furthermore, handling token refreshes on a per-method basis resulted in heavily duplicated code.&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;I re-architected the API layer into a layered, modular system based on the Repository Pattern and Interceptors.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. The Base HTTP Client (The Interceptor Layer)&lt;&#x2F;strong&gt;
Instead of using raw &lt;code&gt;http.Client&lt;&#x2F;code&gt;, I implemented a wrapper (using packages like &lt;code&gt;dio&lt;&#x2F;code&gt; or custom &lt;code&gt;http.BaseClient&lt;&#x2F;code&gt; implementations) that intercepts every request.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Request Interceptor:&lt;&#x2F;strong&gt; Automatically injects the &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;&#x2F;code&gt; header from secure storage into every outgoing request.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Response Interceptor:&lt;&#x2F;strong&gt; Global error handling. If a &lt;code&gt;401 Unauthorized&lt;&#x2F;code&gt; is returned, the interceptor pauses all outgoing requests, silently hits the refresh-token endpoint, updates secure storage, and retries the failed requests.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;2. Domain-Specific Repositories&lt;&#x2F;strong&gt;
Instead of one massive API class, I created focused repositories:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AuthRepository&lt;&#x2F;code&gt;: Handles login, registration, and token management.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;CourseRepository&lt;&#x2F;code&gt;: Fetches course lists and lesson details.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;VideoRepository&lt;&#x2F;code&gt;: Manages video streaming URLs and playback telemetry.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;3. Standardized Result Wrappers&lt;&#x2F;strong&gt;
Instead of throwing exceptions directly into the UI, repositories return a standardized Result type (often using Dart’s &lt;code&gt;Either&lt;&#x2F;code&gt; pattern via the &lt;code&gt;fpdart&lt;&#x2F;code&gt; or &lt;code&gt;dartz&lt;&#x2F;code&gt; package).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;Future&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;Either&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;ApiFailure&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; Course&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; getCourseDetails&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt; id) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;async&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: #F97583;&quot;&gt;  try&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: #F97583;&quot;&gt;    final&lt;&#x2F;span&gt;&lt;span&gt; response &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;= await&lt;&#x2F;span&gt;&lt;span&gt; _client.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&#x2F;courses&#x2F;$&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&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: #F97583;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; Right&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;Course&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;fromJson&lt;&#x2F;span&gt;&lt;span&gt;(response.data));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  } &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; DioError&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; catch&lt;&#x2F;span&gt;&lt;span&gt; (e) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; Left&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;ApiFailure&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;fromDioError&lt;&#x2F;span&gt;&lt;span&gt;(e));&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;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;h3 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;&#x2F;h3&gt;
&lt;p&gt;Separating the UI from the network layer is non-negotiable for production apps. The complexity of handling network latency, offline states, and token lifecycles must be encapsulated so the UI can remain declarative and clean.&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 local caching (using SQLite) much earlier in the architecture. While the API layer was robust, relying entirely on network availability resulted in a poor experience on slow connections. Integrating a repository that checks local storage &lt;em&gt;before&lt;&#x2F;em&gt; hitting the API is the next logical step.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>When API Response Types Don&#x27;t Match Your Flutter Model</title>
          <pubDate>Thu, 05 Mar 2026 00:00:00 +0000</pubDate>
          <author>Syed Zubyl N</author>
          <link>https://syedzubyl.space/blog/api-response-types-mismatch/</link>
          <guid>https://syedzubyl.space/blog/api-response-types-mismatch/</guid>
          <description xml:base="https://syedzubyl.space/blog/api-response-types-mismatch/">&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h3&gt;
&lt;p&gt;A Flutter application was crashing on the profile screen with a cryptic error in the console:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;type &amp;#39;int&amp;#39; is not a subtype of type &amp;#39;bool?&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The app compiled perfectly, the API returned a 200 OK, but the JSON deserialization failed entirely, resulting in a red screen of death in debug mode (and a blank screen in production).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;context&quot;&gt;Context&lt;&#x2F;h3&gt;
&lt;p&gt;In Dart, type safety is strict. When you parse a JSON response, you typically map a &lt;code&gt;Map&amp;lt;String, dynamic&amp;gt;&lt;&#x2F;code&gt; into a strongly-typed Dart object.&lt;&#x2F;p&gt;
&lt;p&gt;Our model looked like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; UserProfile&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: #F97583;&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span&gt; name;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt; isPremium;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  UserProfile&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;required&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; this&lt;&#x2F;span&gt;&lt;span&gt;.name,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; this&lt;&#x2F;span&gt;&lt;span&gt;.isPremium});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  factory&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; UserProfile&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;fromJson&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;Map&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&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;span style=&quot;color: #79B8FF;&quot;&gt; dynamic&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; json) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; UserProfile&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;      name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; json[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;name&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&gt;      isPremium&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; json[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;isPremium&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&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;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;h3 id=&quot;what-i-tried&quot;&gt;What I Tried&lt;&#x2F;h3&gt;
&lt;p&gt;I checked the backend documentation (Swagger&#x2F;OpenAPI). The documentation clearly stated that &lt;code&gt;isPremium&lt;&#x2F;code&gt; was a boolean. I assumed the issue was a null value since &lt;code&gt;isPremium&lt;&#x2F;code&gt; might not exist for legacy users, but I had already marked it as nullable (&lt;code&gt;bool?&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-failed&quot;&gt;What Failed&lt;&#x2F;h3&gt;
&lt;p&gt;Ignoring the type cast didn’t work. The exception specifically complained about an &lt;code&gt;int&lt;&#x2F;code&gt;.&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;I intercepted the raw HTTP response body before it hit the Dart parser.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&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: #79B8FF;&quot;&gt;  &amp;quot;name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Syed&amp;quot;&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: #79B8FF;&quot;&gt;  &amp;quot;isPremium&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&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 backend developer had migrated the database, and the new database driver was serializing SQL &lt;code&gt;TINYINT(1)&lt;&#x2F;code&gt; boolean columns into &lt;code&gt;1&lt;&#x2F;code&gt; and &lt;code&gt;0&lt;&#x2F;code&gt; integers in the JSON payload, rather than &lt;code&gt;true&lt;&#x2F;code&gt; and &lt;code&gt;false&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Because &lt;code&gt;json[&#x27;isPremium&#x27;]&lt;&#x2F;code&gt; contained an integer &lt;code&gt;1&lt;&#x2F;code&gt;, Dart crashed when it implicitly tried to cast it to &lt;code&gt;bool?&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To fix this, I implemented &lt;strong&gt;defensive serialization&lt;&#x2F;strong&gt;. Instead of trusting the API contract blindly, the Dart parser needs to handle potential type coercion gracefully:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;factory&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; UserProfile&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;fromJson&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;Map&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&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;span style=&quot;color: #79B8FF;&quot;&gt; dynamic&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; json) {&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;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &#x2F;&#x2F; Defensive parsing function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  bool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; parseBool&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;dynamic&lt;&#x2F;span&gt;&lt;span&gt; value) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (value &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; null&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; null&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: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (value &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;is&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; value;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (value &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;is&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; value &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&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: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (value &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;is&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;span style=&quot;color: #F97583;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; value.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;toLowerCase&lt;&#x2F;span&gt;&lt;span&gt;() &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;true&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: #F97583;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; null&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;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; UserProfile&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;    name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; json[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;name&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;] &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;Unknown&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&gt;    isPremium&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; parseBool&lt;&#x2F;span&gt;&lt;span&gt;(json[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;isPremium&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&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;h3 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;API Contracts Drift:&lt;&#x2F;strong&gt; Backend implementations change, and serialization layers can inadvertently alter the types of JSON payloads (especially converting booleans to integers or numbers to strings).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Dart is Unforgiving:&lt;&#x2F;strong&gt; Unlike JavaScript, Dart will not automatically coerce &lt;code&gt;1&lt;&#x2F;code&gt; into &lt;code&gt;true&lt;&#x2F;code&gt;. You must handle the conversion explicitly.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&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 will use code-generation tools like &lt;code&gt;json_serializable&lt;&#x2F;code&gt; or &lt;code&gt;freezed&lt;&#x2F;code&gt; with custom &lt;code&gt;JsonConverter&lt;&#x2F;code&gt; classes for primitive types. This abstracts away the boilerplate of defensive parsing and ensures the entire app handles API type mismatches consistently.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Debugging a 405 Method Not Allowed Error in a Mobile API</title>
          <pubDate>Sat, 14 Feb 2026 00:00:00 +0000</pubDate>
          <author>Syed Zubyl N</author>
          <link>https://syedzubyl.space/blog/debugging-405-error/</link>
          <guid>https://syedzubyl.space/blog/debugging-405-error/</guid>
          <description xml:base="https://syedzubyl.space/blog/debugging-405-error/">&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h3&gt;
&lt;p&gt;While developing a mobile application, a specific API endpoint for fetching user profile data suddenly started failing. The mobile client was receiving a &lt;code&gt;405 Method Not Allowed&lt;&#x2F;code&gt; HTTP status code, and the data refused to load.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;context&quot;&gt;Context&lt;&#x2F;h3&gt;
&lt;p&gt;The application relies on a Spring Boot backend exposing RESTful endpoints. The mobile client (built in Flutter) communicates with this API using the &lt;code&gt;http&lt;&#x2F;code&gt; package. The endpoint in question was &lt;code&gt;&#x2F;api&#x2F;v1&#x2F;users&#x2F;profile&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-i-tried&quot;&gt;What I Tried&lt;&#x2F;h3&gt;
&lt;p&gt;At first, I assumed the authentication token was invalid or the endpoint URL was misspelled.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;I checked the JWT token — it was valid.&lt;&#x2F;li&gt;
&lt;li&gt;I verified the URL string in the Dart code — it perfectly matched the backend controller.&lt;&#x2F;li&gt;
&lt;li&gt;I checked the server logs, expecting to see a &lt;code&gt;NullPointerException&lt;&#x2F;code&gt; or a &lt;code&gt;400 Bad Request&lt;&#x2F;code&gt;. Instead, Spring Security was just quietly rejecting the request at the filter level.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;what-failed&quot;&gt;What Failed&lt;&#x2F;h3&gt;
&lt;p&gt;I spent an hour looking at the backend logic, assuming the database query was failing or the routing was broken. None of this was the issue because the request wasn’t even reaching my controller method.&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 breakthrough came when I bypassed the mobile app entirely and used Postman to test the endpoint.&lt;&#x2F;p&gt;
&lt;p&gt;When I sent a &lt;code&gt;GET&lt;&#x2F;code&gt; request in Postman: &lt;strong&gt;200 OK.&lt;&#x2F;strong&gt;
When I looked closely at my Flutter network layer:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; The bug&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;final&lt;&#x2F;span&gt;&lt;span&gt; response &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;= await&lt;&#x2F;span&gt;&lt;span&gt; http.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;post&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: #79B8FF;&quot;&gt;  Uri&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;parse&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;https:&#x2F;&#x2F;api.example.com&#x2F;api&#x2F;v1&#x2F;users&#x2F;profile&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&gt;  headers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;Authorization&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;Bearer $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;token&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&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&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The issue was glaringly simple: I was using &lt;code&gt;http.post&lt;&#x2F;code&gt; for an endpoint that the backend explicitly defined as a &lt;code&gt;@GetMapping&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;code&gt;405 Method Not Allowed&lt;&#x2F;code&gt; means exactly what it says: the server exists, the route exists, but the HTTP verb (GET, POST, PUT, DELETE) you used is not supported for that specific route. It is fundamentally different from a &lt;code&gt;404 Not Found&lt;&#x2F;code&gt; (route doesn’t exist) or a &lt;code&gt;400 Bad Request&lt;&#x2F;code&gt; (payload is wrong).&lt;&#x2F;p&gt;
&lt;p&gt;I corrected the mobile client to use &lt;code&gt;http.get&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; The fix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;final&lt;&#x2F;span&gt;&lt;span&gt; response &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;= await&lt;&#x2F;span&gt;&lt;span&gt; http.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;get&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: #79B8FF;&quot;&gt;  Uri&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;parse&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;https:&#x2F;&#x2F;api.example.com&#x2F;api&#x2F;v1&#x2F;users&#x2F;profile&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&gt;  headers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;Authorization&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;Bearer $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;token&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&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&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Read the HTTP Status Code literally.&lt;&#x2F;strong&gt; Don’t assume a 405 is a generic crash. It has a highly specific meaning defined by the HTTP protocol.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Isolate the client from the server.&lt;&#x2F;strong&gt; When an API fails in a mobile app, test the exact same request in &lt;code&gt;curl&lt;&#x2F;code&gt; or Postman immediately. This tells you instantly if the bug is in the client code (Flutter) or the server code (Spring Boot).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&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 will implement a centralized API client class in Flutter with strict typed methods (&lt;code&gt;fetchProfile()&lt;&#x2F;code&gt;, &lt;code&gt;updateProfile()&lt;&#x2F;code&gt;) rather than writing raw &lt;code&gt;http.get&lt;&#x2F;code&gt; or &lt;code&gt;http.post&lt;&#x2F;code&gt; calls scattered throughout the UI code. This reduces the surface area for simple typo bugs like using the wrong HTTP verb.&lt;&#x2F;p&gt;
</description>
      </item>
    </channel>
</rss>
