1

I have been trying to create an api like this where I tried different things like using array methods like map/filter/reduce where either I get pending promises or result returned before execution of api call. So my doubt is -->

  • How do I get total number of drawn matches of all pages ( so I need to add data.total from all pages).
  • How to better understand this behaviour.

async function getNumDraws(year) {
    const goals = [...Array(11).keys()];
    let result = 0;

    console.log(`before loop ${new Date()}`);
    for(let goal of goals){
        console.log(`in loop before await ${new Date()}`);
        await require('https').get(`https://jsonmock.hackerrank.com/api/football_matches?year=${year}&team1goals=${goal}&team2goals=${goal}`,res=>{
            let data="";
            res.on('data', (chunk) => {
                data += chunk;
            });
            // The whole res has been received. Print out the result.
            res.on('end', () => {
                data=JSON.parse(data);
                console.log(result,data.total)
                result= result + data.total;
            });
        })
        console.log(`in loop after await ${new Date()}`);

    }
    console.log(`after loop ${new Date()}`);
    return result;

}
console.log(getNumDraws(2011));
Anoop
  • 11
  • 3
  • To make a bunch of API calls, use `Promise.all()` and pass an array of promises to it. At the end, send back the array using `res.json()`. –  Jul 27 '20 at 13:25

1 Answers1

4

https.get is a callbacked function so await won't work. You should promisify it first like they did in this other SO question;

const https = require("https");                                      // only require this once

const getJSONAsync = url => new Promise((resolve, reject) => {       // define a function getJSONAsync which returns a Promise that wraps the https.get call, getJSONAsync is awaitable
  let req = https.get(url, res => {                                  // make the https.get request
    if(res.statusCode < 200 || res.statusCode >= 300) {              // if the status code is an error one
      return reject(new Error('statusCode=' + res.statusCode));      // reject and skip the rest
    }

    let body = [];                                                   // otherwise accumulate..
    res.on('data', chunk => body.push(chunk));                       // ..the data
    res.on('end', () => {                                            // on end                               
      try {
        body = JSON.parse(Buffer.concat(body).toString());           // try to JSON.parse the data
      } catch(e) {
        reject(e);                                                   // reject if an error occurs
      }
      resolve(body);                                                 // resolve the parsed json object otherwise
    });
  });

  req.on("error", error => reject(error));                           // reject if the request fails too (if something went wrong before the request is sent for example)
});

async function getNumDraws(year) {
  let result = 0;

  for(let goal = 0; goal < 11; goal++) {
    let data = await getJSONAsync(`https://jsonmock.hackerrank.com/api/football_matches?year=${year}&team1goals=${goal}&team2goals=${goal}`);
    result += data.total;
  }

  return result;
}

Note: getJSONAsync is not specific to getNumDraws, you can use it somewhere else if you need it, and since it returns a Promise you can either await it like getNumDraws does or use it with then/catch blocks like so:

getJSONAsync("url")
  .then(data => {
    // data is the parsed json returned by the request
  })
  .catch(error => {
    // the error message if something fails
  })
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73