Why can't (How can) PRE-REQUEST support {{variable}} in request-line / request-body?

Please search for related topics, and then read through the guidelines before creating a new issue.

Describe the bug
Why can’t (How can) PRE-REQUEST support {{variable}} in request-line / request-body ?

To Reproduce
Steps to reproduce the behavior:

  1. save ‘e_http’ as environment-variable, like ‘http://1.1.1.1
  2. fill request-line as {{e_http}}/api/v1/sys/auth/login/userLogin
  3. fille pre-request script as

var requestUrl = request.url;
var requestUrl2 = “{{e_http}}/api/v1/sys/auth/login/userLogin”;

var md5str = CryptoJS.MD5(requestUrl).toString();
var md5str2 = CryptoJS.MD5(requestUrl2).toString();

console.log(requestUrl+“///”+md5str);
console.log(requestUrl2+“///”+md5str2);

  1. See screenshots, variable can not be referenced in pre-request:

Expected behavior
reference to variable in pre-request when variable in request-line / request-body

Screenshots
compare with jmeter:

App information (please complete the following information):

  • App Type [Chrome App]
  • Postman Version [7.6.0]
  • OS: [windows 7]

Additional context
Add any other context about the problem here.

Hey @medsonkissinger,

Welcome to the Postman community :trophy:

Within the Pre-request Script, you cannot use the {{...}} syntax directly so you would need to grab that environment variable in either of the following ways:

`${pm.environment.get('e_http')}/api/v1/sys/auth/login/userLogin`  

Or

`${pm.environment.replaceIn('{{e_http}}')}/api/v1/sys/auth/login/userLogin`

Hope that helps. :slight_smile:

1 Like

Very thank you for your answer @danny-dainton .
I understand what you mean, but there is another problem comes to me :
If I given up using request.url/request.data, I have to customize over 100 apis
100 request-urls is easy, 100 request-bodies will drive me crazy :tired_face:

I’m a little bit confused by what you mean, the original question was around being able to use an environment variable in a Pre-request Script.

This slight change in what you had would allow you to do that:

var requestUrl = request.url;
var requestUrl2 = `${pm.environment.get('e_http')}/api/v1/sys/auth/login/userLogin`;

var md5str = CryptoJS.MD5(requestUrl).toString();
var md5str2 = CryptoJS.MD5(requestUrl2).toString();

console.log(requestUrl+"///"+md5str);
console.log(requestUrl2+"///"+md5str2); 

This is only for a single request but this could be moved up to the Collection Level and you would only need it once for all the requests, rather than repeating it in everyone.

As for the request body part of your follow up question, I don’t know what your collection looks like or what other scripts/things you have going on in there so I can only offer a solution based on a best guess.

You would need to elaborate more on your specific use case and maybe add some more example images for other people to look at and provide a more tailored answer. :slight_smile:

it’s so nice for you to reply me in time. and i am sorry for not giving you all of my code because it’s classify for my company.now pls allow me to show you the demo:


at last , i will put signKey into request-header.
after login request, there are over 100 requests to rebuilt.
btw, my job is Interface Automation Developer.

thank you for reading my code.

here is the script:

var lodash = require(`lodash`);
const querystring = require('querystring');
console.log("------------------------");
var requestMethod = request.method;
var requestUrl = request.url;
var requestData = request.data;
//generate signKey by CryptoJS
var signKey = signRequest(requestMethod,requestUrl,requestData);
pm.environment.set("signKey", signKey);
console.log("signKey:"+signKey);

/**
 * @param {} method 
 * @param {} url 
 * @param {} data 
 */
function signRequest (method , url , data) {
  let signData = new Map()
  let signString = '' 
  let keys = []
  getSignData('', data, signData)
  signData.forEach((value, key) => keys.push(key))
  keys.sort().forEach((key) => {
    signString += `${key.toString()}=${signData.get(key) ? signData.get(key).toString() : ''};`
    }
    )
  return CryptoJS.SHA256(signString).toString()
}  
//format reuqest body 
function getSignData (keyPrefix, obj, signData) {
  if (lodash.isMap(obj)) {
    obj.forEach((value, key) => {
      getSignData(keyPrefix ? `${keyPrefix}.${key}` : `${key}`, value, signData) 
    })
  } else if (lodash.isSet(obj) || lodash.isArray(obj)) {
    let idx = 0
    obj.forEach((item) => {
      getSignData(keyPrefix ? `${keyPrefix}.${idx}` : `${idx}`, item, signData) 
      idx++
    })
  } else if (isPrimitive(obj)) {
    signData.set(keyPrefix, obj)
  } else if (lodash.isObject(obj)) {
    Object.getOwnPropertyNames(obj).forEach((name) => {
      getSignData(keyPrefix ? `${keyPrefix}.${name}` : `${name}`, obj[name], signData) 
    })
  } 
}
//format reuqest body 
function isPrimitive (obj) {
  return lodash.isNumber(obj) || lodash.isString(obj) || lodash.isBoolean(obj) || lodash.isDate(obj)
}

Hello @danny-dainton
I tried to insert variables like you mentioned, but still does not work, i tried both methods - still nothing :frowning:

// Getting auth token from Keycloak
    pm.sendRequest({
    url:"https://${pm.globals.replaceIn('{{KC_HOST}}')}:${pm.globals.replaceIn('{{KC_PORT}}')}/auth/realms/${pm.globals.replaceIn('{{KC_REALM}}')}/protocol/openid-connect/token", 

        method:"POST",
        header: {
            "Content-Type": "application/x-www-form-urlencoded",
            "Authorization": "Basic " + btoa("rest_api:password")
        },
        body: {
            mode: "urlencoded",
            urlencoded: [
                { key: "grant_type", value: "password" },
                { key: "username", value: "user" },
                { key: "password", value: "password" },
            ]
        }
    },

Hostname being sent is
Host: {pm.globals.replacein('{{kc_host}}')}:{pm.globals.replaceIn(’{{KC_PORT}}’)}
So it did not work :frowning:
If i replace variables with IP and port numbers and realm name respectively, it does work

If those are global variables, you wouldn’t really need to use replaceIn - You also need to ensure that these strings use backticks () and not quote marks` at each end (") or the variables will not be resolved.

// Wrap the url value in backticks
url:`https://${pm.globals.get('KC_HOST')}:${pm.globals.get('KC_PORT')}/auth/realms/${pm.globals.get('KC_REALM')}/protocol/openid-connect/token`
2 Likes

Thanks @danny-dainton !
I changed string like you said and now it works! - I did some other mistakes thus it did not work, but i found them myself. Thank you a lot! :slight_smile:

1 Like

Cool, I would check to see what key/values you have set globally, to ensure those are what you’re expecting.

1 Like

Yeah, i pressed “set variable” button during my messing arround and set value of KC_HOST to … “kc_host” :smiley: But i found it out. Now it works! Thank you very much!

1 Like

I ran into the same problem, but with btoa. Using the back-ticks as recommended here solved that. Thanks!

1 Like