Axios vs Fetch for beginners

updated on 19 April 2022

When we build applications that require us to make a network request, either to our backend or a third-party API, we use HTTP clients like Axios and Fetch to perform such requests. 


In this guide, we introduce Axios and Fetch and compare them so that we can make an informed decision on which one to select.

A quick overview of Fetch and Axios

The Fetch API is an interface that exposes a method called fetch() for making a network request. It is built into modern browsers and so no installation is required. It is also available as an experimental feature in node.js.

Axios is a third-party library that we can add to our project either via a Content Distribution Network or CDN, or install it via a package manager, like npm or yarn. Axios can run within a browser or a node.js environment.

Fetch and axios are both promise-based HTTP clients. This means that when we use them to make a network request, they return a promise that can either resolve or reject. 

Installing Axios

If we’re using Axios on a node.js environment, we can use one of the following installation methods: 

  1. Install using NPM:

npm install axios

2. Install using Yarn:

yarn add axios

We must then import into our project:
import axios from "axios";If we’re using Axios within a browser, we can use a CDN:
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>You can read all the ways to install Axios here. Now that everything is installed, let’s compare them.

Comparing the features of Fetch and Axios

Let’s start with the syntax.

Syntax

Fetch accepts two arguments. The first argument is the URL for the resource we want to fetch. The second is an optional argument which is an object containing the configuration options for making requests. Thus, the syntax is:

Without the configuration option, the request will default to making a GET request:
fetch(url)With the configuration option, we can define some custom settings for the request which include:

fetch(url, {
  method: 'GET', // other options: POST, PUT, DELETE, etc.
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({}),
})

Axios syntax is similar, but there are many different ways of calling it:



axios(url, {
  // configuration options
})

We can also append the HTTP method like this:



axios.get(url, {
  // configuration options
})

Like the fetch method, we can ignore HTTP methods in axios to default to GET like so: 
axios(url)Likewise, we can define some custom settings for the request using the second argument:

axios(url, {
  method: 'get', // other options: post, put, delete, etc.
  headers: {},
  data: {},
})

We can also write it like this:


axios({
  method: 'get',
  url: url,
  headers: {},
  data: {},
})

Now let's examine the different way Axios and fetch handle responses.

Handling JSON data

In the example below, we perform a GET request to a REST API called JSONPlaceholder to fetch a list of todos items using both fetch and Axios and compare the differences.

Using the Fetch API, our code looks like this:


const url = "https://jsonplaceholder.typicode.com/todos";

fetch(url)
  .then(response => response.json())
  .then(console.log);

The result in our console looks like this:

image-pvtqx

The fetch() returns a promise whose response is handled by the .then() method. At this point, we do not have the JSON data format that we need, so we call the .json() method on the response object. This returns another promise that is resolved with the data in JSON form.So a typical fetch request contains two .then() calls.

However, if we use Axios to perform the same fetch, we have the following code:


const url = "https://jsonplaceholder.typicode.com/todos";

axios.get(url)
.then(response => console.log(response.data));

With Axios, the response data is available as JSON by default. The response data is always available on the data property of the response object.

We can override the default JSON data type by specifying the responseType in the configuration option like so:



axios.get(url, {
  responseType: 'json' // options: 'arraybuffer', 'document', 'blob', 'text', 'stream'
})

Auto stringify

Now let’s try sending data using the JSONPlaceholder API. 

We will need to serialize our data into a JSON string to do this. When we send JavaScript objects to the API using a POST method, Axios automatically stringifies the data.

The following code performs a post request using Axios:


const url = "https://jsonplaceholder.typicode.com/todos";

const todo = {
  title: "A new todo",
  completed: false
} 

axios.post(url, {
  headers: {
    'Content-Type': 'application/json',
  },
  data: todo
})
.then(console.log);

When we make a post request with axios, we assign the data to be sent as the request body to the data property. We can also set the content type header. By default, axios sets Content-Type to application/json.

Let's take a look at the response object:

image-o8msf

The response data is located on the response.data like so:

.then(response => console.log(response.data));

If we use the Fetch API, we have to manually stringify the object using JSON.stringify() and then assign it to the body of our request.

const url = "https://jsonplaceholder.typicode.com/todos";

const todo = {
  title: "A new todo",
  completed: false
};

fetch(url, {
  method: "post",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify(todo)
})
  .then((response) => response.json())
  .then((data) => console.log(data))

