Can I use pm.sendRequest() to send requests synchronously?

In the context of http://blog.getpostman.com/2017/10/03/send-asynchronous-requests-with-postmans-pm-api/, I’d like to send 2 requests SYNCHRONOUSLY (and NOT Asynchronously) from a pre-request script.

One of the requests resets my auth token and the other fetches some data needed for the main request I want to send.
The issue is that the data fetching request also needs that auth token to be successful.

Can I write my pre-request script in a way so that my data fetching request always runs AFTER my auth token request?

The code looks like this:

eval(pm.globals.get("adminLogin"))();    //sets authorizationToken

pm.sendRequest({
    url: pm.environment.get("host") + "/" + pm.environment.get("apiPath") + "/card/" + pm.environment.get("card1Id"),
    method: "GET",
    header: {
        "content-type": "application/json",
        "accept": "application/json",
        "authorization": pm.environment.get("authorizationToken")
    },
    body: {}
}, function (err, res) {
    pm.environment.set("txnExpiryDate", res.json().expiryDate.slice(0,2) + "" + res.json().expiryDate.slice(3, 5));
    pm.environment.set("txnCardNumber", res.json().cardNumber);
});

Thanks!

1 Like

Did you find any solution to do this synchronously?

found this https://medium.com/@MrPonath/postman-pre-request-scripts-81920a78d0fc but they are not using the native pm.sendRequest.

No solution yet. So far, I’m trying to have 1 request only in the pre-request script, so for the example above, I make sure I’m logged in already.

The pm.sendRequests are asynchronous in nature.

In the following snippet,

pm.sendRequest(req1, done);
pm.sendRequest(req2, done);

both req1 and req2 are sent out immediately without waiting for them to complete. In order to make req2 wait for req1 you have to nest pm.sendRequest(req2) inside the callback of req1. It will be something like,

pm.sendRequest(req1, function () {
  pm.sendRequest(req2, done);
});

Although this solves your problem, it can get unreadable and complex over time. I’m interested in finding alternatives to solve this. Have you tried seeting the three requests in order in a collection and running them?

6 Likes

Thanks for the nested solution. Agreed, it might be quickly unreadable, unless perhaps if the nested request is done with the code in a variable, e.g.:

eval(pm.globals.get("customerLogin"))();

And yes, I have been using separate requests organised in collections and folders but I quickly reached in excess of 1800 requests for a single API so I’ve been trying to find ways to reduce that number. Including some requests in the pre-request scripts, especially authentication related ones, helps making things a bit easier to navigate through.

EDIT: oh, that bit was already in my example…

I have been using separate requests organised in collections and folders but I quickly reached in excess of 1800 requests for a single API so I’ve been trying to find ways to reduce that number. Including some requests in the pre-request scripts, especially authentication related ones, helps making things a bit easier to navigate through.

We’ve been working on something that might help with that. We are introducing scripts and auth at collection/folder level. It is available for early access on our Canary channel(for linux and mac, coming out on windows soon).

2 Likes

Is there any documentation how Postman Canary would support this as of today?

We’ve added support for collection and folder level scripts and auth in our stable channel. Please update to the latest version and try it out. You can find the option to add scripts and auth in the Edit Folder/Collection option.

Thank you! So would this enable the option to send requests synchronously with pm.sendRequest()?

Nope. pm.sendRequests are asynchronous always. However, you will have the option to group common scripts in folder/collection scripts in the latest version.

you can with javascript promise - await mechanism. even iterations is possible.
//------------------sandos---------------------------
function SendRequest(maxRequest) {
return new Promise(resolve => {
pm.sendRequest({ … },
function(err, res) {
var response = JSON.stringify(res);
console.log("res: " + pinresponse);
if (maxRequest>1) {
SendRequest(maxRequest-1);
} else {
resolve(1);
}
}
);
});
}

async function SenReq(maxRequest) {
return await SendRequest(maxRequest);
}
//Engineered with Sandos chan

Yes it is possible! For instance, I use this for retrieve a JS archive from a CDN, then make it available before the collection gets executed. So paste some similar snippet into your Pre-request Scripts:

var settings = {
    async: false,
    crossDomain: true,
    url: "https://myhost/mylib.js",
    method: 'GET',
};

pm.sendRequest(settings, (err, res) => { 
    eval(res.text()); 
});

That is not a valid Request object to pass to the pm.sendRequest function. The Request object is docmented here: http://www.postmanlabs.com/postman-collection/Request.html, and it has neither “async” nor “crossDomain” properties. In short, you can’t do synchronous calls this way.

You are probably right. However, it s working for me so far! Magic? Older version? Which to.hear more details to have a deep understanding. Thanks for feedback

Older version, maybe. Trust me, I wanted that to work in the worst way!

For anyone else with this kind of need who stumbles across this thread, the way I ended up solving my particular use case was to break my request into two separate requests. In my case, the first request performs the API operation and the second fetches data from Couchbase to validate against. I attach the actual tests for the FIRST request to the test block of the SECOND request. I don’t use sendRequest at all, now.

In the OPs case, I would make the call to get the auth key from the first request and stash it in an environment variable, and then do the API request & associated tests in the second request.

I have a solution by using recursion.

var lib = "";
var jsList = pm.iterationData.get("jsList").split("|");

if (!pm.variables.get("concatLib")){
    pm.variables.clear();
    libGetter();
}
else {
    eval(pm.variables.get("concatLib"));
    preRequestScript();
}

function libGetter(){
    pm.sendRequest({
        url:  "localhost:8080/"+ jsList[0] +".js", 
    }, function (err, res) {
        if (err) { 
            console.log(err);
        }
        else {
            lib = lib.concat(res.text());
            jsList.shift();
            if(jsList[0]){
                libGetter();
            }
            else{
                pm.variables.set("concatLib", lib);
                eval(pm.variables.get("concatLib"));
                preRequestScript();
            }
        }
    });
}

to be consistent with the postman workflow, you should have a pivot request with the aim of synchronously to call many times the other requests, the pivot could have a simple request like “postman-echo.com/get” in order to build the next request on the test script in Postman, the above must set the index value of the iteration to avoid infinity cycle, as show the next image

the calculateFunds post will execute many times through of pivot request, and finally the calculateFunds test script will have to call pivot and eventually using the postman workflow, you don’t mind about the asynchronous callings.

Try something like this:

sendPostRequest(12345)
    .then((data) => {
        console.log("data from  postRequest ", data)
    })
    .catch((error) =>  {
		console.log("error: ", error)
	})

// function that retuns a Promise
function sendPostRequest(id) {

    return new Promise(
        resolve => {
            const postReq = {
                url: pm.environment.get('function-url'),
                method: 'POST',
                body: {
                    mode: 'raw',
                    raw: {
                        id: +id
                    }
                }
            };

            pm.sendRequest(postReq, function(err, res) {
                if (err) {
                    console.error(err);
                    return;
                }
                return resolve( res.json());
            });
        });
}
1 Like

@jdang thanks - I had to make a couple changes (just around the body part) but would it be possible to chain an additional get request?

The post requet returns “null” (which is entirely unhelpful) so I still need a get after this - but I admit I am struggling to see how

You can try following to control the timing of your requests

setTimeout(function(){
pm.sendRequest(req1, function () {
});
},1000);

setTimeout(function(){
pm.sendRequest(req2, function () {
});
},2000);

setTimeout(function(){
pm.sendRequest(req3, function () {
});
},3000);