0

I am fetching cricket matches and scores from different http requests. The first one fetch match list(with unique ids) and second one fetch scores using unique id. I need the second http request(data.map function) to be completed, then data variable value to be sent(in res.json without using timeout). I know using Promises/Callbacks, but I am confused with code. Currently using setTimeout to wait, but I dont want to use timeout. Please Help.

app.get('/api/matches', (req, res) => {
    let url = `http://cricapi.com/api/matches?apikey=${key}`
    request(url, { json: true }, (err, resp, body) => {
        if (err) return res.json({
            error: 1,
            msg: err,
        })
        let data = body.matches.filter(match => {
            return match.matchStarted
        })

        data.map((element, index) => {
            let requrl = `http://cricapi.com/api/cricketScore?apikey=${key}&unique_id=${element.unique_id}`
            request(requrl, { json: true }, (err, resp, body) => {
                element.score = body.score
                data.push(element)
            })
        })

        setTimeout(()=>{
            res.json({
                error: 0,
                matches: data
            })  
        },2000)
    })
})

Expecting output to be cricket matches with their score, but without timeout function, current output is undefined.

Rishabh
  • 25
  • 7
  • Which request library are you using? – onuriltan Aug 25 '19 at 15:31
  • Can you share the key here? Need to test an approach. You can regenerate it later. – Rohit Kashyap Aug 25 '19 at 15:38
  • Nodejs request is what I am using; this one: https://www.npmjs.com/package/request – Rishabh Aug 25 '19 at 15:39
  • I am sorry, but I am unable to share the key. When this code is executed, score is displayed in webpage, but using timeout function to wait for the data to be updated. But using Promises, the second http request would be executed and data would be updated. But here I am confused how to do it. – Rishabh Aug 25 '19 at 15:42

3 Answers3

1

You should use async/await to wait your requests to finish, so what you can do is, so you need to use request-promise package which supports promises, so you can use async await, see at their documentation here

  1. npm install request-promise
  2. Implement async/await as below
const request = require('request-promise');

app.get('/api/matches', async (req, res) => {
  let url = `http://cricapi.com/api/matches?apikey=${key}`
  let { response, body } = await request({ uri: url, method: 'GET' })
  if (response.statusCode !== 200){
   return res.json({ error: 1, msg: err,})
  } 

  let data = body.matches.filter(match => {
         return match.matchStarted
  })
  await Promise.all(data.map(async (element, index) => {
    let { response, body } = await request({ uri: url, method: 'GET' })
    element.score = body.score
    data.push(element)
  }))
  return res.json({ error: 0, matches: data })
}

onuriltan
  • 3,730
  • 4
  • 25
  • 37
  • I think requrl line is missing, though I understood it. I will execute and tell you the output. – Rishabh Aug 25 '19 at 15:45
  • This won't work, because the `await` is not in an `async` function and is therefore a syntax error. What's more, does the `request.get` return a `Promise`? If not, this won't work for that reason either. – lonesomeday Aug 25 '19 at 15:49
  • I updated the answer, added async to data.map callback function, then it will work – onuriltan Aug 25 '19 at 15:51
  • @lonesomeday And yes request.get returns promise, see at [the documentation](https://www.npmjs.com/package/request#promises--asyncawait) – onuriltan Aug 25 '19 at 15:57
  • @onuriltan No, it won't. [See my answer to this question](https://stackoverflow.com/a/42497383/417562), which is the exact same issue. – lonesomeday Aug 25 '19 at 16:12
  • @lonesomeday I see your point! Then I will update the answer accordingly, thanks – onuriltan Aug 25 '19 at 16:15
1

Try wrapping map inside promise like this.


app.get('/api/matches', (req, res) => {
    let url = `http://cricapi.com/api/matches?apikey=${key}`
    request(url, { json: true }, (err, resp, body) => {
        if (err) return res.json({
            error: 1,
            msg: err,
        })
        let data = body.matches.filter(match => {
            return match.matchStarted
        })

        let newData = data.map((element, index) => {
            return new Promise((resolve, reject) => {
                let requrl = `http://cricapi.com/api/cricketScore?apikey=${key}&unique_id=${element.unique_id}`
                request(requrl, { json: true }, (err, resp, body) => {
                    element.score = body.score
                    resolve(element);
                })
            });

        })


        Promise.all(newData).then(data => {
            res.json({
                error: 0,
                matches: data
            })
        })


    })
})

Aviso
  • 695
  • 4
  • 12
0

Wrap every request in a Promise and chain them.

Psuedo code:

// Promise for match
const getMatch = new Promise((resolve, reject) => {
    // Do request, call resolve (or reject) when completed.
    request(url, resolve);
}); 


// Promise for score
const getScore(id) = new Promise((resolve, reject) => {
    // Do request, call resolve (or reject) when completed.
    request(url, resolve);
}); 

// Chain promises
getMatch()
    .then(match => getScore(match))
    .then(profit => console.log(profit)
    .catch(error => console.warn(error)
Sven van de Scheur
  • 1,809
  • 2
  • 15
  • 31
  • But inside the match list http request, only then I will get unique id, and inside the same is score http request, so making different promises would be dealing with it? – Rishabh Aug 25 '19 at 15:48
  • A promise is nothing more than a wrapper for asynchronous code with the possibility to attach callbacks to it. It my example getScore() will be called with whenever getMatch() returns (passed as argument to it's resolve function). When getScore() complets the result is logged to the console. Putting the other bits and pieces in place is up to you. Please see: https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Global_Objects/Promise – Sven van de Scheur Aug 25 '19 at 17:06