Axios Vs Fetch. Which is better for making HTTP requests ?

Is Axios better than fetch? Let us find out Axios is a promised based HTTP library and Fetch is a native browser API.

· 7 min read
Mary Maina

Mary Maina

I am a frontend engineer passionate about building intuitive user interfaces. Tools: React, Next.JS, TypeScript, React Native, NodeJs

Overview

Data management is a crucial aspect of software development when building applications. Dynamic applications heavily rely on real-time data exchange through a server to store, fetch, and update the data when required. This ensures users have a seamless experience when interacting with such applications.

In this article, we will compare Axios and fetch and find out how they can be used to perform different tasks. We will look into the ideal use cases to help developers make informed decisions about which data-fetching tool is suitable for their project requirements.

Definition

  • Axios: It is a promise-based HTTP client for the browser and Node.js. It can run in the browser and node.js in the same codebase making it isomorphic. On the server side, it uses the native node.js http module, while on the client it uses XMLHttpRequest. Read more
  • Fetch: Fetch like axios is a promised-based HTTP client. The fetch API provides a global fetch() method that offers an easy and logical way to fetch resources asynchronously across the network. Read more

Comparisons

Basic Syntax

Let's compare the basic syntax of fetch and axios. Here's an example of making a POST request using Axios, including custom headers. You do not have to convert your data into JSON manually.

First, we will install and import Axios into our project. You can install Axios using a package manager like npm or yarn.

You can create an axios instance with custom configurations.

import axios from 'axios';

//create axios instance
const axiosInstance = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com/todos',
  headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json;charset=UTF-8',
    },
})

//the api request
const payload = {
 title: "Introduction to Js",
 body: "This is the documentation.",
 userId: 1,
 completed: false
};

axiosInstance.post('/', payload)
  .then(({ data }) => {
    console.log("POST request successful. Response:", data);
  })
  .catch(error => {
    console.error('Error:', error);
  });

Compare that to fetch which produces similar results.

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

const options = {
  method: "POST",
  headers: {
    Accept: "application/json",
    "Content-Type": "application/json;charset=UTF-8",
  },
  body: JSON.stringify({
    title: "Introduction to Js",
    body: "This is the documentation.",
    userId: 1,
    completed: false
  }),
};

fetch(URL, options)
  .then((response) => response.json())
  .then((data) => {
    console.log("POST request successful. Response:", data);
  });
  • Axios automatically transforms the data returned from the server, but with fetch() you have to parse the data to a JavaScript object.
  • With axios, you can create an axios instance with configurations.

Request and response interceptors

Interceptors are functions that can alter a response and request before they are handled by the application logic.

Axios has a built-in mechanism for interceptors, which allows you to run your code or modify the request and response objects during the promise lifecycle of a request. This feature is particularly powerful for handling tasks like logging, authentication, and error handling.

Request interceptors

  • You can use request interceptors in Axios to automatically append tokens or headers before a request is sent. For example, adding an Authorization header to every request based on the user token for authorization purposes.
axios.interceptors.request.use(config => {
  // Modify config (e.g., headers)
  config.headers['Authorization'] = 'Bearer token';
  return config;
}, error => {

  return Promise.reject(error);
});

Response interceptors

  • Response interceptors are useful for globally handling responses or error codes. Status codes that fall outside the range of 2xx will cause the functions defined in the error block to get triggered. This is where you will implement the logic to refresh the token upon receiving a 401 status code.
axios.interceptors.response.use(response => {
  // Any status code that lie within the range of 2xx cause this function to trigger
  return response;
}, error => {
  //status codes that fall outside the range of 2xx cause this function to trigger

  return Promise.reject(error);
});

Fetch interceptors

Unlike Axios, With fetch, you cannot directly use the interceptor functions. Fetch does not natively support interceptors. However, you can achieve similar functionality by wrapping the Fetch function inside a custom function where you manually handle modifications before and after making a request.

fetch = (originalFetch => {
  return (...arguments) => {
    const result = originalFetch.apply(this, arguments);
      return result.then(console.log('Request was sent'));
  };
})(fetch);

fetch('https://jsonplaceholder.typicode.com/todos')
  .then(response => response.json())
  .then(data => {
    console.log(data) 
  });

The above code snippet shows how to overwrite the global fetch and define the interceptors.

Data transformation

When sending data with Axios, it automatically converts Javascript objects to JSON format before passing the request. Similarly, when receiving data, Axios automatically parses JSON responses into JavaScript objects.

