A Comparison of JavaScript HTTP Libraries for the Browser

Ludovico Fischer
Ludovico Fischer
Share

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.

Frequently Asked Questions about JavaScript HTTP Libraries

What are the key differences between the JavaScript HTTP libraries?

JavaScript HTTP libraries vary in terms of their features, ease of use, and performance. For instance, Axios is known for its promise-based HTTP client for both browser and node.js, while Fetch API is a modern, promise-based replacement of XMLHttpRequest. SuperAgent is light-weight, flexible and readable, and Request is simple and easy to use but has been deprecated. It’s important to choose a library that suits your specific needs and project requirements.

Why should I use JavaScript HTTP libraries instead of traditional AJAX?

JavaScript HTTP libraries offer several advantages over traditional AJAX. They are more powerful, flexible, and provide a better API. They can handle requests and responses in a more sophisticated way, including the ability to send asynchronous requests, handle different data formats, and catch errors more efficiently.

How do I choose the right JavaScript HTTP library for my project?

The choice of a JavaScript HTTP library depends on your project’s requirements. Consider factors like the library’s features, ease of use, community support, and performance. Also, consider the size of the library if you’re working on a performance-sensitive web application.

Can I use multiple JavaScript HTTP libraries in a single project?

Yes, you can use multiple JavaScript HTTP libraries in a single project. However, it’s generally recommended to stick to one library for consistency and to avoid unnecessary complexity.

How do I handle errors with JavaScript HTTP libraries?

Error handling with JavaScript HTTP libraries is typically done using promises or async/await. These libraries often provide methods for catching errors and handling them appropriately.

Are JavaScript HTTP libraries compatible with all browsers?

Most JavaScript HTTP libraries are compatible with modern browsers. However, some libraries may not support older browsers. Always check the library’s documentation for browser compatibility information.

How do I make a POST request with a JavaScript HTTP library?

Making a POST request with a JavaScript HTTP library typically involves calling a method (like axios.post or fetch) with the URL and the data to be sent as arguments.

What is the performance impact of using JavaScript HTTP libraries?

The performance impact of using JavaScript HTTP libraries is generally minimal. However, some libraries are larger in size and may impact the load time of your web application. Always consider the performance implications of the library you choose.

Can I use JavaScript HTTP libraries with frameworks like React or Angular?

Yes, JavaScript HTTP libraries can be used with JavaScript frameworks like React or Angular. They can be used to make HTTP requests in these frameworks.

Are there any security concerns with using JavaScript HTTP libraries?

As with any code that interacts with the internet, there are potential security concerns. However, most well-maintained JavaScript HTTP libraries have measures in place to mitigate common security risks. Always use libraries from trusted sources and keep them updated to the latest version.