By Faraz Kelhini Translator: blog.logrocket.com/axios-or-fe…

In my recent post on how to make fancy HTTP requests using Axios like a Pro, I described the various benefits of using the AXIos library. However, keep in mind that Axios is not always the best solution, and in some cases we have a better alternative than Axios.

No doubt some developers prefer AxiOS to the built-in API for its simplicity and ease of use, but many overestimate the need for such a library. Fetch () is a built-in API that perfectly recreates Axios’s main features, with the added advantage of being easy to use in all major browsers.

In this summary, we’ll compare fetch() and Axios to see how they can be used in different scenarios. Hopefully, after reading this article, you’ll know more about both.

Basic grammar

Before diving into the advanced features of Axios, let’s do a comparison between the basic syntax and fetch(). The following code is a POST request where we use Axios to send a custom header to a URL. Since Axios automatically converts the data to JSON format, we don’t need to manually convert it.

// axios
const options = {
  url: 'http://localhost/test.htm'.method: 'POST'.headers: {
    'Accept': 'application/json'.'Content-Type': 'application/json; charset=UTF-8'
  },
  data: {
    a: 10.b: 20}}; axios(options) .then(response= > {
    console.log(response.status);
  });
Copy the code

Now let’s rewrite the above functionality using fetch() and compare

// fetch()
const url = 'http://localhost/test.htm';
const options = {
  method: 'POST'.headers: {
    'Accept': 'application/json'.'Content-Type': 'application/json; charset=UTF-8'
  },
  body: JSON.stringify({
    a: 10.b: 20})}; fetch(url, options) .then(response= > {
    console.log(response.status);
  });
Copy the code

Note:

  • To send data, fetch() uses the body attribute, while Axios uses the data attribute;
  • Data in the fetch() method is stringed;
  • In fetch(), the URL is used as a parameter, while in Axios, the URL is used as a configuration item for Options.

Backward compatibility

One of Axios’s main selling points is its wide range of compatibility, even in older browsers like IE11, it can run without issue. Fetch (), however, is a bit more awkward and only supports Chrome 42+, Firefox 39+, Edge 14+, and Safari 10.1+ (you can see the full compatibility table here).

If backward compatibility is the only reason you decide to use Axios, you don’t need to install an HTTP library, you can use Polyfill (click here) like this to implement similar functionality on web browsers that don’t support FETCH (). Note that before using Fetch Polyfill, you need to install it through the NPM command

npm install whatwg-fetch --save
Copy the code

Then you can use fetch() like this

import 'whatwg-fetch'
window.fetch(...)
Copy the code

Note that on older browsers, you may also need to install a Promise polyfill

Response timeout

There’s another reason developers prefer Axios: it’s easy and quick to configure response timeouts. In Axios, you can use the timeout property in the config object to set the timeout length (milliseconds) for terminating the request as follows:

axios({
  method: 'post'.url: '/login'.timeout: 4000.// 4 seconds timeout
  data: {
    firstName: 'David'.lastName: 'Pollock'
  }
})
.then(response= > {/* handle the response */})
.catch(error= > console.error('timeout exceeded'))
Copy the code

Fetch () can do something similar with an AbortController instance, but not as convenient as Axios…

const controller = new AbortController();
const options = {
  method: 'POST'.signal: controller.signal,
  body: JSON.stringify({
    firstName: 'David'.lastName: 'Pollock'})};const promise = fetch('/login', options);
const timeoutId = setTimeout((a)= > controller.abort(), 4000);

promise
  .then(response= > {/* handle the response */})
  .catch(error= > console.error('timeout exceeded'));
Copy the code

Above we created an AbortController object using the AbortController() constructor, which allows us to delay the termination of the request. Signal is a read-only property of AbortController that provides a way to communicate with or terminate a request. If the service does not respond within 4 seconds, Controller.abort () is called and the request is terminated.

Automatically convert JSON data

As we just said, Axios can automatically string data when we send a request (you can also override the default behavior and define a different conversion mechanism yourself). But when we use fetch(), we have to implement the conversion manually, as follows:

// axios
axios.get('https://api.github.com/orgs/axios')
  .then(response= > {
    console.log(response.data);
  }, error => {
    console.log(error);
  });

// fetch()
fetch('https://api.github.com/orgs/axios')
  .then(response= > response.json())    // Take an extra step
  .then(data= > {
    console.log(data) 
  })
  .catch(error= > console.error(error));
Copy the code

It’s nice to be able to automate converting data formats, of course, but remember that fetch() can also do these things.

HTTP interceptor

Another key feature of Axios is its ability to intercept HTTP requests. HTTP interceptors come in handy when you need to check or modify HTTP requests before an application sends them to a background service (or vice versa, like LLDB, log printing, authentication). With interceptors, you don’t need to write the same code for every HTTP request.

How to declare a request interceptor in Axios

axios.interceptors.request.use(config= > {
  // log a message before any HTTP request is sent
  console.log('Request was sent');

  return config;
});

// sent a GET request
axios.get('https://api.github.com/users/sideshowbarker')
  .then(response= > {
    console.log(response.data);
  });
