<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Swapnil Devesh</title>
    <description>The latest articles on Forem by Swapnil Devesh (@sidevesh).</description>
    <link>https://forem.com/sidevesh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F322493%2Fc22af0b3-b97d-4691-aff6-79aeab46955b.jpg</url>
      <title>Forem: Swapnil Devesh</title>
      <link>https://forem.com/sidevesh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sidevesh"/>
    <language>en</language>
    <item>
      <title>If you use fetch() to make Backend API calls, you need to read this</title>
      <dc:creator>Swapnil Devesh</dc:creator>
      <pubDate>Sun, 26 Apr 2020 06:59:45 +0000</pubDate>
      <link>https://forem.com/sidevesh/if-you-use-fetch-to-make-backend-api-calls-you-need-to-read-this-1dd7</link>
      <guid>https://forem.com/sidevesh/if-you-use-fetch-to-make-backend-api-calls-you-need-to-read-this-1dd7</guid>
      <description>&lt;p&gt;Ever since first being introduced, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API"&gt;Fetch API&lt;/a&gt; has sort of become the de facto standard for fetching resources and interfacing with Backend API for modern web applications.&lt;/p&gt;

&lt;p&gt;While similar to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest"&gt;XMLHttpRequest&lt;/a&gt;, fetch provides a way more powerful API with a more flexible feature set. It is also available in &lt;code&gt;window&lt;/code&gt; as well as &lt;code&gt;worker&lt;/code&gt; and there are also libraries like &lt;a href="https://www.npmjs.com/package/node-fetch"&gt;node-fetch&lt;/a&gt; that allow it to be used in nodejs, basically fetch is available almost anywhere and in any context.&lt;/p&gt;

&lt;p&gt;It's promise based API makes it really simple to load resources asynchronously and also makes it simple to handle more complex cases like conditionally chaining fetching of other resources etc.&lt;/p&gt;

