JavaScript
Article
By Ludovico Fischer

A Comparison of JavaScript HTTP Libraries for the Browser

By Ludovico Fischer

Ajax requests are heavily used in modern websites. In addition to the use of the built-in way of performing Ajax requests, using an instance of XMLHttpRequest, many developers employ jQuery’s methods to perform the same task.

In this article, we’ll take a look at two alternative libraries that allow you to achieve the same goal. In particular, I’m going to cover superagent and axios. To compare them, we are going to perform a few requests against a dummy HTTP service.

Introduction to Libraries

An XMLHttpRequest instance can perform either synchronous or asynchronous requests. JavaScript is single-threaded, so synchronous requests block other operations to be executed. For this reason, we never use them in practice. The libraries covered in this article, axios and superagent, always perform asynchronous requests. Since your code keeps running while the browser performs the request in the background, you cannot grab the response right away. You must supply a function to call when the server response is ready, usually called callback, that will handle the response.

To handle this process, axios returns a Promise. Conversely, superagent’s API does not adhere to any standard. So, in regard of this feature, we can say that axios is better than superagent. The advantage is that you can combine a promise returned by axios with that of other libraries or with promises that you create using the built-in JavaScript object. In case you need an overview of promises, you can read this tutorial.

On the other hand, superagent is more well-known and has a small plugin ecosystem around it (for instance, superagent prefix to add a prefix to all URLs).

Axios and superagent are most suitable when you wish to use the basic POST/PUT/GET functionality to communicate with an API. For example, they do not support monitoring upload progress like XMLHttpRequest does in modern browsers. Their main advantage is that you can configure and send a request just by chaining a few function calls.

How to Install the Libraries

XMLHttpRequest requires no installation. All modern browsers, from Internet Explorer 8 onwards, implement XHMLHttpRequest. superagent is distributed as an npm module and as a component module. To install superagent with npm, you need to install it first. npm comes with the standard Node.js or io.js installer, so you should either be good to go if you have already Node.js/io.js installed, or you should install whichever of these you prefer. Next, you need to use a client-side packaging solution like browserify to include superagent in your files. If you don’t have any experience with it, SitePoint has published a tutorial that discusses the features of browserify.

axios is distributed as npm module, an AMD module, and as a plain JavaScript file that exports a global axios object. You can download them all from the axios Githib repository.

Example API

Our example API is an order management service for a bakery. Clients can search for orders by date, by performing a GET request as shown below:

/orders?start=2015-03-23&end=2015-03-24

A client can also create a new order by performing a POST request:

/orders

The data returned by the server in case of a GET request and those sent by the website to create a new order are supplied using the JSON format. For example, if the current date is May the 4th, and a client needs 3 chocolate cakes and 5 lemon cakes to be delivered on March the 10th, you could send a JSON object like the following:

{
  "chocolate": "3",
  "lemon": "5",
  "delivery": "2015-03-10",
  "placed": "2015-03-04"
}

Our goals will be to create a new order and to retrieve orders placed in a particular date range.

Creating a new Order

To create an order, we need to specify:

  1. the request method (POST)
  2. the request URL (/orders)
  3. the request body (our order details in JSON format)
  4. the request body content type (application/json)

Specifying the body content type is a good practice: the server can then determine from the request headers how to parse the body.

We configure a superagent request with a dedicated method for each configuration parameter, then call end() to send the request. The end() function takes a callback as an argument to handle the response. If the first callback argument is truthy, an error occurred. Let’s see an example:

var request = require('superagent');

request.post('/orders/')
  .send({'chocolate': 2, 'placed': '2015-04-26'})
  .type('application/json')
  .accept('json')
  .end(function(err, res) {
    if (err) {
      console.log('Error!');
    } else {
      console.log(res.body);
    }
  });

axios takes the URL as first argument, the request body as a second argument, and all remaining configuration as the third parameter. To handle the response, you can specify two callbacks: one for the success case (I’ll pass it to then) and one for the error case (I’ll pass it to catch). An example of use is shown below:

