<?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[ javascript framework - 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[ javascript framework - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 19:48:31 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/javascript-framework/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build Production-Ready Web Apps with the Hono Framework: A Deep Dive ]]>
                </title>
                <description>
                    <![CDATA[ As a dev, you’d probably like to write your application once and not have to worry so much about where it's going to run. This is what the open source framework Hono lets you do, and it’s a game-changer. Hono is a small, incredibly fast web framework... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-production-ready-web-apps-with-hono/</link>
                <guid isPermaLink="false">68bf3ea02c935a9d306bb65a</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ hono ]]>
                    </category>
                
                    <category>
                        <![CDATA[ javascript framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mayur Vekariya ]]>
                </dc:creator>
                <pubDate>Mon, 08 Sep 2025 20:37:52 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757363825321/562644c8-b2b3-4c1c-92c2-736bcade5aac.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As a dev, you’d probably like to write your application once and not have to worry so much about where it's going to run. This is what the open source framework Hono lets you do, and it’s a game-changer. Hono is a small, incredibly fast web framework that embraces the "write once, run anywhere" philosophy.</p>
<p>The JavaScript ecosystem moves quickly. One minute, we're building monolithic Node.js servers. The next, it's all about serverless functions and running code at the edge on platforms like Cloudflare or Vercel. Staying current can feel like a full-time job.</p>
<p><a target="_blank" href="https://hono.dev/">Hono</a> is built on top of Web Standards – the same <code>Request</code> and <code>Response</code> objects in your browser – which means your code is naturally portable across almost any JavaScript runtime.</p>
<p>This guide is a deep dive into this powerful little framework, designed to help you build real, production-ready applications. We’ll skip the quick "Hello, World!" and jump straight into the patterns and features you will actually use, with plenty of detailed code examples along the way.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-you-will-learn-in-this-guide">What You Will Learn in This Guide</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites-for-following-along">Prerequisites for Following Along</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-a-professional-hono-project">How to Set Up a Professional Hono Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-understand-honos-core-api">How to Understand Hono's Core API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-context-object-in-depth">The Context Object in Depth</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-advanced-features-for-production-apps">How to Use Advanced Features for Production Apps</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-deployment-guide-for-hono">Deployment Guide for Hono</a></p>
</li>
</ul>
<h3 id="heading-what-you-will-learn-in-this-guide">What You Will Learn in This Guide</h3>
<p>By the end of this tutorial, you will be able to:</p>
<ul>
<li><p>Structure a Hono project for both development and production.</p>
</li>
<li><p>Implement advanced routing patterns.</p>
</li>
<li><p>Leverage the full power of the <strong>Context</strong> object to manage requests and pass data between middleware.</p>
</li>
<li><p>Write complex custom middleware for authentication, logging, and error handling.</p>
</li>
<li><p>Validate incoming data using the official <strong>Zod</strong> validator for robust APIs.</p>
</li>
<li><p>Build a small, server-rendered application with <strong>JSX</strong> components.</p>
</li>
<li><p>Deploy a Hono application to various modern hosting platforms.</p>
</li>
</ul>
<h3 id="heading-prerequisites-for-following-along">Prerequisites for Following Along</h3>
<p>This is an in-depth guide, but it assumes you have some foundational knowledge. Before you start, you should have:</p>
<ul>
<li><p><strong>Node.js installed:</strong> Version 18 or higher is recommended.</p>
</li>
<li><p><strong>A code editor:</strong> Visual Studio Code is a great choice.</p>
</li>
<li><p><strong>Familiarity with TypeScript:</strong> You should understand basic types, functions, and <code>async</code>/<code>await</code>.</p>
</li>
<li><p><strong>Basic command-line knowledge:</strong> You should be comfortable running commands in your terminal.</p>
</li>
</ul>
<h2 id="heading-how-to-set-up-a-professional-hono-project">How to Set Up a Professional Hono Project</h2>
<p>You can get started with Hono using a single command. This will create a new project directory with a recommended structure and configuration files. When prompted, select the <code>nodejs</code> template and choose to install dependencies with your preferred package manager (for example, npm).</p>
<pre><code class="lang-bash">npm create hono@latest hono-production-app
</code></pre>
<p>The command will guide you through the setup:</p>
<pre><code class="lang-bash">&gt; npx create-hono hono-production-app