Copy the code

In the code above, axios. Interceptors. Request. Use () is used to define the HTTP request is sent before running the code.

Fetch () doesn’t provide a way to intercept requests by default, but finding a solution isn’t that hard. You can override the global fetch() method and define your own interceptor, like this:

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

fetch('https://api.github.com/orgs/axios')
  .then(response= > response.json())
  .then(data= > {
    console.log(data) 
  });
Copy the code

Download progress

Progress hints can be very useful when downloading large files, especially if the user has a poor Internet connection. Before JavaScript developers are using XMLHttpRequest. Onprogress callback implementations of progress indication. The FETCH ()API does not have an onProgress event callback. Instead, it provides an instance of ReadableStream via the body property of the response object.

The following example briefly illustrates the progress feedback of an image download using ReadableStream

// original code: https://github.com/AnthumChris/fetch-progress-indicators <div id="progress" src="">progress</div> <img id="img"> <script> 'use strict' const element = document.getElementById('progress'); fetch('https://fetch-progress.anthum.com/30kbps/images/sunrise-baseline.jpg') .then(response => { if (! response.ok) { throw Error(response.status+' '+response.statusText) } // ensure ReadableStream is supported if (! response.body) { throw Error('ReadableStream not yet supported in this browser.') } // store the size of the entity-body, in bytes const contentLength = response.headers.get('content-length'); // ensure contentLength is available if (! contentLength) { throw Error('Content-Length response header unavailable'); } // parse the integer into a base-10 number const total = parseInt(contentLength, 10); let loaded = 0; return new Response( // create and return a readable stream new ReadableStream({ start(controller) { const reader = response.body.getReader(); read(); function read() { reader.read().then(({done, value}) => { if (done) { controller.close(); return; } loaded += value.byteLength; progress({loaded, total}) controller.enqueue(value); read(); }).catch(error => { console.error(error); controller.error(error) }) } } }) ); }) .then(response => // construct a blob from the data response.blob() ) .then(data => { // insert the downloaded image into the page document.getElementById('img').src = URL.createObjectURL(data); }) .catch(error => { console.error(error); }) function progress({loaded, total}) { element.innerHTML = Math.round(loaded/total*100)+'%'; } </script>Copy the code

Implementing Progress hints in Axios is easy, especially when paired with the Axios Progress Bar module. First, you introduce the following styles and JS

<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/rikmms/progress-bar-4-axios/0a3acf92/dist/nprogress.css" />

<script src="https://cdn.rawgit.com/rikmms/progress-bar-4-axios/0a3acf92/dist/index.js"></script>
Copy the code

Then you can use the progress bar like this:

<img id="img">

<script>

loadProgressBar();

const url = 'https://fetch-progress.anthum.com/30kbps/images/sunrise-baseline.jpg';

function downloadFile(url) {
  axios.get(url, {responseType: 'blob'})
    .then(response= > {
      const reader = new window.FileReader();
      reader.readAsDataURL(response.data); 
      reader.onload = (a)= > {
        document.getElementById('img').setAttribute('src', reader.result);
      }
    })
    .catch(error= > {
      console.log(error)
    });
}

downloadFile(url);

</script>
Copy the code

The above code uses the FileReader API to asynchronously read the downloaded image. The readAsDataURL method returns the image’s Base64 format string, which is inserted into the IMG SRC property to display the image.

Make multiple requests simultaneously

When we need to make multiple requests at the same time, Axios provides the axios.all() method. We simply send the array of requests to this method, and then use axios.spread () to assign the attributes of the response array to each variable:

axios.all([
  axios.get('https://api.github.com/users/iliakan'), 
  axios.get('https://api.github.com/users/taylorotwell')
])
.then(axios.spread((obj1, obj2) = > {
  // Both requests are now complete
  console.log(obj1.data.login + ' has ' + obj1.data.public_repos + ' public repos on GitHub');
  console.log(obj2.data.login + ' has ' + obj2.data.public_repos + ' public repos on GitHub');
}));

Copy the code

You can also do this with the built-in promise.all() method, passing all requests to Promise.all() as an array and then using async to process the responses as follows:

Promise.all([
  fetch('https://api.github.com/users/iliakan'),
  fetch('https://api.github.com/users/taylorotwell')
])
.then(async([res1, res2]) => {
  const a = await res1.json();
  const b = await res2.json();
  console.log(a.login + ' has ' + a.public_repos + ' public repos on GitHub');
  console.log(b.login + ' has ' + b.public_repos + ' public repos on GitHub');
})
.catch(error= > {
  console.log(error);
});
Copy the code

conclusion

Axios gives us a lot of easy-to-use apis in a compact code package for most of our HTTP communication scenarios. However, if you’d rather stick with native apis, nothing should stop you! You can implement Axios features yourself!

As described in this article, using the Fetch () method provided by a Web browser perfectly overwrites the main functionality provided by the Axios library. Ultimately, whether you need an HTTP library depends entirely on how comfortable you feel using the built-in API.