We must also explicitly set the Content-Type to application/json with Fetch.

Error handling

Both fetch and axios returna promise that is either resolved or rejected.
When the promise rejects wecan use .catch() to handle the error. How we handle errors with axios is more succinct when compared to the Fetch method.

Starting with the axios, a typical error handling with .catch() looks like so:

const url = "https://jsonplaceholder.typicode.com/todos";

axios.get(url)
  .then((response) => console.log(response.data))
  .catch((err) => {
    console.log(err.message);
  });

Axios’s promise will reject if the status code falls outside of the range of 2xx. We can determine more information about the error by checking whether the err object contains a response or a request property like so:

.catch((err) => {
  // handling error
  if (err.response) {
    // Request made and server responded

    const { status, config } = err.response;

    if (status === 404) {
      console.log(`${config.url} not found`);
    }
    if (status === 500) {
      console.log("Server error");
    }
  } else if (err.request) {
    // Request made but no response from server
    console.log("Error", err.message);
  } else {
    // some other errors
    console.log("Error", err.message);
  }
});

A response property on the error object indicates that the client received an error response with a status code outside of the 2xx range. A request property on the error object indicates that a request was made, but the client did not receive a response. Otherwise, if there is no request or response property, an error occurred in setting up the network request.

Fetch will not reject a promise if we get a 404 error or any other HTTP error. Fetch only rejects a promise when the network fails. So we have to manually handle HTTP errors within .then clauses.

Let's take a look at the following code: 

const url = "https://jsonplaceholder.typicode.com/todos";

fetch(url) 
  .then((response) => {
    if (!response.ok) {
      throw new Error(
        `This is an HTTP error: The status is ${response.status}`
      );
    }
    return response.json();
  })
  .then(console.log)
  .catch(err => {
    console.log(err.message);
  });


In the response block, we are checking if the response’s ok status is false, then we throw a custom error that is handled in the .catch block.

We can take a look at the methods available on the response’s object like so:
.then(console.log)

image-ld51j

The above screenshot is for a successful fetch. In a situation where we hit a wrong URL endpoint, the ok and status property will become false and 404 respectively, we throw an error and so the .catch() clause will display our custom error message.

Response Timeout/ Cancel requests

Let’s see how these HTTP clients handle response timeout for HTTP requests. With Axios, wecan add a timeout property in the configuration object and specify the time in milliseconds before the request terminates.

In  the following snippet, we aim to terminate the request if it takes longer than four seconds and then log an error in the console.

const url = "https://jsonplaceholder.typicode.com/todos";

axios.get(url, {
  timeout: 4000, // default is `0` (no timeout)
})
  .then((response) => console.log(response.data))
  .catch((err) => {
    console.log(err.message);
  });

To cancel requests with Fetch, we can use the AbortController interface. See the usage below:

const url = "https://jsonplaceholder.typicode.com/todos";

const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 4000);

fetch(url, {
  signal: signal
})
  .then((response) => response.json())
  .then(console.log)
  .catch((err) => {
    console.error(err.message);
  });

We started by creating a controller object and gained access to the signal object and the abort() method. We then passed the signal object to fetch() via the configuration option. With this, the fetch request will terminate whenever the abort method is called. As we can see, with the help of setTimeout function, the operation terminates if the server does not respond in four seconds.

Performance

Since Fetch and axios are both promise-based, they should not cause any performance issues. However, we can still measure their performance using measurethat.net.

After successive testing using the online tool, we have the following result:

image-gvoek

The graph:

image-2bg33

As seen above, the native Fetch is slightly faster than axios. This is insignificant as both clients are asynchronous.

Browser support

Axios and Fetch are widely supported among modern browsers. For older environments like IE 11 that doesn’t support ES6 Promises, we have to use a polyfill. Also for Fetch, specifically, we will add another polyfill to support implementations in older browsers.

Conclusion

In this guide, we discussed Fetch and axios and practically compare them using real-world scenarios. In the end, what you select in your project depends on your personal preference and ease of use.

Meticulous

Meticulous is a tool to record and replay user sessions. A user session is a sequence of interactions on a web application, like clicking on the sign-up button, typing in an email address and clicking submit. Meticulous can be used to replay these user sessions on new code. This allows you to find out information about the runtime execution of that code (like visual diffs, new exceptions), and catch regressions, prior to that code being released. You can do this without causing side effects or hitting your backend. You can read more about this at our docs here.

Authored by Ibas Majid

Read more