<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ API - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ API - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 24 Jun 2026 10:06:07 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/API/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Extend CRUD Operations to Align with Business Workflows ]]>
                </title>
                <description>
                    <![CDATA[ Most developers are introduced to databases and APIs through a simple pattern: CRUD—Create, Read, Update, Delete. It seems like the perfect abstraction. With just four operations, you can model almost anything. Tutorials use it. Frameworks generate i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/extend-crud-operations-to-align-with-business-workflows/</link>
                <guid isPermaLink="false">68c19bc01159a9ac851f6cb5</guid>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Backend Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tim Kleier ]]>
                </dc:creator>
                <pubDate>Wed, 10 Sep 2025 15:39:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757518255485/8e727e36-d22a-42d9-b1a7-98d3ca5eae35.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Most developers are introduced to databases and APIs through a simple pattern: CRUD—Create, Read, Update, Delete. It seems like the perfect abstraction. With just four operations, you can model almost anything. Tutorials use it. Frameworks generate it. We teach it to beginners as the foundation of working with data.</p>
<p>But once you move beyond basic apps, CRUD starts to fall apart.</p>
<p>Real-world systems don’t just “update” or “delete” things. In a loan application system, for example, borrowers “submit” applications, loan officers “approve” or “reject” them, and applications are eventually “archived”. These aren’t generic CRUD operations—they’re <strong>domain-specific actions</strong> that carry meaning.</p>
<p>And that’s the problem: CRUD hides the meaning of our systems behind vague verbs. REST APIs inherit the same issue, mapping HTTP verbs onto CRUD but still failing to express real workflows clearly.</p>
<p>In this article, we’ll explore:</p>
<ul>
<li><p>Why CRUD works fine for simple apps but becomes an anti-pattern at scale</p>
</li>
<li><p>How concepts like <strong>upsert</strong>, <strong>archive</strong>, and <strong>bulk operations</strong> reveal its cracks</p>
</li>
<li><p>Why REST doesn’t solve these issues</p>
</li>
<li><p>How to design APIs around domain actions and workflows instead.</p>
</li>
</ul>
<p>By the end, you’ll see CRUD for what it really is—a teaching tool, not a design philosophy.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-crud">What is CRUD?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-stretching-crud-upsert-archive-bulk">Stretching CRUD: Upsert, Archive, Bulk</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-breaking-crud-domain-actions">Breaking CRUD: Domain Actions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-breaking-crud-domain-authorization">Breaking CRUD: Domain Authorization</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-crud-alternative-align-to-workflows">CRUD Alternative: Align to Workflows</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-crud">What is CRUD?</h2>
<p><strong>Create, Read, Update, Delete</strong>—these are the four basic operations we perform on data in a database.</p>
<ul>
<li><p><strong>Create</strong> – adds a new record.</p>
</li>
<li><p><strong>Read</strong> – fetches an existing record (or list of records).</p>
</li>
<li><p><strong>Update</strong> – changes one or more fields in a record.</p>
</li>
<li><p><strong>Delete</strong> – removes a record.</p>
</li>
</ul>
<p>For example, in a typical Node.js + Express app managing users:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Create a user</span>
app.post(<span class="hljs-string">'/users'</span>, createUser);

<span class="hljs-comment">// Read a user</span>
app.get(<span class="hljs-string">'/users/:id'</span>, getUser);

<span class="hljs-comment">// Update a user</span>
app.put(<span class="hljs-string">'/users/:id'</span>, updateUser);

<span class="hljs-comment">// Delete a user</span>
app.delete(<span class="hljs-string">'/users/:id'</span>, deleteUser);
</code></pre>
<p>This maps directly to the underlying SQL:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (...);
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = ...;
<span class="hljs-keyword">UPDATE</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">SET</span> ... <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = ...;
<span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = ...;
</code></pre>
<p>And that’s CRUD in its purest form—four operations that can describe almost any database interaction.</p>
<h2 id="heading-stretching-crud-upsert-archive-bulk">Stretching CRUD: Upsert, Archive, Bulk</h2>
<p>Developers quickly realize CRUD isn’t enough, so they invent extensions:</p>
<ul>
<li><p><strong>Upsert</strong>: a mix of “update” and “insert.” If the record exists, update it; if not, create it.</p>
</li>
<li><p><strong>Archive</strong>: instead of deleting a record, we “soft delete” or mark it as inactive so the history stays intact.</p>
</li>
<li><p><strong>Bulk operations</strong>: run create, update, or delete on many records at once for efficiency.</p>
</li>
</ul>
<p>These solve real problems, but they stretch CRUD’s simple model. We now need to distinguish between single and bulk resource actions. And we also need to factor in the technical concerns of upsertions and soft deletions.</p>
<h2 id="heading-breaking-crud-domain-actions">Breaking CRUD: Domain Actions</h2>
<p>The technical domain itself stretches CRUD substantially, but business domain concerns break it entirely. Take a loan application system:</p>
<ul>
<li><p>A borrower doesn’t “create” and “update” an application—they start, submit, or withdraw it.</p>
</li>
<li><p>A loan officer doesn’t “update” an application—they review, approve, or reject it.</p>
</li>
<li><p>Applications don’t get “deleted”—they’re usually archived so there’s a record for compliance.</p>
</li>
</ul>
<p>If we try to model these as plain CRUD, the meaning gets lost:</p>
<pre><code class="lang-http"><span class="hljs-attribute">PATCH /applications/123 { "status"</span>: "approved" }
</code></pre>
<p>Technically, it works. But what does “update” really mean here? Was the application submitted, rejected, or archived? You can’t tell from the API call.</p>
<p>The core problem: CRUD hides intent behind generic, technical language. Real business processes are expressed as domain-specific actions, not generic updates or deletes.</p>
<h2 id="heading-breaking-crud-domain-authorization">Breaking CRUD: Domain Authorization</h2>
<p>CRUD not only obscures intent—it also creates authorization gaps. Using the same loan application example:</p>
<ul>
<li><p>Only loan officers should approve applications.</p>
</li>
<li><p>Borrowers should only edit their own information or withdraw their applications.</p>
</li>
</ul>
<p>If “approve” is just modeled as a generic update, the system can’t distinguish between roles without additional checks. A naive authorization rule like “can this user update?” suddenly lets borrowers perform actions reserved for officers.</p>
<p>This mismatch between technical verbs and business rules can lead to:</p>
<ul>
<li><p>Security issues—unauthorized actions performed by the wrong user.</p>
</li>
<li><p>Audit problems—it’s unclear who did what, and when.</p>
</li>
<li><p>Workflow confusion—state transitions get lost in generic updates.</p>
</li>
</ul>
<p>The solution: treat each domain action as its own API call with explicit authorization rules:</p>
<pre><code class="lang-http"><span class="hljs-attribute">POST /applications/123/approve   # Only accessible to loan officers
POST /applications/123/withdraw  # Only accessible to the borrower</span>
</code></pre>
<p>By modeling actions instead of CRUD operations, intent and permissions are clear, reducing both bugs and security risks.</p>
<h2 id="heading-crud-alternative-align-to-workflows">CRUD Alternative: Align to Workflows</h2>
<p>Real-world applications follow workflows—sequences of states that a resource moves through. Take our loan application example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757257665063/f26ce4c4-afee-4b03-8ddc-bdb724aa9850.png" alt="Loan Application Workflow Diagram" class="image--center mx-auto" width="681" height="674" loading="lazy"></p>
<p>Here’s what the corresponding API endpoints might look like:</p>
<pre><code class="lang-http"># Borrower actions
<span class="hljs-attribute">POST /applications/123/submit       # Draft → Submitted
POST /applications/123/withdraw     # Draft/Submitted → Closed

# Loan officer actions
POST /applications/123/approve      # Submitted → Approved
POST /applications/123/reject       # Submitted → Rejected

# System/Admin actions
POST /applications/123/close        # Approved/Rejected → Closed

