TestingAPIs is still being built. If something breaks, email support@testingapis.com.

Collections, environments and variables

One base URL for every request, and which value wins when two scopes disagree.

Type https://api.testingapis.com into thirty requests and you have thirty places to change when the address changes, or when you want to run the same requests against a staging server. Variables fix that. You write {{baseUrl}}/api/Products/1, and Postman fills in baseUrl when it sends the request. This lesson covers where variables live, which one wins when two have the same name, and how to keep secrets out of files you share.

The double-brace syntax

Anything in double curly braces is a variable: in the URL, in headers, in the body, in the Authorization tab. Postman highlights it, and hovering shows the current value and where it came from. A variable that has no value stays as literal text, braces and all, so a request to {{baseUrl}}/api/Products/1 with no baseUrl defined fails with a confusing address error. If you ever see braces in a URL in an error message, a variable is missing.

Where variables live

Postman has five places to keep a variable. When two have the same name, the narrower scope wins:

ScopeLives inGood for
LocalOne run of one scriptTemporary values a script works out
DataA row of a data file, during a Collection Runner runTest inputs that change per row (lesson 6)
EnvironmentThe environment selected in the top cornerAnything that differs between servers: base URL, keys, accounts
CollectionThe collection itselfDefaults that travel with the collection, and values passed between requests
GlobalYour whole workspaceVery little. Globals leak between unrelated collections

The order in the table is the order of precedence, narrowest first. So an environment variable called baseUrlbeats a collection variable with the same name. That's exactly how the tutorial collection is built: it has a collection variable baseUrl pointing at the public API, so it works the moment you import it, and an environment that can override it. Point the environment at a local copy of an API and every request follows, without touching the collection.

Environments

An environment is a named set of variables you can switch between, typically one per server: local, staging, production. The tutorial's environment file is small:

testingapis-postman-environment.json
{
  "name": "TestingAPIs",
  "values": [
    { "key": "baseUrl", "value": "https://api.testingapis.com", "type": "default", "enabled": true },
    { "key": "apiKey", "value": "", "type": "secret", "enabled": true }
  ],
  "_postman_variable_scope": "environment"
}

After importing it, select TestingAPIsin the environment list. Requests then use its values. If no environment is selected, the collection's own baseUrl still applies, which is why the collection works either way.

Seeing which value won

The request 02 Variables / Product by ID from a variable uses two variables, {{baseUrl}}/api/Products/{{productId}}, and checks the result:

Post-response script
pm.test("the product matches the productId variable", () => {
  pm.expect(pm.response.json().id).to.eql(Number(pm.variables.get("productId")));
});
console.log("baseUrl resolved to", pm.variables.get("baseUrl"));

pm.variables.get returns whichever value wins by the rules above. The console.logline writes to Postman's console, which you open from the bottom of the window. The console is where you go when a variable doesn't hold what you expect: it shows every request as actually sent, with variables already replaced.

Keeping secrets out of shared files

Collections and environments get exported, emailed and committed to Git, so treat anything you type into them as something that might be read by others. Postman separates the value you share from the value used on your machine, and the labels for the two have changed between versions. Before you put a real key into an environment, check which value is the shared one, and leave that one empty.

Mark keys and tokens with the secret type, as the apiKeyvariable above is. Postman then masks the value on screen. Masking doesn't encrypt anything; it stops a key appearing in a screenshot or a screen share, which is how many keys leak.

The tutorial collection reads the key from the environment in a collection-level script, so no request has the key written into it:

Collection pre-request script
// Runs before every request in the collection. Endpoints outside the free tier read an API key from
// this header; it's only added when the apiKey environment variable has a value.
const apiKey = pm.environment.get("apiKey");
if (apiKey) {
  pm.request.headers.upsert({ key: "X-TestingApis-Key", value: apiKey });
}

Scripts are the subject of lesson 5; for now, notice that a script attached to the collection runs before every request inside it, which makes it the one place to add a header to all of them.

Variables in scripts

Scripts read and write variables through the pm object. These four lines cover most needs:

JavaScript
pm.variables.get("baseUrl");               // the value that wins, whatever its scope
pm.collectionVariables.set("todoId", 31);   // write to the collection
pm.environment.set("token", "abc");         // write to the active environment
pm.variables.replaceIn("{{baseUrl}}/api");  // resolve {{...}} inside a string
This example uses endpoints for signed-in members.Sign inCreate a free account

Postman also has built-in dynamic variables that produce a fresh value every time: {{$guid}}, {{$timestamp}}, {{$randomEmail}}, {{$randomFirstName}} and many more. They are the quickest way to stop two test runs colliding on the same email address or name.

Variable checklist

  • No request has a host name written into it; every URL starts with {{baseUrl}}.
  • Values that differ between servers live in environments; defaults live in the collection.
  • Secrets have the secret type and an empty shared value.
  • Nothing depends on a global.
  • When a value surprises you, the console shows what was really sent.

Exercise

Duplicate the TestingAPIs environment and call the copy Broken. Change its baseUrl to https://api.testingapis.com/nope, select it, and send Product by ID from a variable. What status do you get, and what does the console show as the full URL? Then delete baseUrl from the Broken environment entirely and send again. Explain why the request now works.

Practise and go further