7

I am trying to create a dictionary object of the response json's using postman's pm api sendRequest.

Wrote a recursive function to get all the responses but the problem is the response dictionary object population happens way before even the response comes back.

Is there any way to wait the dictionary population before each of the respective response is received so as to capture the response within the dictionary object ?

var respDictionary  = {};

getResponses (listOfUrls);

console.log("respDictionary: ");
console.log(respDictionary);

function getResponses(urlList) {

    if (typeof urlList === 'string') {
        urlList = urlList.split(' ');
    }
    _url = urlList[0];

    var call = {
        url: _url ,
        method: 'GET',
        header: {
            "Authorization": `Bearer ${token}`,
            "Content-Type": "application/json"
        }
    };
    urlList.splice(0, 1);

    pm.sendRequest(
        call,
        function (err, res) {
        if (err) {
            console.log(err);
        } else {
            if (urlList.length === 0) {
                return;
            }
            try {
                respDictionary[_url] = res.json();
            } catch (e) {
                console.log(err);
            }
            getResponses(urlList);
        }
    });
    console.log(respDictionary);
}

Output is:

respDictionary:
Object:{}
//further, pm request responses are listed
1
  • 1
    I updated my answer, in your code the next url would be opened after the previous would finish (serial). My code would open all urls at once. With large amounts of url's it's better to throttle the amount of open connections so I added a throttle.
    – HMR
    Commented Nov 21, 2017 at 10:09

2 Answers 2

3

You do not understand JavaScript asynchrounous handling. Maybe the following will help:

Your code will work if you use promises:

function getResponses(urlList) {

  if (typeof urlList === 'string') {
    urlList = urlList.split(' ');
  }
  return Promise.all( 
    urlList.map(
      function(url){
        return {
          url: url ,
          method: 'GET',
          header: {
            //not sure where token comes from
            "Authorization": `Bearer ${token}`,
            "Content-Type": "application/json"
          }
        };
      }
    ).map(
      function(call){
        return new Promise(
          function(resolve,reject){
            pm.sendRequest(
              call,
              function (err, res) {
              if (err) {
                reject(err);
              } else {
                resolve([call.url,res.json()]);
              }
            });
          }
        )
        .then(
          undefined
          ,function(err){
            //if something goes wrong we will still return something
            return [call.url,{error:err}];
          }
        )
      }
    )
  )
  .then(
    function(results){
      return results.reduce(
        function(acc,result){
          acc[result[0]] = result[1];
        }
        ,{}
      );
    }
  )
}
getResponses (listOfUrls)
.then(//this will always succeed, failed items have {error:something}
  function(results){
    console.log("results:",results);
  }
);
console.log("this comes before results");

The code above will cause all request to happen at once, this may not be the desired behavior, I have written a throttle method that is part of some library functions that may come in handy. You can apply the throttle to your code so it will only have max amount of connections:

const max = 10;//maximum 10 active connections
function getResponses(urlList) {  
  const throttled = throttle(max);
  if (typeof urlList === 'string') {
    urlList = urlList.split(' ');
  }
  return Promise.all( 
    urlList.map(
      function(url){
        return {
          url: url ,
          method: 'GET',
          header: {
            //not sure where token comes from
            "Authorization": `Bearer ${token}`,
            "Content-Type": "application/json"
          }
        };
      }
    ).map(
      throttled(//only max amount of connections active at any time
        function(call){
          return new Promise(
            function(resolve,reject){
              pm.sendRequest(
                call,
                function (err, res) {
                if (err) {
                  reject(err);
                } else {
                  resolve([call.url,res.json()]);
                }
              });
            }
          )
          .then(
            undefined
            ,function(err){
              //if something goes wrong we will still return something
              return [call.url,{error:err}];
            }
          )
        }
      )
    )
  )
  .then(
    function(results){
      return results.reduce(
        function(acc,result){
          acc[result[0]] = result[1];
        }
        ,{}
      );
    }
  )
}
getResponses (listOfUrls)
.then(//this will always succeed, failed items have {error:something}
  function(results){
    console.log("results:",results);
  }
);
console.log("this comes before results");
3

Apart from the other answer(s), following simple approach also works well instead of recursion:

_.forEach (
    urls,
    function (urls) {
        getAPI(url,function (url,schema,err) {            
            if (!err) {                
                respDictionary[url]=resp.json();
                console.log(schema);
            } else {                
                console.log(err);
            }
            pm.environment.set('respDictionary', JSON.stringify(respDictionary));
        });
    }
);

function getAPI(url, callback) {
    var _url = '{{BP_SERVER}}/' + urls;
    var call = {
        url: _url,
        method: 'GET',
        header: {
            "Authorization": `Bearer ${token}`,
            "Content-Type": "application/json"
        }
    };  

    pm.sendRequest(
        call,
        function (err, res) {
            if (!err) {             
                callback(urls,res.json());
            } else {                
                callback(urls,'',err);
            }
        }
    );
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.