# Side effect</span>: spawning a Loan (after Approved)
<span class="hljs-attribute">POST /loans
{
  "applicationId"</span>: "123",
  "amount": 50000,
  "borrowerId": "456",
  "terms": { ... }
}
</code></pre>
<p>At this point, our API calls are almost entirely outside the CRUD pattern—the only one that resembles a CRUD action is the spawning of a loan, which looks like a “create”. Behind the scenes, we’ll still use <code>INSERT</code>, <code>SELECT</code>, and <code>UPDATE</code> statements in SQL, but at the API level we’re aligning to the actual business workflow. Because of it, we’re able to easily support the following:</p>
<ol>
<li><p><strong>Actions reflect business intent</strong> — each API call maps to a real-world task like submit, approve, or withdraw.</p>
</li>
<li><p><strong>Built-in authorization</strong> — endpoints clearly separate borrower, loan officer, and admin responsibilities.</p>
</li>
<li><p><strong>Auditability and workflow enforcement</strong> — state transitions are explicit and invalid transitions are prevented.</p>
</li>
<li><p><strong>Controlled side effects</strong> — spawning loans, notifications, and downstream processes are handled deliberately.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By moving away from CRUD and modeling domain actions instead, our API aligns with real business workflows, clearly communicates intent, and enforces rules and authorization naturally. State transitions, side effects, and auditing become explicit, reducing errors and security risks. While CRUD still powers the underlying database operations, thinking in terms of actions and workflows ensures that the system behaves the way the business expects.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Fetch API vs. Axios vs. Alova: Which HTTP Client Should You Use in 2025? ]]>
                </title>
                <description>
                    <![CDATA[ Before the days of the Fetch API and Axios, developers used callback-based HTTP requests. They manually managed requests with asynchronous operations and, in the process, wrote deeply nested code. This was known as callback hell. Then, in 2015, a pro... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/fetch-api-vs-axios-vs-alova/</link>
                <guid isPermaLink="false">67ed4e54f03ad9ca955f36d0</guid>
                
                    <category>
                        <![CDATA[ Alova ]]>
                    </category>
                
                    <category>
                        <![CDATA[ XHP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ javascript framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ json ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ blob ]]>
                    </category>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ fetch API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ fetching apis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API basics  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abdullah Salaudeen ]]>
                </dc:creator>
                <pubDate>Wed, 02 Apr 2025 14:48:52 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743605319873/9f7583a0-1b01-4714-9fe6-f39bed3954e8.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Before the days of the Fetch API and Axios, developers used callback-based HTTP requests. They manually managed requests with asynchronous operations and, in the process, wrote deeply nested code. This was known as callback hell.</p>
<p>Then, in 2015, a promise-based API request, the Fetch API, was built into JavaScript ES6 to ease the process. After that, libraries like Axios and Alova also appeared.</p>
<p>But why would anyone consider using a third-party API when the lightweight inbuilt Fetch API is an effective option? Well, Axios and Alova provide more than just fetching simple JSON responses. While Axios automates the parsing of JSON and provides shorthand methods for requests, Alova caches responses which prevents making new requests that are redundant.</p>
<p>So which should you stick to – Fetch API, Axios, or Alova? </p>
<p>In this guide, we’ll examine each of these tools based on their features, performance, and project suitability. Walk with me…</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-fetch-api">The Fetch API</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-key-features-of-the-fetch-api">Key Features of the Fetch API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-limitations-of-the-fetch-api">Limitations of the Fetch API</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-axios">Axios</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-key-features-of-axios">Key Features of Axios</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-limitations-of-axios">Limitations of Axios</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-alova">Alova</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-key-features-of-alova">Key Features of Alova</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-limitations-of-alova">Limitations of Alova</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-feature-by-feature-comparison">Feature-by-Feature Comparison</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-cases-and-best-scenarios">Use Cases and Best Scenarios</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-when-to-use-fetch-api">When to Use Fetch API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-axios">When to Use Axios</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-alova">When to Use Alova</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-community-and-ecosystem">Community and Ecosystem</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-ecosystem-and-integrations">Ecosystem and Integrations</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you start this tutorial, you should have a basic understanding of JavaScript and ES6+ features, such as <a target="_blank" href="https://www.freecodecamp.org/news/javascript-async-await/"><code>async/await</code></a>, <a target="_blank" href="https://www.freecodecamp.org/news/javascript-arrow-functions-in-depth/">arrow functions</a>, and <a target="_blank" href="https://salaudeenabdu.hashnode.dev/destructuring-in-javascript">object destructuring</a>. Being familiar with the <code>fetch()</code> API will also be helpful, as we’ll compare it with Axios and Alova.</p>
<p>You should also have a fundamental knowledge of HTTP methods (GET, POST, PUT, DELETE, PATCH) and handling API responses based on status codes to better understand the API examples.</p>
<p>While this tutorial focuses on JavaScript, some examples use React. So you should be familiar with React and understand the basics of components, state, and hooks (like <code>useState</code> and <code>useEffect</code>). Alova also works with frameworks like Vue and Svelte.</p>
<p>Basic experience with package managers (NPM or Yarn) is useful for installing dependencies like Axios and Alova. And understanding Node.js and browser environments will help, as Alova works in both contexts.</p>
<p>Lastly, familiarity with state management and caching concepts will enhance your understanding of Alova’s features, as it integrates state management and caching directly into API requests.</p>
<h2 id="heading-the-fetch-api"><strong>The Fetch API</strong></h2>
<p>Fetch API is a promise-based API request feature in JavaScript that was released to replace the old callback-based XMLHttpRequest (XHP). Unlike the old tool, Fetch API is compatible with modern website features, including <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">service workers</a> and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS">Cross-Origin Resource Sharing (CORS)</a>. </p>
<p>With this tool, calling API data is as simple as making a fetch() request on the API URL, as shown below:  </p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">"https://fakestoreapi.com/products"</span>)
</code></pre>
<p>The <code>fetch()</code> returns the server’s promise which is fulfilled with a response object. Then, you pass in some optional arguments to configure the response as JSON or text, attach it to a variable, and use the data.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> products;

  fetch(<span class="hljs-string">"https://fakestoreapi.com/products"</span>)

    .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json())

    .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {

      products = data

      <span class="hljs-built_in">console</span>.log(products)

    })

    .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching data:"</span>, error))