create-hono version 0.19.2
✔ Using target directory … hono-production-app
✔ Which template <span class="hljs-keyword">do</span> you want to use? nodejs
✔ Do you want to install project dependencies? Yes
✔ Which package manager <span class="hljs-keyword">do</span> you want to use? npm
✔ Cloning the template
✔ Installing project dependencies
🎉 Copied project files
Get started with: <span class="hljs-built_in">cd</span> hono-production-app
</code></pre>
<p>Now, navigate into your new directory: <code>cd hono-production-app</code>. Let's look at the files that were created:</p>
<ul>
<li><p><code>package.json</code>: Defines your project's dependencies and scripts.</p>
</li>
<li><p><code>tsconfig.json</code>: The TypeScript configuration file.</p>
</li>
<li><p><code>src/index.ts</code>: The entry point of your application.</p>
</li>
</ul>
<p>Now, you can run <code>npm run dev</code> to start your development server. Navigate to <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a>, and you will see "Hello Hono!".</p>
<h2 id="heading-how-to-understand-honos-core-api">How to Understand Hono's Core API</h2>
<p>Hono's API is designed to be minimal, which makes it easy to learn – yet incredibly powerful.</p>
<h3 id="heading-how-to-use-advanced-routing-techniques">How to Use Advanced Routing Techniques</h3>
<p>You may already know <code>app.get()</code> and <code>app.post()</code> from Express, but Hono's router can do much more.</p>
<h4 id="heading-1-how-to-route-with-regular-expressions">1. How to Route with Regular Expressions</h4>
<p>You can constrain a URL parameter to match a specific regular expression. For example, to make sure an <code>:id</code> parameter only accepts numbers, you can do this:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Only match routes like /users/123, not /users/abc</span>
app.get(<span class="hljs-string">'/users/:id{[0-9]+}'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> id = c.req.param(<span class="hljs-string">'id'</span>)
  <span class="hljs-keyword">return</span> c.text(<span class="hljs-string">`Fetching data for user ID: <span class="hljs-subst">${id}</span>`</span>)
})
</code></pre>
<h4 id="heading-2-how-to-use-optional-and-wildcard-routes">2. How to Use Optional and Wildcard Routes</h4>
<p>You can define routes that match multiple paths using wildcards (<code>*</code>) or handle optional parameters.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// This will match /files/image.png, /files/docs/report.pdf, and so on.</span>
app.get(<span class="hljs-string">'/files/*'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> {
  <span class="hljs-comment">// c.req.path will contain the full matched path</span>
  <span class="hljs-keyword">return</span> c.text(<span class="hljs-string">`You are accessing the file at: <span class="hljs-subst">${c.req.path}</span>`</span>)
})

<span class="hljs-comment">// The '?' makes the '/:format?' part of the URL optional</span>
<span class="hljs-comment">// This will match both /api/posts and /api/posts/json</span>
app.get(<span class="hljs-string">'/api/posts/:format?'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> format = c.req.param(<span class="hljs-string">'format'</span>)
  <span class="hljs-keyword">if</span> (format === <span class="hljs-string">'json'</span>) {
    <span class="hljs-keyword">return</span> c.json({ message: <span class="hljs-string">'Here are the posts in JSON format.'</span> })
  }
  <span class="hljs-keyword">return</span> c.text(<span class="hljs-string">'Here are the posts in plain text.'</span>)
})
</code></pre>
<h4 id="heading-3-how-to-group-routes-with-approute">3. How to Group Routes with <code>app.route()</code></h4>
<p>For larger applications, you should organize your routes into logical groups. The <code>app.route()</code> method is perfect for this. It allows you to create modular routers and mount them on a specific prefix.</p>
<p>Let's create a more complex API structure for a blog.</p>
<p><code>src/routes/posts.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Hono } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono'</span>

<span class="hljs-comment">// Create a new router instance specifically for posts</span>
<span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">new</span> Hono()

posts.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> c.json({ posts: [] }))
posts.post(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> c.json({ message: <span class="hljs-string">'Post created'</span> }, <span class="hljs-number">201</span>))
posts.get(<span class="hljs-string">'/:id'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> c.json({ post: { id: c.req.param(<span class="hljs-string">'id'</span>) } }))

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> posts
</code></pre>
<p><code>src/routes/authors.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Hono } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono'</span>

<span class="hljs-keyword">const</span> authors = <span class="hljs-keyword">new</span> Hono()

authors.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> c.json({ authors: [] }))
authors.get(<span class="hljs-string">'/:id'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> c.json({ author: { id: c.req.param(<span class="hljs-string">'id'</span>) } }))

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> authors
</code></pre>
<p><code>src/index.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { serve } <span class="hljs-keyword">from</span> <span class="hljs-string">'@hono/node-server'</span>
<span class="hljs-keyword">import</span> { Hono } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono'</span>
<span class="hljs-keyword">import</span> { appendTrailingSlash } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono/trailing-slash'</span>;
<span class="hljs-keyword">import</span> posts <span class="hljs-keyword">from</span> <span class="hljs-string">'./routes/posts.js'</span>
<span class="hljs-keyword">import</span> authors <span class="hljs-keyword">from</span> <span class="hljs-string">'./routes/authors.js'</span>

