Out of the box, Node.js offers the http library for making requests, but it isn't particularly user friendly and requires some customization before it can be easily used. As a result, a large ecosystem of third-party libraries have emerged to make AJAX and HTTP requests easier.

Some offer cross-platform (browser and Node.js) support, while others focus on bundle size or developer experience. With some many options, how do you choose?

To help make your decisions on picking a library a little easier we've assembled a list of the top Node.js HTTP request modules, along with implementation details and feature rundowns.

Axios

Promise based HTTP client for the browser and node.js

The long-time default among many Node.js and javascript developers, Axios has seen renewed development recently after some stagnation. Axios offers a promise-based API that plays nicely with async/await, and offers helpers for the main HTTP methods.

Performing a GET in Axios looks like:

axios.get("https://bearer.sh").then(response => {
  console.log(response)
})

Performing a POST in Axios looks like:

const data = {
  title: "Bearer Rocks"
}

axios.post("https://bearer.sh", data).then(response => {
  console.log(response)
})

One nice feature is it's ability to create configured versions of the client with defaults. For example:


const myClient = axios.create({
  baseURL: "https://api.example.com",
  headers: : {
    Authorization: "Bearer EXAMPLE_CODE"
  }
})

myClient.get('/test')
  .then(response => console.log(response))

This allows you to set baseline configurations for a variety of external calls without the need for your own abstractions.

Axios also offers features like timeout configuration, request cancelling, automatic JSON transforms, and more. With a little work, you can also add retry support.

Pros

  • Ability to create reusable clients.
  • Shared syntax between client and server.
  • Large user base of battle-tested applications.

Cons

  • Some may consider it's package size to be bloated.
  • Still pre-1.0 after 5 years.

superagent

Small progressive client-side HTTP request library, and Node.js module with the same API, supporting many high-level HTTP client features.

Like Axios, superagent is another promise-based request library. It also offers helpers for common use cases like HTTP methods and header setting.

A GET request in superagent looks like this:

superagent.get("https://bearer.sh").then(response => {
  console.log(response)
})

A POST looks like this:

const data = {
  title: "Bearer Rocks"
}

superagent
  .post("https://bearer.sh")
  .send(data)
  .then(response => {
    console.log(response)
  })

superagent can also be used with callbacks by adding .end((err, res) => { }) to the end of the chain.

Its small size when used in the browser (6 KB) is one reason many developers appreciate it. It also offers a variety of add-on features like prefixes, caching, and serialization through its plugin ecosystem.

Pros

Cons

  • Somewhat opinionated API.
  • Callback style can make documentation confusing for new or new-to-javascript developers.

Request

⚠️ As of Feb 11th 2020, Request has been deprecated. We keep listing it, but you should probably think twice before using it in your project.

Request is designed to be the simplest way possible to make http calls.

One of the early libraries for the Node.js ecosystem, Request is dated by today's standards. Promise and async/await support exist only in sibling packages like request-promise and request-promise-native. However, it's history and long life make it one of the most depended on packages on npm.

A GET request in request looks like this:

request.get("https://bearer.sh").on("response", response => {
  console.log(response)
})

A POST request in request looks like this:

const data = {
  title: "Bearer Rocks"
}

request
  .post({ url: "https://bearer.sh", json: data })
  .on("response", response => {
    console.log(response)
  })

We cannot deny the staying power of request, though many modern libraries are considerably more user friendly and continue to be maintained (while request has entered maintenance mode).

Pros

  • Battle-tested usage: 15 million+ downloads per week.
  • Adjacent libraries to handle different implementations

Cons

  • Not a "modern" as other libraries.
  • No longer actively developed.

Got

Human-friendly and powerful HTTP request library for Node.js

Got, by Sindre Sorhus, is a library that aims to be easier to use than others in the space. It supports streams and promises, with async/await being it's preferred use case. Got also brings features like retries on failure, request cancellation, and progress events.

A GET request in Got looks like this:

try {
  const response = await got("https://bearer.sh")
  console.log(response.body)
} catch (err) {
  console.log(err.response.body)
}

A POST in Got looks like this:

try {
  const response = await got
    .post("https://bearer.sh", {
      json: {
        title: "Bearer Rocks!"
      }
    })
    .json()

  console.log(response.body)
} catch (err) {
  console.log(err.response.body)
}

Pros

  • High emphasis on developer experience
  • Familiar conventions
  • Sibling libraries ky for client-side applications, and ky-universal for isomorphic apps.

Cons

  • Documentation assumes a higher level of knowledge from the reader.
  • While many conventions are familiar, the opinionated syntax can sometimes conflict with what is expected.

Fetch / Unfetch / Isomorphic unfetch / node-fetch

We can't go without mentioning one of the many Node.js implementations of fetch. Fetch is the modern implementation of XHR in the browser. A variety of Node.js implementations bring the same API surface from the browser to Node.js. This syntax parody makes it a great choice for isomorphic applications, but also for teams where engineers write javascript on both the client and server.

The fetch API requires a little more work to process requests and handle errors compared to most non-native libraries.

A GET request in fetch looks like this:

fetch("https://bearer.sh")
  .then(response => {
    if (response.ok) {
      return response.json()
    }
    throw new Error(response)
  })
  .then(response => {
    console.log(response)
  })
  .catch(console.error)

A POST request in fetch looks like this:

fetch("https://bearer.sh", {
  method: "POST",
  body: JSON.stringify({ title: "Bearer Rocks!" })
})
  .then(response => {
    //...
  })
  .catch(console.error)

Pros

  • Easier to recognize for front end developers.
  • Transition code from client to isomorphic without much work

Cons

  • Less intuitive than third-party libraries
  • Implementation is tightly linked to what the browser supports.

What library is best for you?

Fortunately, there is no shortage of variety when it comes to Node.js packages. In the HTTP client space, the shared syntaxes make for easier transitions between them. We recommend choosing a library that offers syntax parity or support for both client and server, as well as an easy way to configure shared settings across requests.

Did we miss your favorite library in this post? Let us know and connect with us @BearerSH. Consuming third-party APIs and looking for a solution to make them more reliable? Give Bearer a try today.