</code></pre>
<p>In the code above, the <code>fetch()</code> requests API data from the URL. The response <code>res</code> gets parsed as JSON <code>res.json</code>. Then, the resulting data is attached to the <code>products</code> variable and logged on the console.  </p>
<p>Since Node.js v17.5, the Fetch API has been available natively, eliminating the reliance on external packages like <code>node-fetch</code>, <code>got</code>, or <code>cross-fetch</code> for handling HTTP requests. This native support in both browsers and Node.js removes the need for additional dependencies, reducing the overall bundle size of your application. With this built-in functionality, the Fetch API has become the go-to tool for making asynchronous API calls in JavaScript applications.</p>
<h3 id="heading-key-features-of-the-fetch-api">Key Features of the Fetch API</h3>
<h4 id="heading-promises-based-syntax">Promises-based syntax</h4>
<p>As I mentioned earlier, the Fetch API uses a promise-based syntax that sends a promise from the server and executes it with a response object. While the <code>.then</code> chaining can be optimal for simple requests, using several <code>.then</code>s can lead to callback hell and give you a hard time tracking errors. This is why the <code>async/await</code> alternative is a more optimal solution. Check out the code example below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {

      <span class="hljs-keyword">try</span> {

        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://fakestoreapi.com/products"</span>);

        <span class="hljs-keyword">if</span> (!response.ok) {

          <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP error! Status: <span class="hljs-subst">${response.status}</span>`</span>);

        }

        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();

        products = data

        <span class="hljs-built_in">console</span>.log(products); <span class="hljs-comment">//</span>

      } <span class="hljs-keyword">catch</span> (error) {

        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching data:"</span>, error);

      }

    };

    fetchData();
</code></pre>
<p>As shown above, the fetch makes a get request. Then, the server returns an error status if the response is not ok (returns an error status like <code>error 404</code>). Then, the response gets parsed as JSON and used. </p>
<p>Keep in mind that all methods passed on the response are asynchronous, including the <code>fetch()</code> and the <code>json()</code> parsing.</p>
<h4 id="heading-supports-the-get-post-put-patch-and-delete-methods">Supports the <code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>PATCH</code> and <code>DELETE</code> methods</h4>
<p><code>GET</code>, used to receive responses, is the Fetch API’s default method. So when you’re using it, you don’t have to define it explicitly or attach a body. But for methods that send requests like <code>POST</code>, <code>PUT</code>, <code>PATCH</code> and <code>DELETE</code>, you must specify their method and attach a body. </p>
<p>All these methods send requests to the backend. You can send data to the server with <code>POST</code>,  completely replace an existing resource with new data using <code>PUT</code>, partially update with <code>PATCH</code>, or remove the resource with <code>DELETE</code>.  </p>
<ol>
<li><strong>Here’s how you can define a method:</strong></li>
</ol>
<p>In the code below, I set the POST method to send data to the specified API: </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://example.com/products1"</span>, {

          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>

          <span class="hljs-comment">//...</span>

        });
</code></pre>
<p>Apart from posting data, you can also clear data on the server using <code>DELETE</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://example.com/products1"</span>, {

      <span class="hljs-attr">method</span>: <span class="hljs-string">"DELETE"</span>

      <span class="hljs-comment">//...</span>

    });
</code></pre>
<ol start="2">
<li><strong>Then, define the header:</strong></li>
</ol>
<p>Defining the header lets the server understand the type of content you are sending for proper data handling. As shown here, the header asks the server to store the content as a JSON file and set the authorization token to <code>my-classified-token</code><em>.</em> Keep in mind that the token is the API key that will be used to verify user identity upon use.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://example.com/products1"</span>, {

          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,

          <span class="hljs-attr">header</span>: {

            <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application-json"</span>,

            <span class="hljs-string">"Authorization"</span>: <span class="hljs-string">"Bearer my-classified-token"</span>,

          }

          <span class="hljs-comment">//..</span>

        });
</code></pre>
<p>Here is a full list of parameters that can be passed into the header:</p>
<table><tbody><tr><td><p><strong>Header</strong></p></td><td><p><strong>Purpose</strong></p></td></tr><tr><td><p>"Content-Type": "application/json"</p></td><td><p>Tells the server that the request body is in JSON format.</p></td></tr><tr><td><p>"Authorization": "Bearer token"</p></td><td><p>Provides authentication (API keys, JWT, OAuth tokens).</p></td></tr><tr><td><p>"Accept": "application/json"</p></td><td><p>Specifies that the client expects a JSON response.</p></td></tr><tr><td><p>"Content-Type": "application/x-www-form-urlencoded"</p></td><td><p>Used for sending form data instead of JSON.</p></td></tr><tr><td><p>"Origin": "http://example.com"</p></td><td><p>Indicates where the request is coming from (used in CORS).</p></td></tr></tbody></table>

<ol start="3">
<li><strong>Next, attach the body:</strong></li>
</ol>
<p>After specifying the header, you then attach the body. The body is the data being sent to the backend server. It cannot be used with the GET method which only fetches responses. Besides, the information attached should always be in a valid format that matches the content type specified in the headers. You can add as much value as you require to the body.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://example.com/products1"</span>, {

          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,

          <span class="hljs-attr">header</span>: {

            <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application-json"</span>,

            <span class="hljs-string">"Authorization"</span>: <span class="hljs-string">"Bearer my-classified-token"</span>,

          },

          <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">name</span>: <span class="hljs-string">"Laptop"</span>, <span class="hljs-attr">price</span>: <span class="hljs-number">1200</span> })

        });
</code></pre>
<h4 id="heading-streaming-data">Streaming Data</h4>
<p>It is also worth noting that the Fetch API facilitates large data handling via streaming. It receives copious data in chunks instead of loading the whole data and buffering in the process. So it data displays real-time as they arrive. Here is a simple example of streaming:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {

<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://www.example.com/large-text-file.txt'</span>);

      <span class="hljs-keyword">const</span> reader = response.body.getReader();

      <span class="hljs-keyword">const</span> decoder = <span class="hljs-keyword">new</span> TextDecoder();

      <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {

        <span class="hljs-keyword">const</span> { done, value } = <span class="hljs-keyword">await</span> reader.read();

        <span class="hljs-keyword">if</span> (done) <span class="hljs-keyword">break</span>;

        <span class="hljs-keyword">const</span> chunk = decoder.decode(value, { <span class="hljs-attr">stream</span>: <span class="hljs-literal">true</span> });

        <span class="hljs-built_in">console</span>.log(chunk); <span class="hljs-comment">// Process the chunk (e.g., display it in UI)</span>

      }

      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Stream complete'</span>);

    }

    fetchData();
</code></pre>
<h4 id="heading-fetching-documents-with-the-dom-parser">Fetching Documents with the DOM Parser</h4>
<p>Unlike its predecessor, XHP, which can directly return a document, Fetch API can’t achieve the same results without using the DOM Parser. To use it, you have to set the response type to text, then convert to a document using the DOMParser. Here is an example:</p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">"example.xml"</span>)

  .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.text()) <span class="hljs-comment">// Get raw text</span>

  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {

    <span class="hljs-keyword">const</span> parser = <span class="hljs-keyword">new</span> DOMParser();

    <span class="hljs-keyword">const</span> doc = parser.parseFromString(data, <span class="hljs-string">"text/xml"</span>); <span class="hljs-comment">// Convert text to Document</span>

    <span class="hljs-built_in">console</span>.log(doc); <span class="hljs-comment">// Now it's a Document object</span>

  })

  .catch(<span class="hljs-built_in">console</span>.error);
</code></pre>
<h4 id="heading-request-cancellation-with-abortcontroller">Request Cancellation with AbortController</h4>
<p>Previously, the Fetch API couldn’t abort requests. But it is now possible with <code>AbortController</code> and <code>AbortSignal</code>. But the AbortController API is not native either, which means there is extra bundle and set up required. </p>
<h3 id="heading-limitations-of-the-fetch-api"><strong>Limitations of the Fetch API</strong></h3>
<h4 id="heading-response-flexibility-or-no-automatic-json-parsing">Response Flexibility or No automatic JSON parsing</h4>
<p>Depends on how you see it. Having to specify whether you want your response as JSON <code>res.json()</code> or text <code>res.text()</code> or blob <code>res.blob()</code> lets you set which response type you want from the get go. But it can also be a limitation since most API fetches are in JSON. This means that alternatives like Axios, which sets defaults as <code>res.json()</code>, helps write shorter and cleaner code, and is therefore often preferred by developers. </p>
<h4 id="heading-no-built-in-requestresponse-interceptors">No built-in request/response interceptors</h4>
<p>Unlike Axios, Fetch API does not have built-in methods that intercept and modify requests or responses. This limitation means you have to write boilerplate code to create a custom interceptor.</p>
<p>For instance, via interception, you can attach an Authorization token automatically before sending requests or asking all 401 errors to automatically reload when receiving responses. With the Fetch API, you have to wrap the <code>fetch()</code> in a function to do that, which means more lines of code.</p>
<p>Here is some code built to mimic request/ response interception:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> customFetch = <span class="hljs-keyword">async</span> (url, options = {}) =&gt; {

      <span class="hljs-comment">// Request Interception</span>

      <span class="hljs-keyword">const</span> modifiedOptions = {

          ...options,

          <span class="hljs-attr">headers</span>: {

              <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,

              <span class="hljs-attr">Authorization</span>: Bearer ${<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>)}, <span class="hljs-comment">// Interceptor behavior</span>

              ...options.headers

          }

      };



      <span class="hljs-keyword">try</span> {

          <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url, modifiedOptions);



          <span class="hljs-comment">// Response Interception</span>

          <span class="hljs-keyword">if</span> (!response.ok) {

              <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Intercepted Error:"</span>, response.status);

          }



          <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> response.json();

      } <span class="hljs-keyword">catch</span> (error) {

          <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Fetch error intercepted:"</span>, error);

          <span class="hljs-keyword">throw</span> error;

      }

  };

  <span class="hljs-comment">// Usage (No need to set headers manually)</span>

  customFetch(<span class="hljs-string">'https://api.example.com/data'</span>)

      .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(data))

      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
</code></pre>
<h4 id="heading-error-handling-requires-additional-logic">Error handling requires additional logic</h4>
<p>The Fetch API only rejects network errors, not failed HTTP status codes like 404 or 501. This means that when a fetching request fails, it does not return a  <code>404 Not Found</code> or <code>500 Internal Server Error</code> unless you configure that with additional code. But Axios does.  </p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/invalid-url'</span>)

  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {

    <span class="hljs-keyword">if</span> (!response.ok) { <span class="hljs-comment">// Manually handle non-2xx responses</span>

      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP Error! Status: <span class="hljs-subst">${response.status}</span>`</span>);

    }

    <span class="hljs-keyword">return</span> response.json();

  })

  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(data))

  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error:'</span>, error.message));
</code></pre>
<h2 id="heading-axios"><strong>Axios</strong></h2>
<p>After XHP was replaced with the Fetch API, <a target="_blank" href="https://axios-http.com/docs/intro">Axios</a> emerged in 2016 to address some issues with the new JavaScript-native fetching tool. Built on top of XHP, Axios quickly gained widespread adoption due to combining many Fetch API promise-based features with some methods on the legacy XMLHttpRequest. In no time, it became a popular choice amongst developers.</p>
<p>Axios stands out because it:</p>
<ul>
<li><p>Automates JSON parsing</p>
</li>
<li><p>Has a built-in method to intercept and modify requests and responses </p>
</li>
<li><p>Automates error handling </p>
</li>
<li><p>Automates timeout handling</p>
</li>
<li><p>Can track upload and download progress</p>
</li>
</ul>
<p>And many more features.</p>
<p>In particular, Axios is widely loved because it reduces boilerplate code. Since most API requests encode data with <code>JSON</code>, Axios sets its default parsing to accordingly, which means you don’t have to define <code>JSON</code> again. And why worry anyway, since developers use far fewer <code>res.text()</code> and <code>res.blob()</code> API responses in comparison.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'https://api.example.com/data'</span>);

    <span class="hljs-built_in">console</span>.log(response.data); <span class="hljs-comment">// JSON is already parsed</span>

  };
</code></pre>
<p>Now, compare that to a like-for-like fetching with Fetch API:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/data'</span>);

    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json(); <span class="hljs-comment">// Extra step</span>

    <span class="hljs-built_in">console</span>.log(data);

  };
