Axios Request

Happy Father's Day! 👔

In this post I'll continue exploring the world of data fetching in JavaScript. So far we've covered two APIs available in JavaScript and modern browsers, XHR and Fetch. In today's post I'll explore a third party library that has massive adoption across the web, Axios.

In this blog post, I'll once more rebuild the app from the last two blog posts - two buttons, one to GET some data and the other to POST some data, and wrap things up with some very basic error handling. Once more, all credit goes to Academind for this YouTube video that taught me all of this.

Initial app setup

Once again, our index.html file hasn't changed a whole lot. I've changed the text in the <title></title> tags to "Axios Request", and instead of loading xhr.js or fetch.js, I'm loading axios.js.

The biggest change here is that I am now also loading the Axios library file from the CDN link provided on the Axios GitHub repo. If this was a Node / Express / React or some other kind of project of that sort, I would add this dependency through NPM.

In the case of this project, the Axios CDN file goes before my own axios.js file.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Axios Request</title>
    <script src="https://cdn.jsdelivr.net/npm/axios@1.6.7/dist/axios.min.js"></script>
    <script src="./axios.js" defer></script>
  </head>
  <body>
    <section id="control-center">
      <button id="get-btn">GET data</button>
      <button id="post-btn">POST data</button>
    </section>
  </body>
</html>

The start of axios.js is also going to be the same as the start of xhr.js and fetch.js:

// axios.js
const getBtn = document.getElementById('get-btn');
const postBtn = document.getElementById('post-btn');

const getData = () => {};

const postData = () => {};

getBtn.addEventListener('click', getData);
postBtn.addEventListener('click', postData);

The API we're using

I'm still using the API over at reqres.in, which allows us to fetch and send dummy data via Fetch requests and get real responses back. You can use any test API endpoint service that you would like. This one is easy in that you don't need any authentication and you're not receiving or sending any real data. It also lets us keep things consistent with the last two blog posts 🙂.

Fetch a list of users (GET method)

Like before, we'll start by getting a list of users via a GET request in our getData event listener callback function.

// ...in axios.js
const getData = () => {
  // 1. Call the .get() method on axios. This returns a Promise
  axios.get('https://reqres.in/api/users')
    // 2. Consume the Promise returned by axios
    .then(response => {
      console.log(response);
    });
};

In XHR, we had to construct an xhr object, and then construct a Promise. Fetch returned a Promise out of the box. Axios simplifies things even more - we just call the .get() method on axios, pass it the endpoint we want it to fetch, and it returns a Promise that we can then consume. It's a super straightforward API.

You'll also recall that in XHR, we had to convert the response from JSON to a JavaScript object; in Fetch, we had to convert the readable stream to JSON. However, by default Axios gives us a plain JavaScript object back with no further configuration needed.

This is all we need so far to make a simple request. If we reload index.html in the browser, navigate to Dev Tools > Network, and then press the GET data button, we can see that the browser made the request for us.

On the Headers tab in Dev Tools > Network, we can see the headers for the request:

Headers for our network request.

And on the Preview tab in Dev Tools > Network, we can preview the data we fetched:

A list of users, received from our API GET request.

Here is our full axios.js file at the moment:

// axios.js
const getBtn = document.getElementById('get-btn');
const postBtn = document.getElementById('post-btn');

const getData = () => {
  axios.get('https://reqres.in/api/users')
    .then(response => {
      console.log(response);
    });
};

const postData = () => {};

getBtn.addEventListener('click', getData);
postBtn.addEventListener('click', postData);

No refactor?

At this point in both XHR and Fetch, I did a slight refactor to abstract common functionality and configuration between GET and POST methods into a helper/wrapper function. This isn't really needed with Axios, as the Axios library is the abstraction. So let's proceed with the POST method!

Registering a user (POST method)

To GET data, it was a simple matter of calling axios.get(). To POST data it's very similar: we simply call axios.post(). In addition to the endpoint URL argument, axios.post() accepts the object of data that you want to send. We'll update our postData function like so:

// ...in axios.js
const postData = () => {
  axios.post('https://reqres.in/api/register', {
    email: 'eve.holt@reqres.in',
    password: 'pistol',
  })
    .then(response => {
      console.log(response);
    });
};

That's all we need to do here. For XHR and Fetch, we had to set Headers to specify that we were sending JSON to the endpoint, but if we press the POST data button, then go to Network > Headers in Chrome Dev Tools, we'll see that Axios set the Content-Type Header to application/json for us:

The Content-Type Header set to application/json

This is so cool. That said, if you needed to specify your own Headers, you can do so by passing an object of Headers as a third argument to axios.post():

// ...in axios.js
const postData = () => {
  axios.post('https://reqres.in/api/register', {
    email: 'eve.holt@reqres.in',
    password: 'pistol',
  }, {
    'Content-Type': 'application/json',
  })
    .then(response => {
      console.log(response);
    });
};

Here is our axios.js file in full at the moment:

// axios.js
const getBtn = document.getElementById('get-btn');
const postBtn = document.getElementById('post-btn');

const getData = () => {
  axios.get('https://reqres.in/api/users')
    .then(response => {
      console.log(response);
    });
};

const postData = () => {
  axios.post('https://reqres.in/api/register', {
    email: 'eve.holt@reqres.in',
    password: 'pistol',
  })
    .then(response => {
      console.log(response);
    });
};

getBtn.addEventListener('click', getData);
postBtn.addEventListener('click', postData);

Handling errors

The last thing we need to tie this all together is to handle an error case. We'll once again focus on doing so with the POST method.

You'll recall that in XHR and Fetch there was a bit of a song and dance of listening for an error status code, rejecting a Promise, listening for that rejection, and catching the error. We had to listen for an error status code because these two APIs didn't discern the difference between a network error and an error returned as an API response.

In Axios, this problem has been vastly simplified:

// ...in axios.js
const postData = () => {
  axios.post('https://reqres.in/api/register', {
    // error case
    email: 'test@test.com',
    password: 'tester',
  })
    .then(response => {
      console.log(response);
    })
    .catch(err => {
      console.error(err, err.response);
    });
};

We simply tack on a .catch() method, and we can handle the error as we see fit. In this case, I just console.error() the error and the response attached to it. No rejecting the Promise in our code, no checking for status codes, just a clean .catch() method.

Here is our fully finished axios.js:

// axios.js
const getBtn = document.getElementById('get-btn');
const postBtn = document.getElementById('post-btn');

const getData = () => {
  axios.get('https://reqres.in/api/users')
    .then(response => {
      console.log(response);
    })
};

const postData = () => {
  axios.post('https://reqres.in/api/register', {
    // error case:
    email: 'test@test.com',
    password: 'tester',

    // success case:
    // email: 'eve.holt@reqres.in',
    // password: 'pistol',
  })
    .then(response => {
      console.log(response);
    })
    .catch(err => {
      console.error(err, err.response);
    });
};

getBtn.addEventListener('click', getData);
postBtn.addEventListener('click', postData);

Summary

Axios is a third party library for fetching data in web applications. It's largely seen as a major ergonomic improvement over standard browser APIs like XHR or Fetch. In this blog post we wound up with a very small, readable app that performs GET and POST methods similar to the XHR and Fetch applications from the last two blog posts, but with significantly less boilerplate – or at least boilerplate that we wrote and would have to maintain. That boilerplate is built into the Axios library, and it's just on us to be able to read the docs and implement the library properly.

Axios is very powerful, and seen as a production-ready standard part of the developer toolkit. From setting Headers to handling errors, it fits most of the needs for data fetching and working with REST APIs that a developer will need. That said, it's a good exercise to have a basic understanding of how technologies like XHR and Fetch work, since a library like Axios is essentially an abstraction on those fundamental API patterns.

It's worth noting that Axios is a bit of an older library, predating Fetch. It's battle-tested and it offers some features that Fetch and XHR don't have for more advanced data fetching use cases, but in this day and age it might not be the best choice for your project. That said, a lot of legacy projects use Axios, so it's good to be somewhat familiar with it.