&lt;p&gt;While fetch() is great and really solves almost all the hassles of making API calls, often when using it (or actually any other method like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest"&gt;XMLHttpRequest&lt;/a&gt;, or &lt;a href="https://github.com/axios/axios"&gt;axios&lt;/a&gt; etc), we end up having to handle a lot of cases, from different error codes, to cases where network request fails, parsing of the response body into json or text, extracting or deciphering error reason to show to the user or to log etc.&lt;/p&gt;

&lt;p&gt;This often results in massive blocks being repeated with every Backend API interfacing function. The following code snippet would look very familiar to a lot of Frontend web developers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/v1/categories`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;errors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// handle json.data&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid token.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// in case of error, API returns array of error messages&lt;/span&gt;
      &lt;span class="c1"&gt;// handle error due to invalid token, initiate re-login or something else&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// handle any other error status codes&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// handle any other case, like json parse failure or network error&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Obviously, there is a lot going wrong in the above function, but can we make this better ?&lt;/p&gt;

&lt;p&gt;In case of any Backend API method, there would be status codes that indicate success cases (200, 201 etc) and standard ways to denote errors in case of failing status codes like (401, 404, 500 etc).&lt;/p&gt;

&lt;p&gt;The above code can be greatly simplified and made way less brittle if we can standardise the interface of our Backend API and use that standardised interface to make API calls.&lt;/p&gt;

&lt;p&gt;With that in mind, we can creating sort of a wrapper function that wraps our Backend API calls using fetch() and provides us with a standard interface to our Backend API call results, whether successful or failing.&lt;/p&gt;

&lt;p&gt;I have been using a function along these lines in a lot of my Frontend codebases and it has really helped simplify Backend API calls and to rapidly add new methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;responseParserTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parseResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseParserTypes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;responseParserTypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;fetchPromise&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;handledStatusCodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;parseHandledResponseAs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;parseUnhandledResponseAs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;getUnhandledResponseMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error occured&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;getFailureMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error occured&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseParserTypes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parseHandledResponseAs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`parseHandledResponseAs shouwld be one of [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseParserTypes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;]`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseParserTypes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parseUnhandledResponseAs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`parseUnhandledResponseAs shouwld be one of [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseParserTypes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;]`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fetchPromise&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handledStatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parseResponsePromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parseResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parseHandledResponseAs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;parseResponsePromise&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;parsedResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedResponse&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getFailureMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parseResponsePromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parseResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parseUnhandledResponseAs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;parseResponsePromise&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;parsedResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getUnhandledResponseMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nx"&gt;parsedResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getFailureMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getFailureMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;fetchHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can also find this at &lt;a href="https://gist.github.com/SiDevesh/adaf910bc384574b776c370f77b9bedf"&gt;https://gist.github.com/SiDevesh/adaf910bc384574b776c370f77b9bedf&lt;/a&gt; , this may also be more updated in future.&lt;/p&gt;

&lt;p&gt;Now let's see how the same &lt;code&gt;callCategoriesIndexPageItemsLoad&lt;/code&gt; method can be simplified using the above &lt;code&gt;fetchHandler&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCategories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fetchHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/v1/categories`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;handledStatusCodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;parseHandledResponseAs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;parseUnhandledResponseAs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;getUnhandledResponseMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parsedResponseBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Looks like you are logged out, redirecting to log in page...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong, we are looking into it&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unknown error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;getFailureMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// return proper error message for other failures,&lt;/span&gt;
      &lt;span class="c1"&gt;// like json parse error or network failure,&lt;/span&gt;
      &lt;span class="c1"&gt;// that can be figured out using the exception argument provided&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Network error occured&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With the above implementation, we would get proper error messages for each error status code as well as any other exception that can be then shown in the UI.&lt;/p&gt;

&lt;p&gt;Also, this automatically handles parsing the response so no need to chain the &lt;code&gt;response.json()&lt;/code&gt;, &lt;code&gt;reponse.text()&lt;/code&gt; or any other response parsing call.&lt;/p&gt;

&lt;p&gt;To use this method to get data is as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;getCategories&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// handle json.data&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// show errorMessage&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This should cover a lot of use cases, if there is need to perform actions in case of failure then rather than returning &lt;code&gt;string&lt;/code&gt; message in &lt;code&gt;getUnhandledResponseMessage&lt;/code&gt; and &lt;code&gt;getFailureMessage&lt;/code&gt;, we may also return an object containing the message as &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;statusCode&lt;/code&gt; or something else, which can then be checked for, and corresponding action can be performed.&lt;/p&gt;

&lt;p&gt;That's it then, hope this helps you streamline your Backend API call methods.&lt;/p&gt;

&lt;p&gt;Let me know if you have a better way or know of a library that helps with same.&lt;/p&gt;

&lt;p&gt;Hope this was helpful, if it was then do &lt;strong&gt;&lt;em&gt;follow me on &lt;a href="https://twitter.com/sid_devesh"&gt;twitter&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; for more such articles.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cheers!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>codequality</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Write once, run everywhere, with Flutter (finally)</title>
      <dc:creator>Swapnil Devesh</dc:creator>
      <pubDate>Sun, 26 Apr 2020 06:56:07 +0000</pubDate>
      <link>https://forem.com/sidevesh/write-once-run-everywhere-with-flutter-finally-28a3</link>
      <guid>https://forem.com/sidevesh/write-once-run-everywhere-with-flutter-finally-28a3</guid>
      <description>&lt;p&gt;Cross platform app development - being able to write something once and then have it run on different platforms is a dream that everyone from developers to large companies have been chasing for a long time. Ever since smartphones became the mainstay of computing though, this quest shifted more towards unifying development across Android and iOS.&lt;/p&gt;

&lt;p&gt;Recently &lt;strong&gt;I set out to build a cross platform pomodoro timer app&lt;/strong&gt;, something that can work on all the different devices and platforms we have today (let’s list it, &lt;strong&gt;Android&lt;/strong&gt;, &lt;strong&gt;iOS&lt;/strong&gt;, &lt;strong&gt;Linux&lt;/strong&gt;, &lt;strong&gt;MacOS&lt;/strong&gt;, &lt;strong&gt;Windows&lt;/strong&gt;), with a &lt;strong&gt;consistent and aesthetic UI&lt;/strong&gt; and be able to &lt;strong&gt;sync to cloud&lt;/strong&gt;, with some nice &lt;strong&gt;gamification&lt;/strong&gt; enhancements. My goal was to build this from a single codebase, rather than to build it seperately for each platform since that would mean writing the same thing 5 times! Now the main question is …&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So how do you build a cross platform app that you write once and then run everywhere from mobile platforms to the major desktop operating systems, in 2020 ?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Facebook made a huge development towards cross platform mobile apps development with release of &lt;a href="https://reactnative.dev/"&gt;React Native&lt;/a&gt; in 2015 and since then building mobile apps have really gotten way more simpler as well as accesible to a broader set of developers.&lt;/p&gt;

&lt;p&gt;And with release of &lt;a href="https://flutter.dev/"&gt;Flutter&lt;/a&gt; in 2017 by Google, building high fidelity mobile apps has been made incredibly simple, with developers and companies crafting amazing experiences and UIs using it.&lt;/p&gt;

&lt;p&gt;On the desktop side though, things were quite slow for a while till GitHub released &lt;a href="https://www.electronjs.org/"&gt;Electron&lt;/a&gt; in 2013, allowing web technologies and javascript to be used for writing desktop apps which greatly increased the speed and ease of development of desktop apps, and allowed the bigger pool of web developers to start building native desktop apps. These apps, while great, package the entire chromium engine to render the UI, which causes a major performance and battery life hit, annoying a lot of users. Mentioning of any new desktop app built using Electron almost always leads to a debate on merits and demerits of the framework.&lt;/p&gt;

&lt;p&gt;For apps which are more on the heavier side in terms of functionality, features and scope, such as IDEs, social platforms etc, Electron can be a really good choice since the additional heft from Electron won’t be that apparent given the scope of the app. &lt;strong&gt;120 or 200 MB is acceptable for a feature packed IDE but not for a small To Do app&lt;/strong&gt;. Visual Studio Code is a great example of this, arguably the Electron based app yet.&lt;/p&gt;

&lt;p&gt;For rest of the more single purpose apps, the fact that Electron based apps typically start at 120 MB atleast and consume massive amounts of RAM is a major issue and often we see &lt;strong&gt;users avoiding an app purely because of the unjustifiable performance impact of Electron&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;While we are on the subject of cross platform apps, &lt;strong&gt;Electron still doesn’t allow for building apps for the mobile platforms,&lt;/strong&gt;and probably never will given its focus exclusively on desktop platforms.&lt;/p&gt;

&lt;p&gt;There are some projects that allow &lt;strong&gt;React Native to extend from mobile side of things to desktop&lt;/strong&gt;, such as &lt;a href="https://github.com/microsoft/react-native-windows"&gt;react-native-windows&lt;/a&gt; and &lt;a href="https://github.com/ptmt/react-native-macos"&gt;react-native-macos&lt;/a&gt;. But most of these projects still require considerable work before going mainstream . Also, with their inherent platform differences and the way React Native works, these cannot exactly be used for a “write once and run everywhere” experience, &lt;strong&gt;most often the UI for each platform will have to be written differently&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now out of all the technologies we discussed above, let’s figure out which one to use.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We could have used Electron but then for the mobile platforms, we would have to build, or atleast package the web app code separately with something else like PhoneGap or Cordova, which is not the best experience anyways on mobile devices, &lt;strong&gt;web apps often don’t match the fidelity of native UIs and that gets especially more apparent on touch based mobile devices&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We could have used React Native but then we would be building the UI part seperately for the desktop platforms using react-native-windows AND react-native-macos, that means writing the UI three times! Once for mobile platforms with react-native and then once for Windows using react-native-windows and then again for MacOS with react-native-macos, and we are still forgetting Linux.&lt;/p&gt;

&lt;p&gt;While &lt;strong&gt;React Native is not there yet to build desktop apps&lt;/strong&gt;, &lt;strong&gt;Flutter on the other hand&lt;/strong&gt; has recently seen significant developments, both &lt;a href="https://flutter.dev/desktop"&gt;official&lt;/a&gt; as well as from community to bring its support to desktop platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The official Flutter team recently released support for desktop platforms in alpha&lt;/strong&gt;, currently that only supports the MacOS platform though and is not considered completely stable yet anyways.&lt;/p&gt;

&lt;p&gt;The architecture of Flutter is considerably more easier to bring to new platforms than React Native, thanks to the fact that &lt;strong&gt;it doesn’t rely on the native widgets of the platform and draws all its widget on its own&lt;/strong&gt; (for web developers, it draws the UI more like a its drawing inside a canvas element and less like DOM elements). Plus another benefit of this approach is that &lt;strong&gt;the same extremely huge set of widgets available on Flutter is also available on any new platform, developers are good to go from the beginning to develop incredibly complex UIs from the very start. No need to wait for &lt;a href="https://microsoft.github.io/react-native-windows/docs/parity-status"&gt;components to catch up&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Although another really interesting project &lt;strong&gt;I came across was &lt;a href="https://github.com/go-flutter-desktop/go-flutter"&gt;go-flutter desktop&lt;/a&gt;, which uses Go and GLFW to bring Flutter to desktop&lt;/strong&gt;, basically the platform side of things for Flutter is handled by Go in a cross platform (Windows, Linux and MacOS) way for all the desktop platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using it to bring a Flutter app to desktop is as simple as running a single command in the project and that’s it!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now talking about the experience of using Flutter as a developer to build an app, its one of the &lt;em&gt;smoothest flow that I have experienced in a longwhile&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9CtrxqRD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sidevesh.com/blog/static/dc6fda0fee4a2829ce5ed6a6f14778ef/eea4a/dartpad-flutter.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9CtrxqRD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sidevesh.com/blog/static/dc6fda0fee4a2829ce5ed6a6f14778ef/eea4a/dartpad-flutter.jpg" alt="Screenshot of DartPad, building the Flutter app UI" title="Building Flutter app UI in DartPad, on the web"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My workflow for building the app was pretty simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To try and test different UI possibilities, I started building the prototype of the UI online! &lt;strong&gt;No need to spend time setting up Flutter toolchain, Android studio, Xcode or anything else at all!&lt;/strong&gt; With the support for Flutter added to &lt;a href="https://dartpad.dartlang.org/"&gt;DartPad&lt;/a&gt;, we can start building Flutter apps directly from browser and quickly iterate on ideas.&lt;/li&gt;
&lt;li&gt;Once the UI was ready to go, I switched to setting up Flutter on the system itself . Then I wrote the rest of the functional and native integration dependent parts of the app, things like splite db, key-value store etc.&lt;/li&gt;
&lt;li&gt;Once the app was completely ready, the Android and iOS builds can be created using the flutter toolchain itself:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter build apk
flutter build ios
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For the desktop apps including the installers, Its as simple as running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;hover build windows-msi
hover build darwin-dmg
hover build linux-deb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/go-flutter-desktop/hover"&gt;Hover&lt;/a&gt;, is part of the go-flutter-desktop project itself and handles building the releases for the desktop platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And that’s it!&lt;/strong&gt;, you now have setup package for Windows, dmg installer for MacOS and deb package for Debian based Linux distros (It can also build rpm, appimage and snap packages for other Linux distros), all ready to be distributed, along with the usual Android and iOS binaries ready to push to their respective stores.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And with that you have your app ready to go for any major desktop or mobile platform!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But that’s not all though…&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Flutter actually also &lt;strong&gt;supports web in beta&lt;/strong&gt;! That means the same code can actually also be used to create a web app version.&lt;/p&gt;

&lt;p&gt;Although I didn’t need that for my project and plus I ran into some small issues with the web support that’s still being worked on by Flutter team.&lt;/p&gt;

&lt;p&gt;Also, &lt;strong&gt;any plugin that is used in the app like sqlite (which was used in my app), key value storage etc will require their platform side of code to be written in Go to bring it to desktop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;While the process is not that difficult, its still an extra step in a different environment, since your Flutter app is gonna be written in dart completely otherwise.&lt;/p&gt;

&lt;p&gt;Although &lt;strong&gt;the go-flutter-desktop and the community around it do provide the desktop port of several of the most common plugins&lt;/strong&gt; used in the Flutter ecosystem which covers most of the stuff that a standard app would need.&lt;/p&gt;

&lt;p&gt;Another consideration when evaluating this is that, since &lt;strong&gt;Flutter currently only has the widgets for Material UI and iOS interface&lt;/strong&gt;, if you want your app to look like any other truly native app on your desktop, you will have to create the UI components from scratch on your own which might be a significant effort.&lt;/p&gt;

&lt;p&gt;This was not a problem with my app since the UI was designed to look and behave the same on all platforms and &lt;strong&gt;I think just using Material UI widgets with some small changes to fit your product’s design language would actually suffice for most apps&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;So there you go, although there is still a lot of development yet to happen to bring this to maturity for most production level apps, I think that the toolchain is in a very good stage and progressing towards even better future where we can finally build apps for all the different platforms with an incredible UX and that too with just one codebase!&lt;/p&gt;

&lt;p&gt;Hope this was helpful, if it was then do &lt;strong&gt;&lt;em&gt;follow me on &lt;a href="https://twitter.com/sid_devesh"&gt;twitter&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; for more such articles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Also, do check out the app that I built and described the process for above at &lt;a href="https://tomatoro.app"&gt;https://tomatoro.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cheers!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>electron</category>
      <category>desktop</category>
    </item>
  </channel>
</rss>