</code></pre>
<p>Yeah, there’s an extra line, right? That could mean several lines of code for larger codebases. </p>
<h3 id="heading-key-features-of-axios"><strong>Key Features of Axios</strong></h3>
<h4 id="heading-automatic-json-parsing">Automatic JSON Parsing</h4>
<p>As explained above, you don’t have to call <code>res.json()</code> again while using Axios, since the method is automatically set. But what happens, in rare cases, when you want to fetch a blob or text using Axios? Then, you have to set the response type accordingly. Here’s how you can do that:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'https://api.example.com/data'</span>, {
      <span class="hljs-attr">responseType</span>: <span class="hljs-string">'text'</span>, <span class="hljs-comment">// Treats response as plain text</span>
    });

    <span class="hljs-built_in">console</span>.log(response.data); <span class="hljs-comment">// Plain text string</span>
  };
</code></pre>
<h4 id="heading-built-in-interceptors-to-modify-requests-and-responses">Built-in Interceptors to Modify Requests and Responses</h4>
<p>Axios comes with its built-in interceptors to intercept and modify API responses or requests. Interceptors can help set authorization tokens for requests or modify global responses and errors before they render. Use the <code>.interceptors.request.use()</code> for requests and <code>.interceptors.response.use()</code> for responses. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

  <span class="hljs-keyword">const</span> apiClient = axios.create({

      <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://api.example.com"</span>,

      <span class="hljs-attr">headers</span>: {

          <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>

      }

  });



  <span class="hljs-comment">// Request Interceptor: Attach Authorization headers</span>

  apiClient.interceptors.request.use(<span class="hljs-function"><span class="hljs-params">config</span> =&gt;</span> {

      config.headers.Authorization = Bearer ${<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>)};

      <span class="hljs-keyword">return</span> config;

  }, <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">Promise</span>.reject(error));

  <span class="hljs-comment">// Usage: Axios automatically includes the Authorization header</span>

  apiClient.get(<span class="hljs-string">"/data"</span>)

      .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))

      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
</code></pre>
<p>To achieve that with Fetch API, you will have to write an interceptor wrapper on your API, which needs far more boilerplate code.</p>
<h4 id="heading-request-cancellation-with-canceltoken">Request cancellation with CancelToken</h4>
<p>Although now deprecated, Axios used to have its native request cancellation method known as <code>CancelToken</code>. But now, the <code>AbortController</code> API is regarded as a globally-recognized and reliable method for request abortion.</p>
<h4 id="heading-error-handling">Error Handling</h4>
<p>Axios handles errors better by automatically rejecting all non-2xx status codes like <code>Error 404</code> and <code>501</code>. You do not need to check any <code>response.ok</code> message:</p>
<pre><code class="lang-javascript">axios.get(<span class="hljs-string">'https://jsonplaceholder.typicode.com/invalid-url'</span>)

  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))

  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error Status:'</span>, error.response?.status); <span class="hljs-comment">// Axios auto-rejects non-2xx responses</span>

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error Message:'</span>, error.message);

  });
</code></pre>
<h4 id="heading-built-in-progress-tracking">Built-in Progress Tracking</h4>
<p>Axios incorporates XHP methods like <code>onDownloadProgress</code> and <code>onUploadProgress</code>. This inbuilt feature facilitates tracking download and uploads progress. Whereas with the Fetch API, you’d need <code>ReadableStream</code> to achieve similar results. </p>
<p>Here is an example showing how you can use <code>onUploadProgress</code>: </p>
<pre><code class="lang-javascript">axios.post(url, data, {

    <span class="hljs-attr">onUploadProgress</span>: <span class="hljs-function"><span class="hljs-params">progressEvent</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(progressEvent.loaded)

  });
</code></pre>
<h4 id="heading-supports-other-methods-too">Supports Other Methods, too</h4>
<p>Just like the Fetch API, Axios’ default Method is <code>GET</code>. But you can use the <code>POST</code>, <code>PUT</code>, <code>PATCH</code> or <code>DELETE</code> methods using <code>axios.request()</code>. Here’s how:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

  axios.request({

      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,

      <span class="hljs-attr">url</span>: <span class="hljs-string">"https://api.example.com/users"</span>,

      <span class="hljs-attr">body</span>: { <span class="hljs-attr">name</span>: <span class="hljs-string">"Abdullah"</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span> }, <span class="hljs-comment">// Request body</span>

      <span class="hljs-attr">headers</span>: {

          <span class="hljs-string">"Authorization"</span>: Bearer ${<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>)},

          <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>

      }

  })

  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))

  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Axios Request Error:"</span>, error));
</code></pre>
<p>Axios also provides a shorthand with methods like <code>axios.get</code>, <code>axios.post</code>, <code>axios.put</code>, <code>axios.patch</code>, and <code>axios.delete</code>, as shown below:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// POST Request</span>

axios.post(<span class="hljs-string">"https://api.example.com/users"</span>,

  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Abdullah"</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span> }, <span class="hljs-comment">// Request body</span>

  { <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> } }

)

.then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))

.catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Axios POST Error:"</span>, error));

<span class="hljs-comment">// PUT Request</span>

axios.put(<span class="hljs-string">"https://api.example.com/users/123"</span>,

  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Updated Name"</span> }, <span class="hljs-comment">// Updated data</span>

  { <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Authorization"</span>: Bearer ${<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>)} } }

)

.then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))

.catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Axios PUT Error:"</span>, error));

<span class="hljs-comment">// DELETE Request</span>

axios.delete(<span class="hljs-string">"https://api.example.com/users/123"</span>, {

  <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Authorization"</span>: Bearer ${<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>)} }

})

.then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"User deleted successfully"</span>))

.catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Axios DELETE Error:"</span>, error));
</code></pre>
<h3 id="heading-limitations-of-axios"><strong>Limitations of Axios</strong></h3>
<h4 id="heading-slightly-larger-bundle-size">Slightly larger bundle size</h4>
<p>Axios <a target="_blank" href="https://bundlephobia.com/package/axios@1.8.4">adds 35 kb</a> of extra bundle, while FetchAPI adds 0. While Axios clearly offers more features than Fetch in every other metric, you have to make do with the larger bundle size. And in an age where lightweight and fast applications are often preferred, you might not want that load.</p>
<h4 id="heading-dependency-on-third-party-maintenance">Dependency on third-party maintenance</h4>
<p>Depending on a third-party option for something as crucial as API might not be desirable. So a native tool like the Fetch API, built within JavaScript, offers more reliability.</p>
<h2 id="heading-alova"><strong>Alova</strong></h2>
<p><a target="_blank" href="https://github.com/alovajs/alova">Alova</a> is a request management library that combines simple API fetching with other functionalities like state management, hooks, and caching, amongst many others.</p>
<p>While we use <code>react-query</code> and <code>SWR</code> to process Axios-fetched data, Alova saves you those extra installations and coding by providing these methods natively. The all-in-one alternative not only fetches responses and sends requests, but also merges requests, caches responses, and optimizes them for UI frameworks. </p>
<p>Built in 2022, Alova’s adoption is still early but nonetheless seems promising. It is supported on browsers, Node.js, and most frameworks, including Vue, React, Svelte, and vanilla JavaScript. But it has limited usage for Angular.js.</p>
<p><a target="_blank" href="https://bundlephobia.com/package/alova@2.6.1">At just 10kb</a>, it is about 3 times smaller than Axios, making it a more lightweight alternative for building fast applications. </p>
<p>You can also use Alova to either replace react-query to facilitate Axios or be the one-stop-shop for everything API integration-related. </p>
<p>Here is a simple Alova fetch:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> alovaInstance.Get(<span class="hljs-string">'https://jsonplaceholder.typicode.com'</span>).send();

<span class="hljs-built_in">console</span>.log(response); <span class="hljs-comment">// Response data</span>
</code></pre>
<p>When you are fetching Alova on React components, you can use the <code>createAlova()</code> to set parameters and <code>useRequest()</code> to manage state. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">import</span> { createAlova, useRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">"alova"</span>;

<span class="hljs-keyword">import</span> GlobalFetch <span class="hljs-keyword">from</span> <span class="hljs-string">"alova/GlobalFetch"</span>;

<span class="hljs-comment">// Initialize Alova</span>

<span class="hljs-keyword">const</span> alovaInstance = createAlova({

  <span class="hljs-attr">statesHook</span>: React,

  <span class="hljs-attr">requestAdapter</span>: GlobalFetch(),

});

<span class="hljs-comment">// GET request with useRequest</span>

<span class="hljs-keyword">const</span> Profile = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> { data, loading, error } = useRequest(<span class="hljs-function">() =&gt;</span> alovaInstance.Get(<span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>));

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error fetching profile<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Username: {data.username}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;

};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Profile;
</code></pre>
<h3 id="heading-key-features-of-alova"><strong>Key Features of Alova</strong></h3>
<h4 id="heading-one-stop-shop">One-Stop Shop</h4>
<p>For some functionalities that come built into Alova, Fetch API or Axios might need additional libraries like <code>react-query</code> or <code>SWR</code> to fulfill. </p>
<h4 id="heading-request-sharing-prevents-redundant-requests">Request Sharing Prevents Redundant Requests</h4>
<p>Alova fuses identical requests. Let’s say several components ask for the same data from the API. The Fetch API and Axios send multiple identical requests to the server which creates traffic. But Alova merges them, sends a single request, and shares its response across all components, which reduces network traffic.</p>
<h4 id="heading-state-management">State Management</h4>
<p>With tools like Fetch API and Axios, you have to manage data, loading, and error states manually. Alova lets you do that on the go within a single line of code. Here is how it looks:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//...</span>

