0

I am trying to retrieve data at multiple API endpoints simultaneously and aggregate the result to be sent back to the client as one response.

However, when trying to return data from async.parallel, I get an undefined result. I think this is because the result code is being executed before it is returned, but I am not sure.

I would like to pass an array of ids to the server, get their metadata, combine their metadata into one object, and send a single object back to the client.

function doSomething() {
  for(let i=0; i<req.map.length; i++) {
    stack[i] = (callback) => {
      let data = subroute(req, res, req.map[i])
      callback(null, data)
    }
  }

  async.parallel(stack, (err, result) => {
    if(err) {
      // Handle error
    } else {
      console.log(result) // Logs undefined
      res.json([result])  // Would like to send this result back to the client
    }
  })
}

function subroute(req, res, num) {
  request({
    url: 'https://example.com/api/endpoint/' + num
  },
  (error, response, body) => {
    if(error) {
      res.json({ "error": error })
    } else {
      let i = {
        name: body.name,
        age: body.age,
      }
      return i 
    }
  })
}

How can I accumulate the results of many API endpoint responses on the server and send the back as one response to the client?

Matthew
  • 1,461
  • 3
  • 23
  • 49
  • I think too that the return is not catched up. Add a callback argument to `subroute` and call it in `request`'s callback. Pass a function to `subroute` in `task`, which will call the `callback(null, data)` there – pergy Aug 08 '18 at 16:16
  • You should pass the callback to subroute function and trigger it from there once you are done. – gargsms Aug 08 '18 at 16:16

1 Answers1

1

Change

let data = subroute(req, res, req.map[i])
callback(null, data)

to

subroute(req, res, req.map[i], callback)

Subsequently, change subroute to receive the callback and return the return

function subroute(req, res, num, cb) {
 request({
    url: 'https://example.com/api/endpoint/' + num
  },
  (error, response, body) => {
    if(error) {
      res.json({ "error": error })
      cb(<whatever error you would want to pass>);
    } else {
      let i = {
        name: body.name,
        age: body.age,
      }
      cb(null, i);
    }
  })
}

By doing let data = subroute(req, res, req.map[i]) you are assigning the result of subroute call to data. Notice subroute does not have a return statement in the function body so data will always be undefined.

gargsms
  • 779
  • 8
  • 27
  • Could you please elaborate on: Notice `subroute` does not have a `return` statement in the function body so data will always be `undefined`? – Matthew Aug 08 '18 at 17:07
  • It is implicitly returning `undefined`. A function body without a return statement can be seen as having `return undefined` as the last statement. See: https://stackoverflow.com/questions/17337064/does-every-javascript-function-have-to-return-a-value – gargsms Aug 08 '18 at 17:08
  • So, if I'm understanding correctly, each parameter that is passed into a function has its own return value? – Matthew Aug 08 '18 at 17:12
  • No. A function can only return once. If there is no return statement in a function, it is implied that it returns the default value, which happens to be `undefined` in case of JavaScript. For the same case in python, it returns `None`. – gargsms Aug 08 '18 at 17:16
  • OK. So by `body`, you were referring to the function body, and not the `body` parameter that is being passed into the if/else block? – Matthew Aug 08 '18 at 17:20
  • Yes, that's what I wrote as well. – gargsms Aug 08 '18 at 17:21
  • OK. Thank you for clarification and help on this! – Matthew Aug 08 '18 at 17:22