Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Make API available for variable substitution #2922

Closed
mattdeluco opened this issue Apr 7, 2017 · 13 comments

Comments

@mattdeluco
Copy link

mattdeluco commented Apr 7, 2017

I'm running into an issue with my pre-request script that is the result of environment variables not being substituted in the request (request.url, request.data, etc.)

It's mentioned in a few closed issues here, and that behaviour is apparently by design.

So my request is that if environment variables are not going to be substituted before the pre-request script runs, could you make available the tools and functions Postman uses to make the substitutions? For example, say on my environment there is envVar='envVarValueSubstituted', then in my pre-request script I might have something like this: postman.substituteVariables('A string with an {{envVar}}') which yields the string 'A string with an envVarValueSubstituted'. Or if request.url={{url}}/foo/bar/{{envVar}} and url=https://example.com, postman.substituteVariables(request.url) would yield 'https://example.com/foo/bar/envVarValueSubstituted'.

My use case is generating an Authorization header. I'd like to be able to store a lot of info in the environment variables, and also use chained requests that set environment variables. I have env. vars in both the URL and request body, and I need to use both of those (with substituted variables) when generating the Authorization header.

Version/App Information:

  1. Postman Version: 4.10.5
  2. App (Chrome app or Mac app): Chrome app
  3. OS details: macOS 10.12.3
  4. Is the Interceptor on and enabled in the app: No
  5. Did you encounter this recently, or has this bug always been there: n/a
  6. Expected behaviour: n/a
  7. Console logs (http://blog.getpostman.com/2014/01/27/enabling-chrome-developer-tools-inside-postman/ for the Chrome App, View->Toggle Dev Tools for the Mac app): n/a
  8. Screenshots (if applicable): n/a
@shamasis

This comment has been minimized.

Copy link
Member

shamasis commented Apr 7, 2017

This is a cool idea. Adding it to our list. Will ping when we get around to this.

@numaanashraf numaanashraf added the feature label Apr 7, 2017
@skyboyer

This comment has been minimized.

Copy link

skyboyer commented Apr 7, 2017

Does it make sense to describe additional flag "recursive" per variable?
Then both literal {{var_name}} for headers/body as well as postman.get*Variable would stay untouched. And just parsing would be changed under the hood.

@gitfool

This comment has been minimized.

Copy link

gitfool commented Apr 19, 2017

I have the exact same scenario - I need to replace / substitute variables to generate a custom Authorization header. This is my current workaround I use in the pre-request script:

var replaceVars = function(string)
{
    return string.replace(/\{\{.+?\}\}/g, function(match)
    {
        var varName = match.substr(2, match.length - 4);
        var varValue = environment[varName] || globals[varName];
        return varValue ? replaceVars(varValue) : match; // recursive!
    });
}

var url = replaceVars(request.url);
...
@mattdeluco

This comment has been minimized.

Copy link
Author

mattdeluco commented Apr 19, 2017

@gitfool - the following is what I came up with. I believe it should also work for nested substitutions, in fact it may be possible that it could get stuck in an infinite replacement loop with a clever env var. I nabbed the regex from the Postman code itself, and in there I found that there's a limit of 19 replacement loops IIRC.

If you examine the regex you'll find it matches only the innermost set of double-braces, so on each iteration the replacements move from the inside out allowing nested env vars.

var substituteEnvVars = function (varStr) {
    var match;
    
    while ((match = /\{\{([^{}]*?)}}/g.exec(varStr)) !== null ) {
        if (!Object.has(environment, match[1])) {
            continue;
        }
        var envVar = new RegExp(RegExp.escape(match[0]), 'g');
        varStr = varStr.replace(envVar, environment[match[1]]);
    }
    
    return varStr;
};

Note that RegExp.escape() is from sugarjs, included in Postman for use in pre-request scripts.

@skyboyer

This comment has been minimized.

Copy link

skyboyer commented Apr 19, 2017

@mattdeluco
variable may be got from [data, environment, globals]
Somthing like:

       var source = _.find([data, environment, globals], function (dataObj) {
           return dataObj.hasOwnProperty(variableName); 
       });

@gitfool
environment[varName] || globals[varName] does not seem to be safe because variable may have valid value of empty string so postman and script given would have different results(I mean postman doesn't pick global variable if env variable is empty string)

@gitfool

This comment has been minimized.

Copy link

gitfool commented Apr 19, 2017

@skyboyer That's intuitive to me since the environment variable is defined (as empty string) and so should override the global variable. Presumably you could "uncheck" the environment variable if you want to fallback to the global variable in that case.

@skyboyer

This comment has been minimized.

Copy link

skyboyer commented Apr 19, 2017

@gitfool sorry, my point was not clear.
I just wanted to say environment[varName] || globals[varName] will use global variable(does not it?) if environment's one is empty string. And for postman's native variable substitution feature it works in different way(just like you've just described).

@gitfool

This comment has been minimized.

Copy link

gitfool commented Apr 19, 2017

@skyboyer You're right. All the more reason for Postman to supply the function! 😉

That said, if Postman implemented my suggestion in #2960, they should behave the same way.

@a85

This comment has been minimized.

Copy link
Contributor

a85 commented Dec 24, 2017

@shamasis This should be possible now through the sandbox. Yeah?

@skyboyer

This comment has been minimized.

Copy link

skyboyer commented Feb 16, 2018

Postman team has implemented pm.variables.get() to use instead of environment[...] || globals[...] but the root issue with variable substitution is still actual.

@a85 a85 self-assigned this Jun 29, 2018
@kamranayub

This comment has been minimized.

Copy link

kamranayub commented Sep 27, 2018

Dang, came here looking to do just this. For example, generating the Azure Storage REST API authorization header is ... complicated, but I got it working and I'd like to use the variable substitution to generate the auth signature. I'll have to use some workarounds above for now.

I see VariableList.replace which is what I want but don't see any way to access from pm.*.

@saswatds

This comment has been minimized.

Copy link

saswatds commented Jun 18, 2019

Note:
Duplicate of #5767

@codenirvana

This comment has been minimized.

Copy link
Member

codenirvana commented Sep 2, 2019

We've added support for the new replaceIn method in v7.6.0.

You can use pm.variables.replaceIn(<template: String|Object>) to replace variables in the given template string or object.

Also works with pm.globals and pm.environment.

Example:

  • pm.variables.replaceIn('{{var1}}')
    returns variable var1's value
  • pm.variables.replaceIn(pm.request.url).toString()
    returns resolved request url
  • pm.variables.replaceIn('{{$randomFirstName}} {{$randomLastName}}')
    returns random name. More about Faker: #971 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.