<span class="hljs-keyword">const</span> { data, loading, error } = useRequest(alova.Get(<span class="hljs-string">"/posts/1"</span>));

<span class="hljs-comment">//...</span>
</code></pre>
<h4 id="heading-advanced-request-management">Advanced Request Management</h4>
<p>Alova offers several request management functionalities with each tailored to specific use cases. With its request management, you can request preload for data to be used later, cache data to prevent reload, manage form submission, handle pagination, and automate refetching when needed. Check out their docs to <a target="_blank" href="https://alova.js.org/tutorial/client/strategy/">read more</a>. </p>
<h4 id="heading-multi-level-caching">Multi-Level Caching</h4>
<p>You can also use Alova to cache data, especially when the response isn’t constantly changing and does not need refetching. Unlike <code>react-query</code> that simply stores caches in RAM, Alova offers a more flexible framework. </p>
<p>Its three-pronged caching modes include the memory mode, cache occupying mode, and recovery mode. While memory mode stores data in the RAM, recovery mode persistently stores it in a Local Storage and is made available for longer periods and even offline. Meanwhile, the occupying mode prevents duplicate or redundant requests coming in quick succession. </p>
<p>Independent on any component, cached data can be accessed anywhere in the app if the request URL and parameters match. These features lower traffic going to servers, reduce buffering, and help facilitating a swifter and better user experience.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//...</span>

<span class="hljs-comment">// Initialize Alova instance</span>

<span class="hljs-keyword">const</span> alovaInstance = createAlova({

  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>,

  <span class="hljs-attr">statesHook</span>: React,

  <span class="hljs-attr">requestAdapter</span>: GlobalFetch(),

});

<span class="hljs-comment">// Define GET request</span>

<span class="hljs-keyword">const</span> getPosts = alovaInstance.Get(<span class="hljs-string">"/posts"</span>, {

  <span class="hljs-attr">cache</span>: {

    <span class="hljs-attr">mode</span>: <span class="hljs-string">"memory"</span>, <span class="hljs-comment">// Caches in memory</span>

    <span class="hljs-attr">expires</span>: <span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">5</span>, <span class="hljs-comment">// Expires in 5 minutes</span>

  },

});

<span class="hljs-keyword">const</span> PostList = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> { data, loading, error } = useRequest(getPosts);

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error fetching data<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-comment">//...</span>

};
</code></pre>
<p>In the example above, Alova caches the response using the memory mode <code>cache: {mode: "memory"}</code> and sets the cache expiration to 5 minutes <code>expires: 1000 * 60 * 5</code><em>.</em> You can change <code>“memory”</code> to <code>“recovery”</code> if you want a longer storage duration. </p>
<h4 id="heading-usage-flexibility">Usage Flexibility</h4>
<p>You can use Alova with either Axios or the Fetch API. Here is an example where I fetched data using Axios and complemented it with Alova state management.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//...</span>

<span class="hljs-comment">// Initialize Alova</span>

<span class="hljs-keyword">const</span> alovaInstance = createAlova({

  <span class="hljs-attr">statesHook</span>: React,

  <span class="hljs-attr">requestAdapter</span>: GlobalFetch(),

});

<span class="hljs-comment">// Manage state with Alova</span>

<span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: posts, setData } = useSnapshot([]);

<span class="hljs-keyword">const</span> fetchPosts = <span class="hljs-keyword">async</span> () =&gt; {

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span>);

  setData(response.data); <span class="hljs-comment">// Store data in Alova state</span>

};

<span class="hljs-comment">//...</span>
</code></pre>
<h4 id="heading-supports-other-methods">Supports Other Methods</h4>
<p>Alova also makes <code>GET</code> its default option while supporting other methods like <code>POST</code>, <code>PATCH</code>, <code>PUT</code> and <code>DELETE</code>. Here is how to use <code>POST</code> in Alova, for example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">import</span> { createAlova, useRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">"alova"</span>;

<span class="hljs-keyword">import</span> GlobalFetch <span class="hljs-keyword">from</span> <span class="hljs-string">"alova/GlobalFetch"</span>;

<span class="hljs-keyword">const</span> alovaInstance = createAlova({

  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>,

  <span class="hljs-attr">statesHook</span>: React,

  <span class="hljs-attr">requestAdapter</span>: GlobalFetch(),

});

<span class="hljs-keyword">const</span> PostForm = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> { <span class="hljs-attr">send</span>: createPost } = useRequest(alovaInstance.Post(<span class="hljs-string">"/posts"</span>, { title }), { <span class="hljs-attr">immediate</span>: <span class="hljs-literal">false</span> });

  createPost().then(<span class="hljs-built_in">console</span>.log)

};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PostForm;
</code></pre>
<p>Of course, it has shorthand methods too:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">import</span> { createAlova, useRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">"alova"</span>;

<span class="hljs-keyword">import</span> GlobalFetch <span class="hljs-keyword">from</span> <span class="hljs-string">"alova/GlobalFetch"</span>;

<span class="hljs-keyword">const</span> alova = createAlova({

  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>,

  <span class="hljs-attr">statesHook</span>: React,

  <span class="hljs-attr">requestAdapter</span>: GlobalFetch(),

});

<span class="hljs-keyword">const</span> { <span class="hljs-attr">send</span>: createPost } = useRequest(alova.Post(<span class="hljs-string">"/posts"</span>, { <span class="hljs-attr">title</span>: <span class="hljs-string">"New Post"</span> }), { <span class="hljs-attr">immediate</span>: <span class="hljs-literal">false</span> });

<span class="hljs-keyword">const</span> { <span class="hljs-attr">send</span>: updatePost } = useRequest(alova.Put(<span class="hljs-string">"/posts/1"</span>, { <span class="hljs-attr">title</span>: <span class="hljs-string">"Updated Post"</span> }), { <span class="hljs-attr">immediate</span>: <span class="hljs-literal">false</span> });

<span class="hljs-keyword">const</span> { <span class="hljs-attr">send</span>: patchPost } = useRequest(alova.Patch(<span class="hljs-string">"/posts/1"</span>, { <span class="hljs-attr">title</span>: <span class="hljs-string">"Patched Post"</span> }), { <span class="hljs-attr">immediate</span>: <span class="hljs-literal">false</span> });

createPost().then(<span class="hljs-built_in">console</span>.log);

updatePost().then(<span class="hljs-built_in">console</span>.log);

patchPost().then(<span class="hljs-built_in">console</span>.log);
</code></pre>
<h4 id="heading-bundle-size">Bundle Size</h4>
<p>Alova is three times smaller than Axios, but that does not even tell the full story. With Axios and the Fetch API, you need different libraries to handle caching, request deduplication, and retries. But Alova has everything in-built. So using Axios and Fetch API in real code production will always require more bundles than Axios. And overall, Alova facilitates lighter-weight applications compared to Axios and sometimes the Fetch API as well. </p>
<h3 id="heading-limitations-of-alova"><strong>Limitations of Alova</strong></h3>
<h4 id="heading-adoption-is-still-low">Adoption Is Still Low</h4>
<p>While writing this article, I had a hard time getting enough resources on Alova. And that is because it only debuted in July 2022 which means adoption is still early. So, troubleshooting Alova might be problematic since there are fewer Alova-themed API communities, as well as fewer StackOverflow answers, Youtube Tutorials, or GitHub contributions. </p>
<h4 id="heading-potential-stability-amp-long-term-maintenance-risks">Potential Stability &amp; Long-Term Maintenance Risks</h4>
<p>Newer libraries have a higher risk of abandonment. Axios has been around for years, while Alova is still growing. Besides, it has fewer production use cases and battle-tested applications compared to Axios and Fetch.</p>
<h4 id="heading-learning-curve">Learning Curve</h4>
<p>Alova’s learning curve can take some getting used to because it handles API requests differently from tools like Axios or the Fetch API.</p>
<p>Instead of making requests directly, you work with request instances and manage state within Alova’s system. This requires learning new ways to structure API calls and use features like caching and request merging. While it may feel unfamiliar at first, it can help reduce redundant API calls and improve performance once you understand it.</p>
<h4 id="heading-fewer-third-party-integrations">Fewer Third Party Integrations</h4>
<p>Alova has fewer third-party libraries built specifically for it, requiring more manual work for compatibility with existing tools. </p>
<h2 id="heading-feature-by-feature-comparison"><strong>Feature-by-Feature Comparison</strong></h2>
<table><tbody><tr><td><p><strong>Feature</strong></p></td><td><p><strong>Fetch API</strong></p></td><td><p><strong>Axios</strong></p></td><td><p><strong>Alova</strong></p></td></tr><tr><td><p><strong>Ease of Use</strong></p></td><td><p>Medium (requires manual handling)</p></td><td><p>High (user-friendly syntax)</p></td><td><p>Medium (requires new patterns)</p></td></tr><tr><td><p><strong>Performance</strong></p></td><td><p>High (lightweight, native)</p></td><td><p>Medium (slightly larger size)</p></td><td><p>High (optimized for caching &amp; batch requests)</p></td></tr><tr><td><p><strong>JSON Handling</strong></p></td><td><p>Manual parsing (.json())</p></td><td><p>Automatic</p></td><td><p>Automatic</p></td></tr><tr><td><p><strong>Request Cancellation</strong></p></td><td><p>AbortController (manual)</p></td><td><p>Built-in with CancelToken</p></td><td><p>Built-in</p></td></tr><tr><td><p><strong>Interceptors</strong></p></td><td><p>No</p></td><td><p>Yes</p></td><td><p>Yes</p></td></tr><tr><td><p><strong>Timeout Handling</strong></p></td><td><p>No (manual with AbortController)</p></td><td><p>Yes (built-in)</p></td><td><p>Yes (built-in)</p></td></tr><tr><td><p><strong>Data Caching</strong></p></td><td><p>No</p></td><td><p>No (requires third-party caching)</p></td><td><p>Yes (built-in)</p></td></tr><tr><td><p><strong>Retry Mechanism</strong></p></td><td><p>No</p></td><td><p>Yes</p></td><td><p>Yes</p></td></tr><tr><td><p><strong>Error Handling</strong></p></td><td><p>Requires manual handling</p></td><td><p>Automatic rejection for non-2xx status codes</p></td><td><p>Built-in error recovery</p></td></tr><tr><td><p><strong>Browser Support</strong></p></td><td><p>All modern browsers</p></td><td><p>All modern browsers</p></td><td><p>All modern browsers</p></td></tr><tr><td><p><strong>Node.js Support</strong></p></td><td><p>Yes</p></td><td><p>Yes</p></td><td><p>Limited</p></td></tr></tbody></table>

