Update an env var in a prerequest script and use in request?

Is it possible to update an environment variable within a collection pre-request script and have access to that updated value in the actual request?

Assume you have a simple GET request which uses an variable within the URL, e.g:

http://example.com/api/thing/{{ID}}

Where {{ID}} is stored as an environment variable.

Sometimes, this data needs to be modified before the request runs. You can use a pre-request script to update the value, however, as the request has already been initiated, the updated value is not used in the URL above; instead, the initial (unmodified) value is used.

Is it possible to use it somehow to force a refresh of the variables used should this occur?

Example:
If the environment variable ID is set to “foo123456”, then:

Example, pre-request script:

const ID = pm.environment.get("ID");
if (ID.startsWith("foo")) {
    pm.environment.set('ID', "bar" + ID);
};

This does update the Environment variable, however, the request is incorrect:

Desired result:

http://example.com/api/thing/barfoo123456

Actual result:

http://example.com/api/thing/foo123456

Of course, running the request a second time works as expected.

Hi @swinster

I just tried this and it works as expected for me…

Could you share any more information that might help recreate what you are seeing?

For example; in your environment file, have you got your variable set in both Initial and Current? (My script only worked with your code above when I had the ‘Current’ value set.

Example of what I get:

The environment variable set as ‘foo’

After clicking send (once) I see ‘barfoo’ in logs…
image

Hmm, interesting. Firstly, yes, I use the “Current Value” of an environment variable to store a current value. I believe initial values are used when sharing and initialising an environment (copied to the current value).

Initial values are shared when you share a collection or environment. Current values are local and not synced or shared. See Specifying variable detail.

As an aside, I have had to use the initial value to describe the variable as Postman doesn’t offer this facility (see Add descriptions to variables · Issue #11303 · postmanlabs/postman-app-support · GitHub and other issues). But I digress :slight_smile:

I use the pre-request script within the collection scope to set these variables, as I have numerous requests where this update might be required.

I will recreate something simple and see what happens, then post back with some results.

It’s always the current value that is used within environment variables.

If you have an initial value set, but no current value and try to console log the variable, it will return as an empty string. (Not undefined).

If you forget to select the environment, then it will return undefined.

When you first add an environment variable and set the initial value, it gets automatically copied to the current value (but you can delete it afterwards).

Initial values shouldn’t really conflict.

In relation to your original problem. This should work as James has detailed. I can only recommend that you console log the environment variable straight after you set it in the same block of code to ensure that its working.

1 Like

Unfortunately, this (for whatever reason) is not working for me :frowning: .

The code I used above is a very similar example, but I have included the actual pre-script code below. I created a new collection and a new environment just for testing:

Here is the variable in the environment scope:

And this is the pre-script code:

//Check if Env ID has 'EN' in front of it and add it if not. Anoyingly, this will only work for the next request
var envID = pm.environment.get("envID");

console.log("This is the initial value of the ID: " + envID);

if (!(envID.startsWith("EN"))) {
    pm.environment.set('envID', "EN" + envID);
};

console.log("This is the latest value of the ID: " + pm.environment.get("envID"));

And an image of the request seen in Postman:

This is the log output:

This is the initial value of the ID: lFC4pZPgYUX75gdN5WlnLw2
This is the latest value of the ID: ENlFC4pZPgYUX75gdN5WlnLw2
GET https://example.com/api/v3/envs/lFC4pZPgYUX75gdN5WlnLw2

We can see that the environment variable is updated successfully but it is simply not used in the request.

Can you highlight the envID variable in the URL.

It should tell you what the current value and what it thinks the scope is.

Is it telling you “environment”?

The higher prioriy than environment variable is global variable. If there is a global variable by the same name, then postman might be referring to that.

Yes, and it is the environment scope :frowning: The variable doesn’t exist in any other scope.

image
NOTE: I manually updated the variable again to remove the “EN”, but yes, it updates correctly.

Whats in your ‘params’ tab?

Nothing. Not use on this request.

I suspect there is something in there because it has a green dot by it…

You are right. there was, I deleted it after the screenshot (just to test), but what was in there was disabled

image

are you on the latest version of Postman?

HA! I think I have figured it out.

In the collection, I have to set up API authentication (this API uses some very obscure authentication!). This code takes the request URL and uses it in the HMAC argument in the authorisation header. The URL was grabbed BEFORE the update had been applied.

Here is the code:

// **** Setup Pre-request Authentication ****

// Function to create a random alpahnumeric character using the {{$randomAlphaNumeric}} dynamic variable 
function randomString(length=1) {
    let randomString = "";
    for (let i = 0; i < length; i++){
        randomString += pm.variables.replaceIn("{{$randomAlphaNumeric}}");
    }
    return randomString;
}

// Grab the API ID and API key set within an enviroment scope
const API_ID = pm.variables.get("API_ID");
const API_KEY = pm.variables.get("API_KEY");

// Grab new token of 10 characters from the randomString function
const STRING_LEN = 10
var token = randomString(STRING_LEN);


// URL Encode the request URL
const EncodedURL = encodeURI(pm.variables.replaceIn(pm.request.url));

// Grab an epoch timestamp based on the {{$timestamp}} dynamic variable.
var timestamp = pm.variables.replaceIn('{{$timestamp}}');

// Debug
console.log(pm.request.url.getPathWithQuery());

// Concatonate various strings to create the HMAC signature 
// (see https://docs.cloudshare.com/rest-api/v3/overview/using-the-rest-api/ - "The HMAC Signature" 
const HMACString = API_KEY + EncodedURL + timestamp + token;

var hmac = CryptoJS.SHA1(HMACString).toString();

// Sets the Authorization Request Headers (see documentation URLabove) and save them to an enviroment vaaiable to be used with the requests
AUTH_PARAM = "userapiid:" + API_ID + ";timestamp:" + timestamp + ";token:" + token + ";hmac:" + hmac;
pm.environment.set('auth-header', "cs_sha1 "+ AUTH_PARAM);

If I update the environment variable before I do this authorisation compute, then it works as expected.

// **** Setup Pre-request Authentication ****

// Function to create a random alpahnumeric character using the {{$randomAlphaNumeric}} dynamic variable 
function randomString(length=1) {
    let randomString = "";
    for (let i = 0; i < length; i++){
        randomString += pm.variables.replaceIn("{{$randomAlphaNumeric}}");
    }
    return randomString;
}

//Check if Env ID has 'EN' in front of it and add it if not. Anoyingly, this will only work for the next request
var envID = pm.environment.get("envID");

if (!(envID.startsWith("EN"))) {
    pm.environment.set('envID', "EN" + envID);
};

// Grab the API ID and API key set within an enviroment scope
const API_ID = pm.variables.get("API_ID");
const API_KEY = pm.variables.get("API_KEY");

// Grab new token of 10 characters from the randomString function
const STRING_LEN = 10
var token = randomString(STRING_LEN);


// URL Encode the request URL
const EncodedURL = encodeURI(pm.variables.replaceIn(pm.request.url));

// Grab an epoch timestamp based on the {{$timestamp}} dynamic variable.
var timestamp = pm.variables.replaceIn('{{$timestamp}}');

// Debug
console.log(pm.request.url.getPathWithQuery());

// Concatonate various strings to create the HMAC signature 
// (see https://docs.cloudshare.com/rest-api/v3/overview/using-the-rest-api/ - "The HMAC Signature" 
const HMACString = API_KEY + EncodedURL + timestamp + token;

var hmac = CryptoJS.SHA1(HMACString).toString();

// Sets the Authorization Request Headers (see documentation URLabove) and save them to an enviroment vaaiable to be used with the requests
AUTH_PARAM = "userapiid:" + API_ID + ";timestamp:" + timestamp + ";token:" + token + ";hmac:" + hmac;
pm.environment.set('auth-header', "cs_sha1 "+ AUTH_PARAM);

I did not think this would affect things upstream, but the fact that you guys proved it should work simply meant that I could investigate what might be failing else where.

Many thanks.

1 Like

@maintenance-techno12

The priority for scoping is…

Local → Data → Environment → Collection → Global

If you have a variable set as global and also in an environment, then the environment variable will be what wins.

@swinster Glad you found out what the issue was.