'async / await for Node.js https.get

I'm trying to simplify code with async / await

But have problems making https.get with async / await structure.

I am aware of how to do this with third-party modules but prefer the native node.js https module.

Below code doesn't work for me:

async function get_page() {

    const https = require('https')
    const url = 'https://example.com'

    const util = require('util')
    const https_get = util.promisify(https.get)

    const data = await https_get(url)

    do_awesome_things_with_data(data)
}

This code working fine:

function get_page() {

    const https = require('https')
    const url = 'https://example.com'

    let data = ''

    https.get(url, res => {

        res.on('data', chunk => { data += chunk }) 

        res.on('end', () => {

           do_awesome_things_with_data(data)

        })
    }) 
}


Solution 1:[1]

https.get doesn't return something that can be promisified as the signature of the callback doesn't match (err, value), so you can't await it.

However, you can wrap the https.get call within a Promise, like so, then await when calling get_page

const https = require('https')

async function get_page() {
    const url = 'https://example.com'

    return new Promise((resolve) => {
        https.get(url, res => {

            res.on('data', chunk => { data += chunk }) 

            res.on('end', () => {

               resolve(do_awesome_things_with_data(data));

            })
        }) 
    })
}

// usage

(async () => await get_page())()

Edits

I've updated my answer to include the note of https.get not being able to be promisified and moved the require('https') outside of the function call.

Solution 2:[2]

Instead of promisify, roll your own function, or use a 3rd party library. Promisify cannot wrap what https.get returns.

// generic promise method for https
const requestPromise = ((urlOptions, data) => {
  return new Promise((resolve, reject) => {
    const req = https.request(urlOptions,
      (res) => {
        let body = '';
        res.on('data', (chunk) => (body += chunk.toString()));
        res.on('error', reject);
        res.on('end', () => {
          if (res.statusCode >= 200 && res.statusCode <= 299) {
            resolve({statusCode: res.statusCode, headers: res.headers, body: body});
          } else {
            reject('Request failed. status: ' + res.statusCode + ', body: ' + body);
          }
        });
      });
    req.on('error', reject);
    req.write(data, 'binary');
    req.end();
  });
});

Then call it like this:

async function get_page() {
    const url = 'https://example.com'
    const data = await requestPromise({url, method:'GET'})
    do_awesome_things_with_data(data)
}

Or simply use a library such as axios to return a native promise, and also handle additional boilerplate cases.

Solution 3:[3]

Here is how I did it:

async myFunc = function {
    let url = 'http://your.data/file';
    let promise = new Promise((resolve, reject) => {
        var data = '';
        https.get(url, res => {
            res.on('data', chunk => { data += chunk }) 
            res.on('end', () => {
               resolve(data);
            })
        }) 
    });

    let result = await promise; // wait until the promise resolves
    doStuffWithResult(result);
};

In my case, I was fetching a .json file, so I actually used resolve(JSON.parse(data)) to return cleanely JSON object.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Dan Mantyla