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.

4
  • Which request library are you using? Commented Aug 25, 2019 at 15:31
  • Can you share the key here? Need to test an approach. You can regenerate it later. Commented Aug 25, 2019 at 15:38
  • Nodejs request is what I am using; this one: npmjs.com/package/request Commented Aug 25, 2019 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. Commented Aug 25, 2019 at 15:42

3 Answers 3

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
            })
        })


    })
})

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you very much. It worked very well as I expected.
I think that request-promise and async/await is far more better approach than a accepted answer
I think request-promise does the same thing
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 })
}

6 Comments

I think requrl line is missing, though I understood it. I will execute and tell you the output.
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.
I updated the answer, added async to data.map callback function, then it will work
@lonesomeday And yes request.get returns promise, see at the documentation
@onuriltan No, it won't. See my answer to this question, which is the exact same issue.
|
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)

2 Comments

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?
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: developer.mozilla.org/nl/docs/Web/JavaScript/Reference/…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.