<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Hono()

app.use(appendTrailingSlash());

app.route(<span class="hljs-string">'/posts/'</span>, posts)
app.route(<span class="hljs-string">'/authors/'</span>, authors)

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> c.text(<span class="hljs-string">'Hello Hono!'</span>)
})

serve({
  fetch: app.fetch,
  port: <span class="hljs-number">3000</span>
}, <span class="hljs-function">(<span class="hljs-params">info</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running on http://localhost:<span class="hljs-subst">${info.port}</span>`</span>)
})
</code></pre>
<p>This pattern keeps your main <code>index.ts</code> file clean and makes your application much easier to navigate and maintain.</p>
<h2 id="heading-the-context-object-in-depth">The Context Object in Depth</h2>
<p>The <strong>Context</strong> (<code>c</code>) is the heart of Hono. It's an object that gets passed to every middleware and route handler, containing all the information related to the current request. It's essentially a container for the request (<code>c.req</code>) methods for creating a response (<code>c.json</code>, <code>c.html</code>, <code>c.text</code>), as well as a special property for passing data between middleware (<code>c.set</code> and <code>c.get</code>).</p>
<p>While this covers its most common and useful properties, the full Context object contains more. For a comprehensive list of all available properties and methods, you can refer to the official <a target="_blank" href="https://hono.dev/docs/api/context">Hono documentation</a>.</p>
<p>Let's explore how you can use the context object to pass data between middleware and handlers, a crucial technique for things like authentication.</p>
<p>The <code>c.set()</code> and <code>c.get()</code> methods allow you to store and retrieve typed data within the context of a single request.</p>
<p>Replace <code>src/index.ts</code> with this example for authentication:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Hono } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono'</span>
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { Context, Next } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono'</span>

<span class="hljs-comment">// Define a type for the variables we will store in the context</span>
<span class="hljs-keyword">type</span> AppVariables = {
  user: {
    id: <span class="hljs-built_in">string</span>
    name: <span class="hljs-built_in">string</span>
    roles: <span class="hljs-built_in">string</span>[]
  }
}

<span class="hljs-comment">// Use a generic to tell our Hono app about the variables type</span>
<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Hono&lt;{ Variables: AppVariables }&gt;()

<span class="hljs-comment">// Middleware to "authenticate" a user from a header</span>
<span class="hljs-keyword">const</span> authMiddleware = <span class="hljs-keyword">async</span> (c: Context, next: Next) =&gt; {
  <span class="hljs-keyword">const</span> userId = c.req.header(<span class="hljs-string">'X-User-ID'</span>)
  <span class="hljs-keyword">if</span> (!userId) {
    <span class="hljs-keyword">return</span> c.json({ error: <span class="hljs-string">'Missing X-User-ID header'</span> }, <span class="hljs-number">401</span>)
  }

  <span class="hljs-comment">// In a real app, you would fetch this from a database</span>
  <span class="hljs-keyword">const</span> user = {
    id: userId,
    name: <span class="hljs-string">'Jane Doe'</span>,
    roles: [<span class="hljs-string">'admin'</span>, <span class="hljs-string">'editor'</span>],
  }

  <span class="hljs-comment">// Use c.set() to attach the user data to the context</span>
  c.set(<span class="hljs-string">'user'</span>, user)

  <span class="hljs-keyword">await</span> next()
}

