node.jsrequest-promise

request-promise loop, how to include request data sent with response?


I am trying to use request-promise in a loop and then send a response back to the client with all of the responses. The below code works, however I want to also include the request data with each response so that the request ID can be correlated with the result. Is there a built in way to do this:

promiseLoop: function (req, res) {
    var ps = [];
    for (var i = 0; i < 3; i++) {
        // var read_match_details = {
        //     uri: 'https://postman-echo.com/get?foo1=bar1&foo2=bar2',
        //     json: true // Automatically parses the JSON string in the response 
        // };
        var session = this.sessionInit(req, res);
        if (this.isValidRequest(session)) {
            var assertion = session.assertions[i];
            const options = {
                method: 'POST',
                uri: mConfig.serviceURL,
                body: assertion,
                headers: {
                    'User-Agent': 'aggregator-service'
                },
                json: true
            }
            logger.trace(options);
            ps.push(httpClient(options));
        }

    }

    Promise.all(ps)
        .then((results) => {
            console.log(results); // Result of all resolve as an array
            res.status(200);
            res.send(results);
            res.end();
        }).catch(err => console.log(err));  // First rejected promise
}

Solution

  • Assuming httpClient() is request-promise that you refer to and the assertion value is what you're trying to pass through with this result, you could change this:

    ps.push(httpClient(options));
    

    to this:

    ps.push(httpClient(options).then(result => {
        return {id: assertion, result};
    }));
    

    Then, your promise would resolve to that object which contains both the result and the id and you could access each in the final array of results.


    Your code doesn't show what the current result is. If it's already an object, you could also just add the id property to that object if you'd rather. This is up to you exactly how you put that final result together.

    ps.push(httpClient(options).then(result => {
        // add id into final result
        result.id = assertion;
        return result;
    }));
    

    Anyway, the general idea is that before putting the promise in the array, you use a .then() handler to slightly modify the returned result, adding in whatever data you want to add and then returning that new modified result so it becomes the resolved value of the promise chain.


    To make sure you process all responses, even if some have an error, you can use the newer [Promise.allSettled()][1] instead of Promise.all() and then look through which responses succeeded or failed in processing the results. Or, you can catch any errors, turn them into resolved promises, but give them a sential value (often null) that you can see in processing the final results:

    ps.push(httpClient(options).then(result => {
        // add id into final result
        result.id = assertion;
        return result;
    }).catch(err => {
        console.log(err);
        // got an error, but don't want Promise.all() to stop
        // so turn the rejected promise into a resolved promise
        // that resolves to an object with an error in it
        // Processing code can look for an `.err` property.
        return {err: err};
    }));
    

    Then, later in your processing code:

    Promise.all(ps)
        .then((results) => {
            console.log(results); // Result of all resolve as an array
    
            // filter out error responses
            let successResults = results.filter(item => !item.err);
            res.send(successResults );
        }).catch(err => console.log(err));  // First rejected promise