<h2 id="heading-use-cases-and-best-scenarios"><strong>Use Cases and Best Scenarios</strong></h2>
<p>Choosing the right HTTP client for your project depends on several factors, including project complexity, dependencies, and performance considerations. Let’s explore when it’s best to use the Fetch API, Axios, or Alova.</p>
<h3 id="heading-when-to-use-fetch-api">When to Use Fetch API</h3>
<ol>
<li><h4 id="heading-suitable-for-lightweight-projects-and-simple-requests">Suitable for Lightweight Projects and Simple Requests</h4>
</li>
</ol>
<p>The Fetch API is built into modern browsers and is ideal for handling basic HTTP requests without adding dependencies. If your project requires only simple GET, POST, or DELETE requests with minimal configurations, Fetch API is a great choice.</p>
<ol start="2">
<li><h4 id="heading-when-working-in-environments-where-third-party-libraries-are-restricted">When Working in Environments Where Third-Party Libraries Are Restricted</h4>
</li>
</ol>
<p>Certain enterprise or security-sensitive applications may restrict the use of external libraries. Since the Fetch API is built into the browser, it remains a viable option when third-party packages like Axios or Alova are not allowed.</p>
<ol start="3">
<li><h4 id="heading-when-minimal-dependencies-are-preferred">When Minimal Dependencies Are Preferred</h4>
</li>
</ol>
<p>Since Fetch API is native to JavaScript, it does not require installing extra libraries, making it perfect for projects that need to keep dependencies low. This can be particularly beneficial for small lightweight apps or static websites.</p>
<h3 id="heading-when-to-use-axios">When to Use Axios</h3>
<ol>
<li><h4 id="heading-ideal-for-backend-heavy-applications-or-complex-apis">Ideal for Backend-Heavy Applications or Complex APIs</h4>
</li>
</ol>
<p>For projects that require multiple API calls, error handling, and efficient request management, Axios is a solid choice. It allows concurrent requests, request cancellation, and improved control over HTTP headers.</p>
<ol start="2">
<li><h4 id="heading-when-automatic-json-handling-interceptors-and-robust-error-handling-are-needed">When Automatic JSON Handling, Interceptors, and Robust Error Handling Are Needed</h4>
</li>
</ol>
<p>Axios simplifies working with JSON data by automatically parsing responses. It also provides built-in interceptors for request and response transformations, as well as superior error handling compared to Fetch API.</p>
<ol start="3">
<li><h4 id="heading-useful-when-working-with-nodejs-in-full-stack-applications">Useful When Working with Node.js in Full-Stack Applications</h4>
</li>
</ol>
<p>Axios works both in the browser and in Node.js, making it an excellent choice for full-stack applications where a unified API client is needed across the frontend and backend.</p>
<h3 id="heading-when-to-use-alova">When to Use Alova</h3>
<ol>
<li><h4 id="heading-when-working-with-frontend-heavy-applications-react-vue-svelte">When Working with Frontend-Heavy Applications (React, Vue, Svelte)</h4>
</li>
</ol>
<p>Alova integrates well with frontend frameworks and state management tools, making it a great choice for single-page applications (SPAs) that depend on smooth data fetching, pagination, and updates.</p>
<ol start="2">
<li><h4 id="heading-best-for-projects-requiring-optimized-caching-and-data-synchronization">Best for Projects Requiring Optimized Caching and Data Synchronization</h4>
</li>
</ol>
<p>Alova is designed for performance optimization and better caching strategies. It is suitable for applications that rely on real-time data synchronization and need to minimize redundant network requests.</p>
<ol start="3">
<li><h4 id="heading-when-performance-optimization-and-reduced-network-load-are-priorities">When Performance Optimization and Reduced Network Load Are Priorities</h4>
</li>
</ol>
<p>With its intelligent caching mechanisms, Alova can significantly reduce API call frequency, thereby improving the overall performance of the application. It is especially useful in scenarios where network efficiency is crucial, such as mobile applications or progressive web apps (PWAs).</p>
<h2 id="heading-community-and-ecosystem"><strong>Community and Ecosystem</strong></h2>
<p>The community and ecosystem surrounding an HTTP client can impact ease of use, available learning resources, and integration with other tools. Let's explore how the Fetch API, Axios, and Alova are perceived in 2025.</p>
<h3 id="heading-ecosystem-and-integrations"><strong>Ecosystem and Integrations</strong></h3>
<p>While Fetch API is widely supported, developers often supplement it with additional libraries for improved caching, timeouts, and request queuing. This can lead to increased development effort compared to using an out-of-the-box solution like Axios or Alova.</p>
<p>Meanwhile, Axios benefits from a well-established ecosystem with a variety of plugins and extensions, making it easy to integrate with different backend architectures, authentication systems, and request monitoring tools.</p>
<p>Alova is designed to work seamlessly with modern state management libraries such as React Query and Vue Query. These integrations make it an attractive choice for developers focused on optimizing frontend data fetching strategies.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Choosing between the Fetch API, Axios, and Alova depends on your project’s needs and priorities. The Fetch API is best for lightweight applications that require minimal dependencies, while Axios is a robust choice for full-stack applications and backend-heavy environments. Alova, on the other hand, is an excellent option for optimizing data fetching and caching in frontend-focused applications.</p>
<p>As developers explore new ways to enhance performance and reduce network load, Alova's adoption is expected to grow, particularly in SPAs and PWAs. But Axios remains a reliable and widely adopted solution, while the Fetch API continues to be the fundamental building block for HTTP requests in JavaScript.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Zod for React API Validation ]]>
                </title>
                <description>
                    <![CDATA[ In React applications, handling API (Application Programming Interface) responses can be challenging. You might encounter data that’s missing crucial fields, that’s formatted unexpectedly, or that simply doesn’t match what you anticipated. This incon... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-zod-for-react-api-validation/</link>
                <guid isPermaLink="false">67c1f994107ebba152ad9e79</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ zod ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ frontend ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Emore Ogheneyoma Lawrence ]]>
                </dc:creator>
                <pubDate>Fri, 28 Feb 2025 17:59:48 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740756200896/a57c4e95-b13e-412a-828e-09e97f22a6c4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In React applications, handling API (Application Programming Interface) responses can be challenging. You might encounter data that’s missing crucial fields, that’s formatted unexpectedly, or that simply doesn’t match what you anticipated.</p>