app.get(<span class="hljs-string">'/admin/dashboard'</span>, authMiddleware, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> {
  <span class="hljs-comment">// Use c.get() to retrieve the typed user data</span>
  <span class="hljs-keyword">const</span> user = c.get(<span class="hljs-string">'user'</span>)

  <span class="hljs-keyword">if</span> (!user.roles.includes(<span class="hljs-string">'admin'</span>)) {
    <span class="hljs-keyword">return</span> c.json({ error: <span class="hljs-string">'Forbidden'</span> }, <span class="hljs-number">403</span>)
  }

  <span class="hljs-keyword">return</span> c.json({
    message: <span class="hljs-string">`Welcome to the admin dashboard, <span class="hljs-subst">${user.name}</span>!`</span>,
    userId: user.id,
  })
})

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> app
</code></pre>
<p>Let's break down the important parts of the code above.</p>
<ul>
<li><p><strong>Typed context variables</strong>: We define a TypeScript type <code>AppVariables</code> and pass it as a generic to our Hono app <code>new Hono&lt;{ Variables: AppVariables }&gt;()</code>. This is a powerful feature that gives us full type-safety for our context variables, preventing typos and ensuring that the data we store and retrieve is exactly what we expect it to be.</p>
</li>
<li><p><strong>Custom middleware</strong>: The <code>authMiddleware</code> is a custom function that runs before our route handler. It inspects the incoming request's headers (<code>c.req.header('X-User-ID')</code>).</p>
</li>
<li><p><strong>Storing data</strong>: If a valid header is found, the middleware uses <code>c.set('user', user)</code> to store the user object on the context. This data is now available to any subsequent middleware or route handler for the same request.</p>
</li>
<li><p><strong>Retrieving data</strong>: The route handler <code>app.get('/admin/dashboard', ...)</code> then uses <code>c.get('user')</code> to retrieve the user object. Hono's type system ensures that <code>c.get('user')</code> returns a variable with the type <code>{ id: string; name: string; roles: string[]; }</code>.</p>
</li>
<li><p><strong>Flow control</strong>: If the user is missing or doesn't have the "admin" role, the middleware or handler can immediately send an error response using <code>c.json()</code> and a status code, preventing the request from proceeding further.</p>
</li>
</ul>
<p>Now, run <code>npm run dev</code>.</p>
<p>You can test with <code>curl</code> (add header):</p>
<pre><code class="lang-bash">curl -H <span class="hljs-string">"X-User-ID: 123"</span> http://localhost:3000/admin/dashboard
</code></pre>
<p>This will return a welcome message.</p>
<p>Without the header:</p>
<pre><code class="lang-bash">curl http://localhost:3000/admin/dashboard
</code></pre>
<p>This will return a <code>401</code> error.</p>
<p>This demonstrates how to pass typed data securely and efficiently between middleware and route handlers.</p>
<h2 id="heading-how-to-use-advanced-features-for-production-apps">How to Use Advanced Features for Production Apps</h2>
<p>Now we're ready to tackle the features you'll use every day in production: advanced middleware, data validation, and building full-stack applications.</p>
<h3 id="heading-how-to-use-advanced-middleware-patterns">How to Use Advanced Middleware Patterns</h3>
<p>Hono has a powerful set of built-in middleware, including JWT and caching. These are not separate libraries you have to install, but rather functions that come with the Hono package itself.</p>
<p><strong>Step 1:</strong> Replace <code>src/index.ts</code> with this example for JWT and caching:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Hono } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono'</span>
<span class="hljs-keyword">import</span> { serve } <span class="hljs-keyword">from</span> <span class="hljs-string">'@hono/node-server'</span>
<span class="hljs-keyword">import</span> { jwt, sign } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono/jwt'</span>

<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Hono()
<span class="hljs-keyword">const</span> SECRET = <span class="hljs-string">'my-secret-key'</span> <span class="hljs-comment">// Use an environment variable in production!</span>

<span class="hljs-comment">// Create a simple in-memory cache store</span>
<span class="hljs-keyword">const</span> cacheStore = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>();

<span class="hljs-comment">// Custom caching middleware for Node.js</span>
app.use(<span class="hljs-string">'/api/public-data'</span>, <span class="hljs-keyword">async</span> (c, next) =&gt; {
  <span class="hljs-keyword">const</span> cacheKey = c.req.url;

  <span class="hljs-comment">// Check if the response is in our cache</span>
  <span class="hljs-keyword">if</span> (cacheStore.has(cacheKey)) {
    <span class="hljs-keyword">const</span> cachedItem = cacheStore.get(cacheKey);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Serving from custom in-memory cache.'</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(cachedItem.body, { headers: cachedItem.headers });
  }

  <span class="hljs-comment">// If not in cache, proceed to the route handler</span>
  <span class="hljs-keyword">await</span> next();

  <span class="hljs-comment">// After the handler returns, clone and store the response</span>
  <span class="hljs-keyword">if</span> (c.res) {
    <span class="hljs-keyword">const</span> newResponse = c.res.clone();
    <span class="hljs-keyword">const</span> body = <span class="hljs-keyword">await</span> newResponse.text();
    <span class="hljs-keyword">const</span> headers = <span class="hljs-built_in">Object</span>.fromEntries(newResponse.headers.entries());
    cacheStore.set(cacheKey, { body, headers });
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Storing response in custom in-memory cache.'</span>);
  }
});

