5 Ways to Make HTTP Requests in Node.js using Async/Await

March 19, 2020
Written by
Sam Agnew
Twilion

Making HTTP requests is core functionality for modern languages and one of the first things many developers learn when acclimating to new environments. When it comes to Node.js there are a fair amount of solutions to this problem both built into the language and by the community. Let’s take a look at some of the most popular ones.

A few years ago, I wrote a similar post on this topic. But now that async/await functionality is more pervasive and mainstream in JavaScript code, making network requests is more straightforward than ever. On top of that, Request, the previously most popular HTTP library for Node has been deprecated. So it's time for an updated guide!

As in the other post, we’ll be using NASA’s Astronomy Picture of the Day API as the JSON API that we are interacting with in all of these examples because space is the coolest thing ever.

Pizza GIF

Before moving on, make sure you have up to date versions of Node.js and npm installed on your machine.

HTTP – the Standard Library

For the purpose of making comparisons, let's start by taking a look at the default HTTP module without Promises and async/await. With this module, you have the advantage of not relying on any dependencies, but it isn't very developer-friendly compared to other solutions.

The following code will send a GET request to NASA’s API and print out the URL for the astronomy picture of the day as well as an explanation:

const https = require('https');

https.get('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY', (resp) => {
  let data = '';

  // A chunk of data has been received.
  resp.on('data', (chunk) => {
    data += chunk;
  });

  // The whole response has been received. Print out the result.
  resp.on('end', () => {
    console.log(JSON.parse(data).explanation);
  });

}).on("error", (err) => {
  console.log("Error: " + err.message);
});

Much of the http and the https module’s functionality is fairly low-level. You’re required to receive response data in chunks and need to explicitly listen for when all of the data is received. You also need to parse the response data manually. This module also does not support HTTPS by default, so we need to require the https module instead if the API we are using communicates over HTTPS. Although you can't use the async/await feature for the HTTP requests made with this library, you could potentially use asynchronous streams for chunking the data.

It may take a bit more effort to get the data you want, but is a great utility if you don’t want to add dependencies to your codebase or want access to its low level functionality.

Got

Got is a great choice if you want a more lightweight library. It is designed to be human-friendly and is also available to use by default in Twilio Functions.

Install Got with npm:

npm install got@9.6.0

Because Got uses promises, you’ll see that you need much less code to accomplish the same task that we did above, and can also take advantage of the async and await keywords:

const got = require('got');

(async () => {
  try {
    const response = await got('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY', { json: true });
    console.log(response.body.url);
    console.log(response.body.explanation);
  } catch (error) {
    console.log(error.response.body);
  }
})();

This library does not parse JSON by default, so we needed to add { json: true } as an argument when making the request. Got is a fantastic option if you just want an easy to use library that deals with HTTP requests in a sane way.

Axios

Axios is another Promise based HTTP client that works for the browser as well as node.js.

To install Axios from npm, enter the following command in your terminal:

npm install axios@0.19.2

The following code will accomplish the same task of logging the URL and explaining the astronomy picture of the day:

const axios = require('axios');

(async () => {
  try {
    const response = await axios.get('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY')
    console.log(response.data.url);
    console.log(response.data.explanation);
  } catch (error) {
    console.log(error.response.body);
  }
})();

Axios even parses JSON responses by default. Pretty convenient! You can even make multiple concurrent requests with axios.all if you wanted to do something like get the astronomy picture of two different days at once:

const axios = require('axios');

(async () => {
  try {
    const [response1, response2] = await axios.all([
      axios.get('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&date=2020-03-18'),
      axios.get('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&date=2020-03-17')
    ]);
    console.log(response1.data.url);
    console.log(response1.data.explanation);

    console.log(response2.data.url);
    console.log(response2.data.explanation);
  } catch (error) {
    console.log(error.response.body);
  }
})();

SuperAgent

Similarly to Axios, SuperAgent is another popular library primarily used for making asynchronous requests in the browser but works in Node.js as well. Install SuperAgent with the following command:

npm install superagent@5.2.2

What is cool about SuperAgent is that you have other useful functions that you can chain onto requests such as query() to add parameters to the request rather than passing them through as an options object. We’ve been manually adding them in the URL in the previous examples, but notice how SuperAgent gives you a function to do this:

const superagent = require('superagent');

(async () => {
  try {
    const queryArguments = {
      api_key: 'DEMO_KEY',
      date: '2020-03-18'
    }

    const response = await superagent.get('https://api.nasa.gov/planetary/apod').query(queryArguments)
    console.log(response.body.url);
    console.log(response.body.explanation);
  } catch (error) {
    console.log(error.response.body);
  }
})();

Just like with Axios you don’t have to parse the JSON response yourself, which is pretty cool.

node-fetch

node-fetch is a light weight module that brings the browser library window.fetch to Node.js with minimal code.

As with the previous examples, install node-fetch with the following:

npm install node-fetch@2.6.0

Recent versions of this library use promises, so we're able to use async/await syntax with it as well:

const fetch = require('node-fetch');

(async () => {
  try {

    const response = await fetch('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY')
    const json = await response.json()

    console.log(json.url);
    console.log(json.explanation);
  } catch (error) {
    console.log(error.response.body);
  }
})();

This library does have a built in function for converting the response to JSON, but it does not do it automatically in the same way that Axios and SuperAgent do. This is a great library for people who are used to using the Fetch API in the browser.

Final Thoughts

This doesn’t cover all of the solutions, but now you see how the basic functionality works in a few of the most popular HTTP libraries in Node.

Other languages have a similar variety of libraries to tackle this problem. Check out these other tutorials in Swift, Python and Ruby. Also, check out our Node.js Quickstarts for a place to apply your new skills.

What are your favorite ways to send HTTP requests? Feel free to reach out and let me know or ask any questions: