Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)

        })
    }) 
}
like image 789
Systems Rebooter Avatar asked Dec 15 '20 13:12

Systems Rebooter


People also ask

Is https request asynchronous?

XMLHttpRequest supports both synchronous and asynchronous communications.

Can I use async await in NodeJS?

Async functions are available natively in Node and are denoted by the async keyword in their declaration. They always return a promise, even if you don't explicitly write them to do so. Also, the await keyword is only available inside async functions at the moment – it cannot be used in the global scope.

Does NodeJS support fetch?

With version 17.5, Node. js has made experimental support for the Fetch API available. Since then, we no longer need to install a third-party library to create server-side JavaScript code that utilizes the Fetch API.


2 Answers

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.

like image 99
steadweb Avatar answered Oct 29 '22 17:10

steadweb


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.

like image 22
Steven Spungin Avatar answered Oct 29 '22 15:10

Steven Spungin