<span class="hljs-comment">// Login to get a JWT</span>
app.post(<span class="hljs-string">'/login'</span>, <span class="hljs-keyword">async</span> (c) =&gt; {
  <span class="hljs-keyword">const</span> { username } = <span class="hljs-keyword">await</span> c.req.json()
  <span class="hljs-keyword">if</span> (username === <span class="hljs-string">'admin'</span>) {
    <span class="hljs-keyword">const</span> payload = {
      sub: username,
      role: <span class="hljs-string">'admin'</span>,
      exp: <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Date</span>.now() / <span class="hljs-number">1000</span>) + <span class="hljs-number">60</span> * <span class="hljs-number">5</span>, <span class="hljs-comment">// 5 minutes expiration</span>
    }
    <span class="hljs-keyword">const</span> token = <span class="hljs-keyword">await</span> sign(payload, SECRET)
    <span class="hljs-keyword">return</span> c.json({ token })
  }
  <span class="hljs-keyword">return</span> c.json({ error: <span class="hljs-string">'Invalid credentials'</span> }, <span class="hljs-number">401</span>)
})

<span class="hljs-comment">// Protected route</span>
app.get(
  <span class="hljs-string">'/api/protected'</span>,
  jwt({ secret: SECRET }),
  <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> payload = c.get(<span class="hljs-string">'jwtPayload'</span>)
    <span class="hljs-keyword">return</span> c.json({ message: <span class="hljs-string">'You have access!'</span>, payload })
  }
)

<span class="hljs-comment">// Cached route</span>
app.get(
  <span class="hljs-string">'/api/public-data'</span>,
  <span class="hljs-keyword">async</span> (c) =&gt; {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Executing handler with delay...'</span>);
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-number">1000</span>)) <span class="hljs-comment">// Simulate a delay</span>
    <span class="hljs-keyword">return</span> c.json({ data: <span class="hljs-string">'This is some public data that rarely changes.'</span> })
  }
)

serve({ fetch: app.fetch, port: <span class="hljs-number">3000</span> }, <span class="hljs-function">(<span class="hljs-params">info</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running on http://localhost:<span class="hljs-subst">${info.port}</span>`</span>)
})
</code></pre>
<p>The code above shows two different types of middleware in action.</p>
<p>First, <strong>JWT middleware</strong> (<code>jwt</code>) is a powerful way to secure your routes. When we call <code>jwt({ secret: SECRET })</code>, we're telling Hono to check for a valid JWT in the <code>Authorization</code> header of the incoming request. If a valid token is found, it decodes the payload and attaches it to the context, where we can retrieve it with <code>c.get('jwtPayload')</code>. If no token is found or if the token is invalid, the middleware automatically stops the request and returns a <code>401 Unauthorized</code> error.</p>
<p>We also have <strong>Custom Cache Middleware</strong> which demonstrates the power of Hono's middleware system for in-memory caching. The middleware first checks an in-memory <code>Map</code> to see if a response for the current URL already exists. If it does, it immediately returns the cached response, preventing the route handler from ever being executed. If the response is not in the cache, it allows the request to continue to the handler. After the handler returns, the middleware intercepts the response and stores a copy in the cache before sending it back to the client. This is a robust and reliable pattern for Node.js environments.</p>
<p><strong>Step 2:</strong> Run <code>npm run dev</code>.</p>
<p><strong>Step 3:</strong> Test the login endpoint with <code>curl</code>:</p>
<p>First, let's test the login endpoint to get a JWT. Open a new terminal and run the following command. The command sends a <code>POST</code> request to the <code>/login</code> endpoint with <code>username: "admin"</code> in the request body.</p>
<pre><code class="lang-bash">curl -X POST http://localhost:3000/login -H <span class="hljs-string">"Content-Type: application/json"</span> -d <span class="hljs-string">'{"username": "admin"}'</span>
</code></pre>
<p>This will return a JSON object with a JWT. Copy this token for the next step.</p>
<p>Now, let's test the protected route. We'll use the token we just received in the <code>Authorization</code> header. Replace <code>&lt;your_jwt_token&gt;</code> with the token you copied.</p>
<pre><code class="lang-bash">curl http://localhost:3000/api/protected -H <span class="hljs-string">"Authorization: Bearer &lt;your_jwt_token&gt;"</span>
</code></pre>
<p>You should get a success message with the decoded payload.</p>
<p>Finally, let's test the cached route. You’ll need to run a production build and run the file with <code>node</code> for this to work.</p>
<p>First, run the following command. The <code>1000</code> millisecond delay in the code will make this request take about a second.</p>
<pre><code class="lang-bash">curl -o /dev/null -s -w <span class="hljs-string">'Total: %{time_total}s\n'</span> http://localhost:3000/api/public-data
</code></pre>
<p>Immediately run the <strong>exact same command again</strong>. This time, the response will be almost instantaneous because our custom cache middleware served the response directly from its in-memory store, completely bypassing the <code>setTimeout</code> in the route handler. Run it a third time, and you'll see a similar near-instantaneous response.</p>
<p>Here's an example of what your terminal output should look like when testing the cache. The first request took around 1 second, but subsequent requests were a matter of milliseconds.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757125753352/180cc4a7-f361-4966-a26f-a5d8251f77a4.png" alt="180cc4a7-f361-4966-a26f-a5d8251f77a4" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-create-a-global-error-handler">How to Create a Global Error Handler</h3>
<p>You can define a single global error handler with <code>app.onError()</code>. This is useful for handling unexpected errors in a centralized way, such as validation failures.</p>
<p>Add the following code to your <code>src/index.ts</code>:</p>
<pre><code class="lang-typescript">app.get(<span class="hljs-string">'/users/:id'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> id = c.req.param(<span class="hljs-string">'id'</span>)
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(<span class="hljs-built_in">Number</span>(id))) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'User ID must be a number.'</span>)
  }
  <span class="hljs-keyword">return</span> c.text(<span class="hljs-string">`User ID is <span class="hljs-subst">${id}</span>`</span>)
})

app.onError(<span class="hljs-function">(<span class="hljs-params">err, c</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`<span class="hljs-subst">${err}</span>`</span>)
  <span class="hljs-keyword">return</span> c.json({
    success: <span class="hljs-literal">false</span>,
    message: err.message,
  }, <span class="hljs-number">500</span>)
})
</code></pre>
<p>Now, if you visit <a target="_blank" href="http://localhost:3000/users/abc"><code>http://localhost:3000/users/abc</code></a>, you will get a JSON error response instead of an uncaught exception.</p>
<h3 id="heading-how-to-handle-validation-with-zod">How to Handle Validation with Zod</h3>
<p>For robust APIs, data validation is essential. Hono integrates seamlessly with <a target="_blank" href="https://zod.dev/">Zod</a>, a popular TypeScript-first schema validation library.</p>
<p><strong>Step 1:</strong> Install the necessary dependencies:</p>
<pre><code class="lang-bash">npm install zod @hono/zod-validator
</code></pre>
<p><strong>Step 2:</strong> Replace <code>src/index.ts</code> with the validation example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Hono } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono'</span>
<span class="hljs-keyword">import</span> { serve } <span class="hljs-keyword">from</span> <span class="hljs-string">'@hono/node-server'</span>
<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> { zValidator } <span class="hljs-keyword">from</span> <span class="hljs-string">'@hono/zod-validator'</span>

<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Hono()

<span class="hljs-comment">// Define a Zod schema for the user creation data</span>
<span class="hljs-keyword">const</span> createUserSchema = z.object({
  username: z.string().min(<span class="hljs-number">3</span>).max(<span class="hljs-number">20</span>),
  email: z.string().email(),
  age: z.number().int().positive(),
  tags: z.array(z.string()).optional(),
})