With fetch, data transformation requires manual handling. When posting the data, you need to convert Javascript objects to JSON using JSON.stringify explicitly ().

axios.post(URL, {
  name: 'John',
  age: 30,
  isAdmin:false
})
.then(response => {
  // Automatically parsed JSON response
  console.log(response.data); 
})
.catch(error => {
  console.error(error);
});

With fetch, data transformation requires manual handling. When sending the data you need to explicitly convert JavaScript objects to JSON using JSON.stringify().

Similarly, when receiving the data, you need to manually parse the JSON response in the .json() method.

fetch(URL, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'John',
    age: 30,
    isAdmin: false
  })
})
  // Manually parse JSON response
.then(response => response.json()) 
.then(data => {
  console.log(data);
})
.catch(error => {
  console.error('Error:', error);
});

Request Error handling

Axios automatically handles errors by rejecting responses that fall outside the 2xx range which corresponds to successful responses.

In the existence of an error, the error the information about it is obtained inside the .catch() block. By automatically rejecting unsuccessful responses, Axios provides a predictable error-handling mechanism.

import axios from 'axios'
const URL = "https://jsonplaceholder.typicode.com/todos"
axios(URL)
  .then((response) => {
    console.log("Data received:", response.data);
  })
  .catch(error => {
    if (error.response) {
      console.error('Response Error:', error.response.status);
      console.error('Response Data:', error.response.data);
    } else if (error.request) {
      // The request was made but no response was received
      console.error('Request Error:', error.request);
    } else {
      console.error('Error:', error.message);
    }
    console.error('Axios Error Config:', error.config);
  });

On the other hand, fetch does not automatically respond to errors. Instead, it considers the response as successful even if the server returns an error status code (e.g., 400 Bad Request).

To handle HTTP errors in Fetch, you have to use a conditional statement within the .then() block to explicitly check the response. ok, value.

If the value is false, it means that the server responded with an error status code

const URL = 'https://jsonplaceholder.typicode.com/todos'
fetch(URL)
  .then(response => {
    if (!response.ok) {
      throw Error(`HTTP error: ${response.status}`);
    }
    return response.json();
  })
  .then(data => {
    console.log('Data received:', data);
  })
  .catch(error => {
    console.error('Error message:', error.message);
  });

Timeout Support

Response timeout refers to the maximum time a client is willing to wait for a response from the server before considering the request as failed due to timeout.

In Axios, you can specify a timeout value in milliseconds in the configuration object passed to the request. The timeout can be defined while creating the axios instance.

Axios will reject the request promise with an error indicating a timeout

occurred if the server does not respond within the specified time duration.

In this example, if the server does not respond within 5000ms Axios with throw an error code set to 'ECONNABORTED' indicating a timeout has occurred.

// Import Axios
import axios from 'axios'

const URL = 'https://jsonplaceholder.typicode.com/todos'
const instance = axios.create({
  baseURL: URL,
  timeout: 5000 // Timeout in milliseconds
});

// Make a GET request using the Axios instance
instance.get('/')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    if (error.code === 'ECONNABORTED') {
      console.error('Request Timeout:', error.message);
    } else {
      console.error('Axios Error:', error);
    }
  });

Fetch, however, does not have an in-built support for response timeouts. Rather you can use the AbortController interface which allows a fetch request to be aborted after a certain period.

const controller = new AbortController();
const signal = controller.signal;

// Abort request after 5 seconds
const timeoutId = setTimeout(() => controller.abort(), 5000); 
const URL = "https://jsonplaceholder.typicode.com/todos"

fetch(URL, { signal })
  .then(response => {
    if (!response.ok) {
      throw new Error('HTTP error, status: ' + response.status);
    }
    return response.json();
  })
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    if (error.name === 'AbortError') {
      console.error('Request Timeout:', error.message);
    } else {
      console.error('Fetch Error:', error);
    }
  }).finally{
   //clear the timeout
     clearTimeout(timeoutId);
  }

After 5 seconds, the setTimeout function invokes controller.abort() to abort the request.

Fetch will throw an error with the name set to 'AbortError' indicating a timeout once the request is aborted.

In conclusion, the choice between Axios and Fetch boils down to the specific requirements of your project and your environment.

Axios is preferably used in complex applications since it simplifies the process of making HTTP requests and has robust features.

Fetch being a native browser API looks ideal for applications where minimizing dependencies is a priority and simplicity is required.

share

Mary Maina

I am a frontend devloper