<p>This inconsistency can lead to errors in your code and make it difficult to work with the data effectively. Imagine wrestling with unpredictable API responses as your application grows – it can quickly become a development nightmare!</p>
<p>This is where Zod comes in, offering a solution to effectively manage API data validation within React.</p>
<h3 id="heading-by-the-end-of-this-tutorial-youll-learn-how-to">By the end of this tutorial, you’ll learn how to:</h3>
<ol>
<li><p>Set up and use Zod for API response validation in React.</p>
</li>
<li><p>Define schemas to validate and transform incoming data.</p>
</li>
<li><p>integrate Zod into API calls to improve data handling and prevent UI crashes.</p>
</li>
</ol>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-zod-and-why-use-it-for-react-api-calls">What is Zod, and Why Use it for React API Calls?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-generate-a-new-typescript-react-project">How to Generate a New TypeScript React Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-core-zod-concepts-basic-usage-types-and-validation">Core Zod Concepts: Basic Usage, Types, and Validation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-zod-schemas-for-api-responses">How to Build Zod Schemas for API Responses</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-integrate-zod-with-react-api-calls">How to Integrate Zod with React API Calls</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-render-the-user-interface-ui-and-handle-errors-in-react">How to Render the User Interface (UI) and Handle Errors in React</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-zod-and-why-use-it-for-react-api-calls">What is Zod, and Why Use it for React API Calls?</h2>
<p>Zod is a powerful TypeScript-first library that simplifies data validation. It lets you define clear rules (schemas) for your expected data format.</p>
<p>Zod can then validate incoming data (often from API responses) to ensure it conforms to these rules. This validation process guarantees that the data adheres to your defined format, enhancing the reliability and integrity of your application.</p>
<p>Here's why Zod shines for React API validation:</p>
<ul>
<li><p>Clear schemas: Zod helps you define concise blueprints for API responses, enhancing readability and maintainability.</p>
</li>
<li><p>Data validation: It offers powerful validation methods for various data types, enforcing rules like required fields and specific formats.</p>
</li>
<li><p>Early error detection: It helps you detect data inconsistencies during API calls, preventing unexpected errors later in the application.</p>
</li>
<li><p>Improved developer experience: It promotes type-safe coding, streamlining development time by eliminating manual data type checks.</p>
</li>
<li><p>Single source of truth: And finally, Zod serves as a central point for data model definitions, ensuring consistency across the React application and reducing errors.</p>
</li>
</ul>
<p>Using Zod, you can transform unpredictable API responses into clean, structured data, setting the stage for a smoother and more efficient development experience in your React applications.</p>
<h2 id="heading-how-to-generate-a-new-typescript-react-project">How to Generate a New TypeScript React Project</h2>
<p>Creating a new React project with TypeScript is straightforward. Here's how to get started. Execute the following command in your terminal:</p>
<pre><code class="lang-bash">npm create vite@latest my-react-app -- --template react-ts
</code></pre>
<p>Once the project is generated, navigate to the projects directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-react-app
npm install
npm run dev
</code></pre>
<p>That’s it! Your React Project with TypeScript is now up and ready to use. Run the command below to install the Zod package:</p>
<pre><code class="lang-bash">npm install zod
</code></pre>
<h2 id="heading-core-zod-concepts-basic-usage-types-and-validation">Core Zod Concepts: Basic Usage, Types, and Validation</h2>
<p>Zod helps you define clear expectations for your API responses using <strong>schemas</strong>. These schemas act like blueprints, specifying the types of data you expect to receive.</p>
<h3 id="heading-how-to-build-schemas">How to Build Schemas</h3>
<p>Zod provides builder functions like <code>z.string()</code>, <code>z.number()</code>, and <code>z.object()</code> to create schemas. These functions define the data type you want for a specific field in your response.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { z } <span class="hljs-keyword">from</span> <span class="hljs-string">'zod'</span>;
<span class="hljs-comment">// Define basic data types</span>
<span class="hljs-keyword">const</span> userName = z.string().min(<span class="hljs-number">5</span>).max(<span class="hljs-number">10</span>); <span class="hljs-comment">// String with min 5 and max 10 characters</span>
<span class="hljs-keyword">const</span> userAge = z.number().positive().int();  <span class="hljs-comment">// Positive integer</span>
<span class="hljs-keyword">const</span> userEmail = z.string().email();        <span class="hljs-comment">// Ensures a valid email format</span>

<span class="hljs-built_in">console</span>.log(userName.parse(<span class="hljs-string">'John Doe'</span>));       <span class="hljs-comment">// Output: John Doe (valid)</span>
<span class="hljs-built_in">console</span>.log(userAge.parse(<span class="hljs-number">30</span>));              <span class="hljs-comment">// Output: 30 (valid)</span>
<span class="hljs-built_in">console</span>.log(userEmail.parse(<span class="hljs-string">"johnDoe@gmail.com"</span>)); <span class="hljs-comment">// Output: johnDoe@gmail.com (valid)</span>
</code></pre>
<p>The code above defines three basic data types:</p>
<ul>
<li><p><code>userName</code>: Represents a string with a minimum length of 5 characters and a maximum length of 10 characters.</p>
</li>
<li><p><code>userAge</code>: Represents a positive integer.</p>
</li>
<li><p><code>userEmail</code>: Ensures a valid email format.</p>
</li>
</ul>
<p>Here’s the result of the code above:  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738857987322/55a5943c-6633-4432-a441-c3dfa9400d93.png" alt="Image of the resulting code above" class="image--center mx-auto" width="337" height="85" loading="lazy"></p>
<h3 id="heading-how-to-add-validation-rules">How to Add Validation Rules</h3>
<p>Zod allows you to chain methods like <strong>min</strong>, <strong>max</strong>, <strong>positive</strong>, <strong>int</strong>, and <strong>email</strong> to enforce specific rules on these data types. Here’s an example of an invalid string exceeding the maximum length:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">console</span>.log(userName.parse(<span class="hljs-string">"Hello there, My Name is John Doe"</span>)); <span class="hljs-comment">// Throws ZodError</span>
</code></pre>
<p>The code throws a <code>ZodError</code> due to exceeding the maximum length of 10 strings, disrupting our application flow and eventually causing our application to break.  </p>
<p>Here’s the image of the resulting code error:  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738859384410/27c2a5f3-2410-4709-ac27-8bf24f6c3fd8.png" alt="Image of the resulting code above" class="image--center mx-auto" width="325" height="225" loading="lazy"></p>
<h3 id="heading-validating-and-parsing">Validating and Parsing</h3>
<p>Zod offers two ways to check data against your schema:</p>
<ul>
<li><p><code>schema.parse(data)</code><strong>:</strong> This method attempts to parse the data according to your schema. But if there's a validation error, it throws a <code>ZodError</code>. This can disrupt your application's flow, as illustrated in the previous example.</p>
</li>
<li><p><code>schema.safeParse(data)</code>: This is the recommended approach. it parses the data and returns a <code>ZodResult object</code>. This object contains some key properties:</p>
<ul>
<li><p><code>success</code>: A boolean indicating whether the parsing was successful.</p>
</li>
<li><p><code>data</code>: The parsed data itself (if the success property is true)</p>
</li>
<li><p><code>error</code>: An error message if validation fails (if success property is false)</p>
</li>
</ul>
</li>
</ul>
<p>Here are two examples showcasing the usage of <code>safeParse</code> with both valid and invalid data so you can see the resulting outcomes.  </p>
<p>First, lets see an example using <code>safeParse</code> with valid data:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> userSchema = z.object({
  name: userName,
  age: userAge,
  email: userEmail,
});

<span class="hljs-keyword">const</span> userData = {
  name: <span class="hljs-string">"John Doe"</span>,
  age: <span class="hljs-number">24</span>,
  email: <span class="hljs-string">"johndoe@gmail.com"</span>
};

<span class="hljs-keyword">const</span> result = userSchema.safeParse(userData);

<span class="hljs-built_in">console</span>.log(result); <span class="hljs-comment">// ZodObject containing data and success status</span>
</code></pre>
<p>This code defines a schema for user data using Zod, including properties for name, age, and email. It then attempts to parse a sample <code>userData</code> object using this schema via <code>safeParse()</code>. If successful, it prints the parsed data – otherwise, it logs an error message indicating the use of invalid data.  </p>
<p>Here’s the image of the resulting code above:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738861119776/7f9cf3ec-fc83-452c-9477-1c7d6422efe3.png" alt="7f9cf3ec-fc83-452c-9477-1c7d6422efe3" class="image--center mx-auto" width="356" height="140" loading="lazy"></p>
<p>Let’s now see how <code>safeParse()</code> handles invalid data using the same example as above. We’ll pass invalid data to the <code>userSchema.safeParse()</code> function to observe its behaviour.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> userSchema = z.object({
  name: userName,
  age: userAge,
  email: userEmail,
});

<span class="hljs-keyword">const</span> userData = {
  name: <span class="hljs-string">"John Doe"</span>,
  age: <span class="hljs-number">24</span>,
  email: <span class="hljs-string">"johndoe.com"</span> <span class="hljs-comment">// invalid email</span>
};

<span class="hljs-keyword">const</span> result = userSchema.safeParse(userData);

