How to properly check and log http status code using promises and node.js?

17,406

Solution 1

You mixed up the first two lines. The new Promise wrapper that gets you the value to return needs to be on the outside, and the http.get call should be inside its executor callback. Also you don't really need that timeout:

function getStatusCodeResult(website) {
    return new Promise((resolve, reject) => {
        http.get(website, (res) => {
            let statusCode = res.statusCode,
                error = statusCode >= 400 && statusCode <= 500 ? `error: ${website}`: null
            if (error) {
                reject(error)
            } else if (statusCode >= 200 && statusCode <= 300) {
                resolve(`Success: ${website}`)
            }
        })
    })
}

Solution 2

Using util.promisify(), you can convert http.get() into a promise-based asynchronous method, but first there's some preparation to do since it does not follow the convention of callback(error, response) { ... }:

const http = require('http')
const { promisify } = require('util')

// define a custom promisified version of `http.get()`
http.get[promisify.custom] = (options) => new Promise(resolve => {
  http.get(options, resolve)
});

// convert callback to promise
const httpGet = promisify(http.get)

async function getStatusCodeResult(website) {
  const res = await httpGet(website)
  const status = res.statusCode
  const message = `${http.STATUS_CODES[status]}: ${website}`

  if (status >= 400) {
    throw message
  } else {
    return message
  }
}

In addition, you can use http.STATUS_CODES to get the the appropriate message for each possible statusCode rather than returning a vague Error or Success.

Share:
17,406
Squanchy
Author by

Squanchy

Updated on June 07, 2022

Comments

  • Squanchy
    Squanchy over 1 year

    I am new to JavaScript and very new to node.js framework, just started using it a few days ago. My apologies if my code is nonsensical, the whole idea of promises and callbacks is still sinking in. That being said my question is the following I am trying to figure out if certain request to websites are successful or cause an error based on the range of their status code response. I am working with an array of websites and what I've done so far is below, I do however get a TypeError: Cannot read property 'then' of undefined on my local machine with node.js installed and can't figure out why.

    const sample = [
        'http://www.google.com/',
        'http://www.spotify.com/us/',
        'http://twitter.com/',
        'http://google.com/nothing'
    ]
    
    const http = require('http')
    
    const getStatusCodeResult = (website) => {
    
        http.get(website, (res) => {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    let statusCode = res.statusCode
                    error = statusCode >= 400 && statusCode <= 500 ? `error: ${website}`: null
                    if (error) {
                        reject(error)
                        
                    } else if (statusCode >= 200 && statusCode <= 300) {
                        resolve(`Success: ${website}`)
                    }
                }, 0)
            })
        })
    }
    // LOOP PROMISES
    const getAllStatusCodeResult = (websites) => {
        websites.forEach((website) => {
            getStatusCodeResult(website)
                .then((result) => {
                    console.log(result)
                })
                .catch(error => {
                    console.log('error', error)
                })
        })
    }
    getAllStatusCodeResult(sample)

    Ideally I would want the result to be printed as the example below, but for now I am just using console.log to figure out if the code even works.

       // Example Printout
       {
          success: ['https://www.google.com/', 'https://www.spotify.com/us/', 
          'https://twitter.com /' ],
          error: [''http://google.com/nothing']
       } 
    
  • Squanchy
    Squanchy over 5 years
    Awesome, can you please explain why the promise wraps the http.get is that the way its always used you wrap the referencing environment whit the promise? Also, do you by any chance know why I am only getting error error: http://google.com/nothing Success: http://www.google.com/ and not the rest of sites.
  • Bergi
    Bergi over 5 years
    Yes, you always wrap the asynchronous function within the new Promise constructor. How you resolve and reject is usually different though
  • Bergi
    Bergi over 5 years
    If you're not getting anything from the other promises, it's likely that the response were neither 400<=status<500 nor 200<=status<300. If there's a redirect or a server error, you never settle the promise (which is a bad thing!), so neither of your callbacks would run.
  • Patrick Roberts
    Patrick Roberts over 5 years
    @Bergi would it be beneficial for me to add a solution using util.promisify() or should I not bother?
  • Squanchy
    Squanchy over 5 years
    @Bergi do you think I should post a different question, about not logging all the sites in the sample array only logging http://google.com/nothing and http://www.google.com/?
  • Bergi
    Bergi over 5 years
    @PatrickRoberts Please go for it. (Also I didn't check the http.get signature in the docs, it's kinda suspicious that there's no error parameter)
  • Bergi
    Bergi over 5 years
    I wonder, shouldn't http.get[promisify.custom] be native in node already?
  • Patrick Roberts
    Patrick Roberts over 5 years
    @Bergi I checked, it's not defined.