axios.post(
  '/orders/',
  {
    chocolate: 2,
	placed: '2015-04-26'
  },
  {
    headers:{
      'Content-type': 'application/json',
      'Accept': 'application/json'
    }
  }
)
  .then(function(response) {
    console.log(response.data);
  })
  .catch(function(response) {
    console.log('Error!)
  });

To achieve the same goal using XMLHttpRequest, we configure the HTTP method and the URL in the open() function. Then, we attach a response callback to the onload handler and call send to send the request. An example of use is shown below:

var xhr = new XMLHttpRequest();

// The last parameter must be set to true to make an asynchronous request
xhr.open('POST', '/orders/', true);

xhr.setRequestHeader('Content-type', 'application/json');
xhr.setRequestHeader('Accept', 'application/json');
xhr.onload = function() {
  if (xhr.status >= 200 && xhr.status < 300) {
    console.log(xhr.response);
  } else {
    console.log('Error !');
  }
};
xhr.send();

The browser attaches the response data to the XMLHttpRequest object itself. To know whether an error occurred, we have to analyze the response status and manage it in the way we prefer. In this case, I’m logging the response returned in case of a success status (from 200 to 299); the string 'Error !' otherwise.

Retrieving Orders Based on a Date Range

To retrieve the orders placed in a date range, we’ll set a start and an end query parameters. The superagent query() function takes an object that contains the query parameters and their values:

request.get('/orders')
  .query({start: '2015-04-22', end: '2015-04-29'})
  .accept('json')
  .end(function(err, res) {
    if (err) {
      /* Handle error */
    }  else {
      /* Handle response */
	}
});

axios uses the params key in the configuration object:

axios.get(
  '/orders',
  {
      headers: {
        'Accept': 'application/json'
      },
      params: {
        start: '2015-04-22',
		end: '2015-04-29'
      }
  }
);

Query strings should not contain certain characters, especially &, = and ?. Both axios and superagent take care to escape the query parameters for you.

With XMLHttpRequest, you need to escape the components manually using the built-in encodeURIComponent() function on key-value pair of the query string. Below you can find an example of how you can do that, even if it’s superfluous for this particular case:

var xhr = new XMLHttpRequest();
xhr.open('GET', '/orders?start=' +
		encodeURIComponent('2015-04-22') + '&end=' +
		encodeURIComponent('2015-04-29'), true);

Recommendations

Although axios uses promises, the code looks almost identical to superagent. With superagent you set the content type with a dedicated method, but with axios you need to be careful to avoid typos in the header name.

superagent and axios automatically deserialize the request body based on the content type. You can achieve the same goal by setting the responseType property on the XMLHttpRequest instance. They also handle all non-200 responses as errors while XMLHttpRequest offers more flexibility by allowing you to manage the status code and then act accordingly.

Both superagent and axios work also on the server. However, superagent has the most pleasant API in my opinion. But if you want promises, axios is your best bet. As a final note, if you can handle browser differences on your own or just target modern browsers, XMLHttpRequest is fine.

Conclusion

In this article, we have seen how to communicate with a simple REST API using raw XMLHttpRequest, axios, and superagent. The three solutions offer equivalent functionality but with their own peculiarities. If you work with modern browsers, you can rely on XMLHttpRequest. superagent and axios are convenient if you wish to avoid dealing with older versions of Internet Explorer and use the same API on the server.

In case you want to play with the code showed in this article, you can access the GitHub repository I created.

  • gregor7777

    Promise link is broken, 4th paragraph.

    • James Hibbard

      Fixed now. Thanks for pointing it out.

  • Luke Page

    You should check out the fetch polyfill, I think using a polyfill has significant advantages over a custom api.

    • Ludovico FIscher

      We’ve considered talking about fetch, but decided it deserves its own article.

      • Libor Nenadál

        It would be good to have it included…

  • gskema

    Do these libs use XMLHttpRequest internally in browsers?

    • Marlon Bernardes

      Yes, both libraries use XMLHttpRequest (or ActiveXObject for those who use an old IE)

  • Github repo link in the conclusion is broken.

    • Aurelio De Rosa

      It’s working now :)

Recommended
Sponsors
Get the latest in JavaScript, once a week, for free.