0

I'm chaining Q promises:

Q(initialCall).then(someOtherCallThatUsesResultsFromPreviousResults)

A call usually means a promisified node.js http.get call to an external REST api. The path is constructed using information from previous call. At the same time I want to pipe the information from previous call as well. The final result from the chain should be data from both calls merged into one object. Right now the passing of the information is done explicitly via an additional parameter - object. Any way that would not require explicitly passing the extra parameter?

function jsonRequest(pathThatIsContructedBasedOnPreviousResults, object:any) {
  var deferer = Q.defer();
    var options = capsuleOptions;
    options.path = path;

    https.get(options, function (response) {
      response.on('data', function (d) {
        var parsedJson = JSON.parse(d);
        deferer.resolve({data: parsedJson, object: object});
      })}).on('error', function(e) {deferer.reject(e);});

    return deferer.promise;
}

Example:

function getUserDetailsByEmail(email) {
    var userByEmailRequestPath = '/api/party?email=' + email;
    return jsonRequest(userByEmailRequestPath, email);
}

UserByEmail endpoint doesn't return email as part of response JSON and I still want to include email in the return value.

sumek
  • 26,495
  • 13
  • 56
  • 75

2 Answers2

0

Your example is hard to follow. But for what I understood you want to receive inputs from two sources. You can wrap your call in another function that receives the external param. I assume you are looking for something like this:

function getJsonRequestExecutor( externalObject ) {
   return function( pathThatIsContructedBasedOnPreviousResults ) {
       ...
   };
}

Then you can call it as:

Q(initialCall)
   .then( getJsonRequestExecutor( email ) );
fmsf
  • 36,317
  • 49
  • 147
  • 195
0

If I understand correctly, you want getUserDetailsByEmail() to return a promise that makes email and path available as well as data returned in an https response.

This can probably be done in several different ways; I can think of two :

1. "Pre-compose" an object in getUserDetailsByEmail(), augment with data in jsonRequest(), and return it promise-wrapped

function jsonRequest(obj) {
    var dfrd = Q.defer(),
    var options = _.extend({}, capsuleOptions, {
        'path': obj.path
    });
    https.get(options, function (response) {
        response.on('data', function (d) {
            obj.data = JSON.parse(d);
            dfrd.resolve(obj);
        });
    }).on('error', function(e) {
        dfrd.reject(e);
    });
    return dfrd.promise;
}

function getUserDetailsByEmail(email) {
    return jsonRequest({
        email: email,
        path: '/api/party?email=' + email
    });
}

2. "Post-compose" an object in getUserDetailsByEmail(), after obtaining asynchronous data from jsonRequest()

function jsonRequest(path) {
    var dfrd = Q.defer();
    var options = _.extend({}, capsuleOptions, {
        'path': obj.path
    });
    https.get(options, function (response) {
        response.on('data', function (d) {
            dfrd.resolve(JSON.parse(d));
        });
    }).on('error', function(e) {
        dfrd.reject(e);
    });
    return dfrd.promise;
}

function getUserDetailsByEmail(email) {
    var path = '/api/party?email=' + email;
    return jsonRequest(path).then(function(data) {
        return {
            email: email,
            path: path,
            data: data
        };
    });
}

In both versions :

  • you will see that underscore's _.extend() is used to prevent pollution of capsuleOptions. This is not germane to the solutions, just good practice.
  • getUserDetailsByEmail() returns a promise of a js plain object with properties .email, .path and .data.

Which of the two versions you choose (or something completely different) may be determined by the behaviour required of any other calls to jsonRequest(). In this regard, you will probably find that version 2 is the more "natural".

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44