<span class="hljs-built_in">console</span>.log(result); <span class="hljs-comment">// ZodObject containing error and success status</span>
</code></pre>
<p>In this code example, we defined the <code>userSchema</code>. Next, we attempted to parse the <code>userData</code> object. But the parsing failed because the email property was not correctly formatted. Here’s a visual representation of the resulting output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740502631913/25dead7a-ab09-4d1d-9dcc-fada38e7d4d6.png" alt="25dead7a-ab09-4d1d-9dcc-fada38e7d4d6" class="image--center mx-auto" width="367" height="217" loading="lazy"></p>
<p>Unlike using <code>parse</code>, which completely halts your application upon encountering validation errors and throws a <code>ZodError</code>, utilizing <code>safeParse</code> allows you to gracefully handle these errors, ensuring uninterrupted operation.</p>
<h2 id="heading-how-to-build-zod-schemas-for-api-responses">How to Build Zod Schemas for API Responses</h2>
<p>Building on our understanding of Zod’s core concepts, let’s create Zod schemas specifically for data received from API calls. We’ll leverage data from <a target="_blank" href="https://jsonplaceholder.typicode.com/posts">JSONPlaceholder</a>, which offers information about posts.  </p>
<p>Here’s a sample JSON response representing a post from JSONPlaceholder:</p>
<pre><code class="lang-typescript">{
  <span class="hljs-string">"userId"</span>: <span class="hljs-number">1</span>,
  <span class="hljs-string">"id"</span>: <span class="hljs-number">3</span>,
  <span class="hljs-string">"title"</span>: <span class="hljs-string">"ea molestias quasi exercitationem repellat qui ipsa sit aut"</span>,
  <span class="hljs-string">"body"</span>: <span class="hljs-string">"et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut"</span>
}
</code></pre>
<p>Create a React component (give it a name that fits your project structure) to demonstrate building and utilizing Zod schemas for API validation. In this article, for illustrative purposes, we’ll call it the <code>ZodApi</code> component.</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">import</span> { z } <span class="hljs-keyword">from</span> <span class="hljs-string">'zod'</span>;

  <span class="hljs-keyword">const</span> postSchema = z.object({
  userId: z.number().positive().int(),
  id: z.number().positive().int(),
  title: z.string(),
  body: z.string()
});

<span class="hljs-keyword">const</span> postSchemaArray = z.array(postSchema); <span class="hljs-comment">// Schema for array of posts</span>
</code></pre>
<p>This code defines the expected structure of a single post object (<code>postSchema</code>) and an array of posts (<code>postSchemaArray</code>).</p>
<p>The following sections will explore integrating Zod with React components for API call handling and error management.</p>
<h2 id="heading-how-to-integrate-zod-with-react-api-calls">How to Integrate Zod with React API Calls</h2>
<p>Let's bridge the gap between your defined Zod schemas and real API interactions.</p>
<p>We’ll need to update the code we wrote in the previous section to achieve our desired result in this section.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { z } <span class="hljs-keyword">from</span> <span class="hljs-string">'zod'</span>;
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> postSchema = z.object({
  userId: z.number().positive().int(),
  id: z.number().positive().int(),
  title: z.string(),
  body: z.string()
});

<span class="hljs-keyword">const</span> postSchemaArray = z.array(postSchema); <span class="hljs-comment">// schema for an array of posts</span>

<span class="hljs-keyword">type</span> Posts = z.infer&lt;<span class="hljs-keyword">typeof</span> postSchemaArray&gt;; <span class="hljs-comment">// type of the posts</span>

<span class="hljs-keyword">const</span> ZodApi = <span class="hljs-function">() =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetch(<span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
      .then(<span class="hljs-function">(<span class="hljs-params">posts: Posts</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> validatedPosts = postSchemaArray.safeParse(posts); <span class="hljs-comment">// remember to use safeParse instead of parse</span>

        <span class="hljs-keyword">if</span> (validatedPosts.success === <span class="hljs-literal">false</span>) {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Validation Error:"</span>validatedPosts.error);
          <span class="hljs-keyword">return</span>;
        }

        <span class="hljs-comment">// we can now safely use the posts</span>
        <span class="hljs-built_in">console</span>.log(validatedPosts.data);
      });
  }, []);
  <span class="hljs-keyword">return</span> &lt;div&gt;ZodApi&lt;/div&gt;;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ZodApi;
</code></pre>
<p>The <code>ZodApi</code> component demonstrates:</p>
<ul>
<li><p>Fetching data: Uses <code>useEffect</code> and <code>fetch</code> to get data from the API.</p>
</li>
<li><p>Type safety: <code>type Posts = z.infer&lt;typeof postSchemaArray&gt;;</code> ensures type safety by defining the <code>Posts type</code> inferred from the schema <code>postSchemaArray</code>.</p>
</li>
<li><p>Parsing with Zod: Validates the fetched data against the <code>postSchemaArray</code> using <code>safeParse</code>.</p>
</li>
<li><p>Handling success: If validation succeeds, it provides access to clean data in <code>validatedPosts.data</code> for use in your component (UI, state, and so on).</p>
</li>
</ul>
<p>Error handling: The <code>if</code> statement showcases a simple approach to Zod error handling. In a case where the validation is not successful (<code>validatedPosts.success === false</code>), a ZodError message is logged to the console.  </p>
<p>Here’s a snapshot showing the resulting output in the console.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740504815204/45ce101a-4e8c-475b-ad4d-783b0940710b.png" alt="45ce101a-4e8c-475b-ad4d-783b0940710b" class="image--center mx-auto" width="460" height="203" loading="lazy"></p>
<h2 id="heading-how-to-render-the-user-interface-ui-and-handle-errors-in-react">How to Render the User Interface (UI) and Handle Errors in React</h2>
<p>In this section, you’ll learn how to render the UI based on our validated data and implement the error-handling mechanism using React states.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { z } <span class="hljs-keyword">from</span> <span class="hljs-string">"zod"</span>;
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> postSchema = z.object({
  userId: z.number().positive().int(),
  id: z.number().positive().int(),
  title: z.string(),
  body: z.string(),
});

<span class="hljs-keyword">const</span> postSchemaArray = z.array(postSchema); <span class="hljs-comment">// schema for an array of posts</span>

<span class="hljs-keyword">type</span> Posts = z.infer&lt;<span class="hljs-keyword">typeof</span> postSchemaArray&gt;; <span class="hljs-comment">// type of the posts</span>

<span class="hljs-keyword">const</span> ZodApi = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [posts, setPosts] = useState&lt;Posts&gt;([]); <span class="hljs-comment">// State to store validated posts</span>
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-string">""</span>); <span class="hljs-comment">// State to store any errors</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetch(<span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
      .then(<span class="hljs-function">(<span class="hljs-params">posts: Posts</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> validatedPosts = postSchemaArray.safeParse(posts); <span class="hljs-comment">// remember to use safeParse instead of parse</span>

        <span class="hljs-keyword">if</span> (validatedPosts.success === <span class="hljs-literal">false</span>) {
          <span class="hljs-built_in">console</span>.log(validatedPosts.error.name);
          setError(validatedPosts.error.message); <span class="hljs-comment">// set error state</span>
          <span class="hljs-keyword">return</span>;
        }

        <span class="hljs-comment">// we can now safely use the validatedPosts </span>
        <span class="hljs-built_in">console</span>.log(validatedPosts.data);
        setPosts(validatedPosts.data)
      });
  }, []);

  <span class="hljs-comment">// Handle loading state (optional)</span>
  <span class="hljs-keyword">if</span> (!posts.length &amp;&amp; !error) {
    <span class="hljs-keyword">return</span> &lt;div&gt;Loading posts...&lt;/div&gt;;
  }

  <span class="hljs-comment">// Handle error state</span>
  <span class="hljs-keyword">if</span> (error) {
    <span class="hljs-keyword">return</span> &lt;div&gt;<span class="hljs-built_in">Error</span> fetching Data&lt;<span class="hljs-regexp">/div&gt;; /</span><span class="hljs-regexp">/ Display user-friendly error message
  }

  return (
    &lt;div&gt;
      &lt;h1&gt;Posts&lt;/</span>h1&gt;
      &lt;ol&gt;
        {posts.map(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> (
          &lt;li key={post.id}&gt;
            {post.title}
          &lt;/li&gt;
        ))}
      &lt;/ol&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ZodApi;
</code></pre>
<p>In the code above, we’ve updated the <code>ZodApi</code> component to perform the following tasks:</p>
<ul>
<li><p>State declaration: The <code>posts</code> and <code>error</code> states hold the data and error (if any) gotten from the fetch request.</p>
</li>
<li><p>Error handling: We use the <code>posts</code> and <code>error</code> state to show a “Loading posts…” message when the posts are being fetched and no error occurs, and display an error message when an error occurs.</p>
</li>
<li><p>Rendering posts: It maps through the fetched posts and renders them on the UI.</p>
</li>
</ul>
<p>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740506104138/f2afac53-e312-4a40-af01-500e0dd349f7.gif" alt="f2afac53-e312-4a40-af01-500e0dd349f7" class="image--center mx-auto" width="400" height="814" loading="lazy"></p>
<p>After fetching the results, you should see the 100 posts displayed on your screen. If you followed the steps correctly, you'll find all 100 posts visible. If you encounter any issues, make sure the fetching process was successful.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By incorporating Zod into your React development workflow, you can build more robust and reliable applications.</p>
<p>Zod empowers you to catch mismatched data early on, preventing errors and saving valuable debugging time. Also, the user-friendly error messages given by Zod validation enhance your application’s overall user experience.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