app.post(
  <span class="hljs-string">'/users'</span>,
  zValidator(<span class="hljs-string">'json'</span>, createUserSchema), <span class="hljs-comment">// Use zValidator middleware</span>
  (c) =&gt; {
    <span class="hljs-comment">// The validated data is available on c.req.valid()</span>
    <span class="hljs-keyword">const</span> user = c.req.valid(<span class="hljs-string">'json'</span>)
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Creating user: <span class="hljs-subst">${user.username}</span> with email <span class="hljs-subst">${user.email}</span>`</span>)
    <span class="hljs-keyword">return</span> c.json({
      success: <span class="hljs-literal">true</span>,
      message: <span class="hljs-string">'User created successfully!'</span>,
      user: user,
    }, <span class="hljs-number">201</span>)
  }
)

serve({ fetch: app.fetch, port: <span class="hljs-number">3000</span> }, <span class="hljs-function">(<span class="hljs-params">info</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running on http://localhost:<span class="hljs-subst">${info.port}</span>`</span>)
})
</code></pre>
<p>This is how the Zod validation is working:</p>
<ol>
<li><p>We first define a schema called <code>createUserSchema</code> using <code>z.object()</code>. This schema is a blueprint for the expected data structure. We use Zod's built-in methods like <code>z.string().min(3)</code>, <code>z.string().email()</code>, and <code>z.number().int().positive()</code> to specify validation rules for each property. For example, <code>username</code> must be a string between 3 and 20 characters, <code>email</code> must be a valid email format, and <code>age</code> must be a positive integer.</p>
</li>
<li><p>We then apply the <a target="_blank" href="https://github.com/honojs/middleware/tree/main/packages/zod-validator"><code>zValidator</code></a> middleware to our route handler. The first argument, <code>'json'</code>, tells the middleware to validate the incoming request's JSON body. The second argument, <code>createUserSchema</code>, tells it which schema to use for the validation.</p>
</li>
<li><p>The <code>zValidator</code> middleware automatically does the heavy lifting. When a request hits the <code>/users</code> endpoint, it will parse the JSON body and attempt to validate it against <code>createUserSchema</code>. If the data is invalid (for example, the <code>email</code> is not in a valid format), the middleware will immediately stop the request and return a <code>400 Bad Request</code> status with a detailed error message, all without us having to write any manual checks.</p>
</li>
<li><p>If the data is valid, the middleware makes it available on the <code>Context</code> object, which we can access with <code>c.req.valid('json')</code>. Hono's type system ensures that this data is correctly typed according to the Zod schema, so we can use it safely in our handler.</p>
</li>
</ol>
<p><strong>Step 3:</strong> Run <code>npm run dev</code>.</p>
<p><strong>Step 4:</strong> Test with <code>curl</code> (valid data):</p>
<pre><code class="lang-bash">curl -X POST http://localhost:3000/users -H <span class="hljs-string">"Content-Type: application/json"</span> -d <span class="hljs-string">'{"username": "testuser", "email": "test@example.com", "age": 25}'</span>
</code></pre>
<p>This will return a success message.</p>
<p>Test with invalid data (for example, bad email):</p>
<pre><code class="lang-bash">curl -X POST http://localhost:3000/users -H <span class="hljs-string">"Content-Type: application/json"</span> -d <span class="hljs-string">'{"username": "testuser", "email": "invalid-email", "age": 25}'</span>
</code></pre>
<p>This will automatically return a <code>400</code> status with a detailed error message from Zod.</p>
<h3 id="heading-how-to-build-a-full-stack-app-with-jsx">How to Build a Full-Stack App with JSX</h3>
<p>Hono supports server-side rendering with JSX, allowing you to build full-stack applications without needing a separate framework.</p>
<p><strong>Step 1:</strong> Create <code>src/components/Layout.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { html } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono/html'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Layout = <span class="hljs-function">(<span class="hljs-params">props: { title: <span class="hljs-built_in">string</span>; children?: <span class="hljs-built_in">any</span> }</span>) =&gt;</span> html`<span class="xml">
  <span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span></span><span class="hljs-subst">${props.title}</span><span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-tag">body</span> { <span class="hljs-attribute">font-family</span>: sans-serif; <span class="hljs-attribute">background</span>: <span class="hljs-number">#f4f4f4</span>; <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>; }
        <span class="hljs-selector-class">.container</span> { <span class="hljs-attribute">max-width</span>: <span class="hljs-number">800px</span>; <span class="hljs-attribute">margin</span>: <span class="hljs-number">2rem</span> auto; <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>; <span class="hljs-attribute">background</span>: white; <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>; }
        <span class="hljs-selector-tag">header</span> { <span class="hljs-attribute">border-bottom</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>; <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">1rem</span>; }
        <span class="hljs-selector-tag">footer</span> { <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">2rem</span>; <span class="hljs-attribute">text-align</span>: center; <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.8rem</span>; <span class="hljs-attribute">color</span>: <span class="hljs-number">#777</span>; }
      </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span></span><span class="hljs-subst">${props.title}</span><span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
          </span><span class="hljs-subst">${props.children}</span><span class="xml">
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Powered by Hono<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
`</span>
</code></pre>
<p><strong>Step 2:</strong> Create <code>src/components/PostItem.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> PostItem = <span class="hljs-function">(<span class="hljs-params">props: { post: { id: <span class="hljs-built_in">number</span>; title: <span class="hljs-built_in">string</span>; author: <span class="hljs-built_in">string</span> } }</span>) =&gt;</span> (
  &lt;article style=<span class="hljs-string">"border-bottom: 1px solid #eee; padding: 1rem 0;"</span>&gt;
    &lt;h3&gt;&lt;a href={<span class="hljs-string">`/posts/<span class="hljs-subst">${props.post.id}</span>`</span>}&gt;{props.post.title}&lt;<span class="hljs-regexp">/a&gt;&lt;/</span>h3&gt;
    &lt;p&gt;&lt;em&gt;By {props.post.author}&lt;<span class="hljs-regexp">/em&gt;&lt;/</span>p&gt;
  &lt;/article&gt;
)
</code></pre>
<p><strong>Step 3:</strong> Update <code>src/index.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Hono } <span class="hljs-keyword">from</span> <span class="hljs-string">'hono'</span>
<span class="hljs-keyword">import</span> { serve } <span class="hljs-keyword">from</span> <span class="hljs-string">'@hono/node-server'</span>
<span class="hljs-keyword">import</span> { Layout } <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Layout'</span>
<span class="hljs-keyword">import</span> { PostItem } <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/PostItem'</span>

<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Hono()

<span class="hljs-comment">// Mock data</span>
<span class="hljs-keyword">const</span> posts = [
  { id: <span class="hljs-number">1</span>, title: <span class="hljs-string">'Getting Started with Hono'</span>, author: <span class="hljs-string">'Alice'</span> },
  { id: <span class="hljs-number">2</span>, title: <span class="hljs-string">'Advanced Middleware Patterns'</span>, author: <span class="hljs-string">'Bob'</span> },
  { id: <span class="hljs-number">3</span>, title: <span class="hljs-string">'Deploying Hono to the Edge'</span>, author: <span class="hljs-string">'Charlie'</span> },
]

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">c</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> c.html(
    &lt;Layout title=<span class="hljs-string">"My Hono Blog"</span>&gt;
      &lt;h2&gt;Recent Posts&lt;/h2&gt;
      {posts.length &gt; <span class="hljs-number">0</span>
        ? posts.map(<span class="hljs-function"><span class="hljs-params">post</span> =&gt;</span> &lt;PostItem post={post} /&gt;)
        : &lt;p&gt;No posts yet!&lt;/p&gt;
      }
    &lt;/Layout&gt;
  )
})

serve({ fetch: app.fetch, port: <span class="hljs-number">3000</span> }, <span class="hljs-function">(<span class="hljs-params">info</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running on http://localhost:<span class="hljs-subst">${info.port}</span>`</span>)
})
</code></pre>
<p>Make sure to update the <code>dev</code> script in your <code>package.json</code> file to have <code>src/index.tsx</code> as the starting point.</p>
<pre><code class="lang-json"><span class="hljs-string">"dev"</span>: <span class="hljs-string">"tsx watch src/index.tsx"</span>
</code></pre>
<p><strong>Step 4:</strong> Run <code>npm run dev</code> and visit <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a>. You will see a fully rendered blog page with the list of posts.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756952439130/27ee63cc-6d60-4372-9634-4d1eadf33f32.png" alt="Blog page with list of posts" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-deployment-guide-for-hono">Deployment Guide for Hono</h2>
<p>You have built your application, and now it's time to share it with the world. Here’s how you can deploy your Hono app to some of the most popular platforms.</p>
<h3 id="heading-how-to-deploy-to-nodejs">How to Deploy to Node.js</h3>
<p>For a traditional server environment, you can use the <code>@hono/node-server</code> adapter and a process manager like <code>pm2</code> for production.</p>
<p><code>src/index.ts</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { serve } <span class="hljs-keyword">from</span> <span class="hljs-string">'@hono/node-server'</span>
<span class="hljs-keyword">import</span> app <span class="hljs-keyword">from</span> <span class="hljs-string">'./app'</span> <span class="hljs-comment">// Assuming your Hono app is in app.ts</span>

