<?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 - Dart</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/dart/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Thu, 05 Mar 2026 00:00:00 +0000</lastBuildDate>
      <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>
    </channel>
</rss>