serve({ fetch: app.fetch, port: <span class="hljs-number">3000</span> })
</code></pre>
<p>You will then build your TypeScript to JavaScript and run <code>pm2 start dist/index.js</code> to run it in the background.</p>
<h3 id="heading-how-to-deploy-to-cloudflare-workers">How to Deploy to Cloudflare Workers</h3>
<p>Hono's true power lies in its portability. The <code>create hono</code> command can set up a project specifically for Cloudflare Workers.</p>
<p>Run the following command and select the <code>cloudflare-workers</code> template:</p>
<pre><code class="lang-bash">npm create hono@latest my-app-hono-cloudflare-worker

create-hono version 0.19.2
✔ Using target directory … my-app-hono-cloudflare-worker
? Which template <span class="hljs-keyword">do</span> you want to use?
  aws-lambda
  bun
❯ cloudflare-workers
  cloudflare-workers+vite
  deno
  fastly
  lambda-edge
</code></pre>
<p>The setup process is identical to the Node.js example, but the project structure is optimized for Cloudflare.</p>
<p>Once the project is set up, you only need to type one command to deploy your application to Cloudflare:</p>
<pre><code class="lang-bash">wrangler deploy
</code></pre>
<p>This command will prompt you to log in to your Cloudflare account and will handle the entire deployment process automatically.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>You've made it! We’ve covered a lot in this guide. You started with a professional project setup and moved all the way through advanced routing, context management, complex middleware patterns, robust data validation, and full-stack JSX components.</p>
<p>You now have the knowledge and the tools to build serious, production-ready applications with Hono. Its simple API doesn't limit its power. Rather, it enhances it by getting out of your way and letting you focus on building great features. And with its helpful portability, you can be confident that the application you build today can be deployed to the platforms of tomorrow.</p>
<p>The web development ecosystem will continue to evolve, but by building on Web Standards, Hono is a framework that's built to last.</p>
<p>To continue your journey, I highly recommend exploring the official <a target="_blank" href="https://hono.dev/docs/">Hono documentation</a>, which is full of even more examples and guides.</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>
        
    </channel>
</rss>
