Sharing tips and tricks with others in the Postman community

I’ve found in my short time working for Postman, that everyone I talk to uses the application in slightly different ways.

We all have our little tips and tricks that we use locally that have helped us with the tasks that we have been doing. These might be small things like creating a small helper function or much more bigger things.

I was inspired by @tmccann’s post this week about a particular way he’s created a process to solve a problem he was having, in his context.

This was new knowledge to me and I’m sure it was new to others too but by sharing this information, it’s allowed me to know a little bit more about the different use cases that our users have.

I want to start a thread that people can contribute to and share these new and different ways that you have Postman configured to suit your own context. By sharing something, big or small, you are passing on this awesome new information to other people in the wider Postman community.

I’m going to kick this off with something simple that solved a certain problem for me and hopefully, this encourages people to do the same.

I had a need to clear out my environment variables after a Collection run to start again in a known state for each run - I knew that I could use .unset() to clear each variable I had created but the code turned ugly really quickly when you have multiple repeated lines.

I was also aware of .clear() to go nuclear and wipe out the lot but I wanted to keep a few reusable variables like the baseURL for my requests.

I needed something that kind of sat in the middle of those two, that’s when I created this little cleanup function.

function cleanup() {
    const clean = _.keys(pm.environment.toObject())
    _.each(clean, (arrItem) => {
        if (!arrItem.startsWith("some_prefix")) {
            pm.environment.unset(arrItem)
        }
    })
}
cleanup() 

This is just a simple piece of JS code that clears out all the variables, apart from the ones that start with a certain prefix. This was just a basic naming convention that I created to add some order to my environment files.

This function was placed in Tests tab of the last request in the Collection, it would grab all of the environment variables and if the name didn’t start with the prefix, it would clear it out of my environment file. Simple but very effective for me at the time.

What are the things that you have been using locally that you think others might find interesting and valuable?

9 Likes

Well, I don’t want @dannydainton to have all the fun around here so here is a simple contribution from me. :smiley:

To go along the lines with my post earlier this week. I do a lot of CI/CD work, so that means I rely on Newman a lot.
For anyone that runs something similar, they know that you can console out everything or subsets of information when needed. However this usually means you have the add the console.log statements to the Pre-Request Scripts or the Tests tabs.

When you need to do debugging you can always add/remove these as needed but it is not good practice to leave those in there once you are done debugging. This is especially true if you are working on larger teams and not just a one person show.

In my case, I want to know when things go wrong but I don’t want to have to own everything and want to allow my user base to be able to troubleshoot without pulling me as I would become a bottle neck in the process.

What I did was I put this snippet of code in Tests tab of the collection:

var debug = pm.globals.get("debug");

// Check if the response body is JSON format.
try {
response = JSON.parse(responseBody);
} catch (exception) {
response = responseBody;
}

// Check debug logging is enabled, also that the response type is JSON and its not empty.
if (debug == 1) {
console.log(response);
}

What I am doing is setting a variable that I pass in as a parameter in my Jenkins job, this is a Global Variable that can be then passed into Newman on the command line.
My command would then look something like this:

newman run collectionName.json \
        --environment "environmentName.json" \
        --global-var debug=1 \
        --verbose \
        --disable-unicode \
        --color on \
        --delay-request 100

So what this is doing here is allowing me to pass that parameter as a Global var and run my collection.
First it will decide if the response is JSON or not. In my case it will either be JSON format or HTML but I am just doing a catch all here if its not JSON, you can improve on that as needed.

Once I know the response body format, I then check if we have debugging enabled or not as per mu parameter from my Jenkins job. It will be 0 for OFF and 1 for ON.

On each call in my collection it will then print out the response body if it is ON.
The outcome here is that when I look at the console logs in Jenkins, I see the responses for my calls and tell if there is a data issue that is causing things to fail.

As mentioned, this allow me to be hands off when there are issues and others can debug because the data is there in front of them. No need to pull me in to re-run and tell them where things are going wrong.

As always if you have questions or feedback, feel free to reach out :slight_smile:

5 Likes

Loosely Detecting Headers

Whilst testing a collection of APIs recently I found myself in a situation whereby I needed to detect if the response was JSON - pretty straight forward really in the grand schema of things. Postman has the pm.response.headers collection and the has method. However, that’s quite strict and uses exact matching. Some of the responses I was dealing with where inconsistent in their Content-Type values. e.g.

Content-Type: application/json
Content-Type: application/json;charset=utf-8

At the time of writing there was no .contains() method, so I had to improvise and came up with the following:

const isJsonResponse = (pm.response.headers.filter((header) => header.value.indexOf('application/json') !== -1).length > 0);

if (isJsonResponse) { 
	... do stuff ... 
}

A JavaScript dev I know, improved upon the snippet using object destructing, making it:

const isJsonResponse = pm.response.headers.filter(({headerValue}) => headerValue.indexOf('application/json') > -1).length;

It’s probably not going to change your life, but it’s something to keep in the tool box.

Oh, and one more thing!

The reason I needed a JSON detection snippet was because I was validating the JSON Schema of the API response. If you’re lazy like me, I can totally recommend a free tool for generating the JSON Schema from existing JSON over at Quicktype IO. Paste your JSON on the left hands side, and choose JSON Schema from the languages drop-down, thus:

https://app.quicktype.io?share=GxkZCPp7lZ1g3NpWhS6j.

4 Likes

Extracting values from a JSON response

I notice lots of questions from the community which all have a similar flavour - Users are having trouble extracting data from a JSON response body when the value is within an array.

These are normally JavaScript related questions, more than specific Postman questions but I want to use this thread to offer more support around this problem.

For these examples I’ll be using the https://randomuser.me API, this returns lots of random user data, in a JSON format. This is perfect to help with explaining ways to extract data.

This is an example of the response body returned from the randomuser API:

{
    "results": [
        {
            "gender": "female",
            "name": {
                "title": "mrs",
                "first": "tilla",
                "last": "sævareid"
            },
            "location": {
                "street": "mogens thorsens gate 3652",
                "city": "alta",
                "state": "nordland",
                "postcode": "1152",
                "coordinates": {
                    "latitude": "49.9350",
                    "longitude": "113.7576"
                },
                "timezone": {
                    "offset": "-6:00",
                    "description": "Central Time (US & Canada), Mexico City"
                }
            },
            "email": "tilla.sævareid@example.com",
            "login": {
                "uuid": "ed63d908-5b6f-4cf5-9abe-0be5107000ed",
                "username": "tinybird773",
                "password": "planet",
                "salt": "Tx7V7veO",
                "md5": "c601d954f8144194fd1f2df8e4d8e05e",
                "sha1": "205292c0af997e9c95ae8bd1247a8962a2240eac",
                "sha256": "ddcf7358dda748e1c61c8ea09434e5d3fd7b5aedf90a922c44423fb48815ff09"
            },
            "dob": {
                "date": "1991-12-12T09:06:33Z",
                "age": 27
            },
            "registered": {
                "date": "2007-10-10T12:43:45Z",
                "age": 11
            },
            "phone": "24000987",
            "cell": "94325402",
            "id": {
                "name": "FN",
                "value": "12129107373"
            },
            "picture": {
                "large": "https://randomuser.me/api/portraits/women/8.jpg",
                "medium": "https://randomuser.me/api/portraits/med/women/8.jpg",
                "thumbnail": "https://randomuser.me/api/portraits/thumb/women/8.jpg"
            },
            "nat": "NO"
        }
    ],
    "info": {
        "seed": "dab43d72e88a90df",
        "results": 1,
        "page": 1,
        "version": "1.2"
    }
} 

I’m going to do some basic global variable setting using the JSON response to demonstrate how to extract the values. You could also use this method to set the environment variables too.

Generally, users run into problems when the response body contains an array and this is when people tend to reach out for support because the code that would have been used the get the data from a single object, no longer works.

let jsonData = pm.response.json()

pm.globals.set('gender', jsonData.results.gender)

As you can see from the image, it’s created the global variable called gender but it’s failed to extract the value from the response.

As the results property type is an array with a list of objects within it, we need to specify which object we would like to use.

This response only has a single item and to get the data from within this object we reference it using [0]. Arrays are zero indexed so they start from 0 rather than 1 - This is an important thing to remember when working with JS arrays.

let jsonData = pm.response.json()

pm.globals.set('gender', jsonData.results[0].gender)

This time because we have added [0] to results, it has set the gender variable correctly. What that’s basically doing is saying that we want to get the value from the "gender" key, in the first object of the array.


Hardcoding the array index number is going to be ok if you know that you only have a single object but if you have multiple objects, you would need to iterate through those objects to get each of the values.

This time we’re going to add some JavaScript code to loop through the results array and get all the values from the "first" key, within the "name" object. Don’t worry, this will all make sense with a few examples.

Within the Postman application, there are a few built-in modules that we can use to help us out. For this example, I’m going to use the _.each() function from the Lodash module.

Using this function we can loop through the results array and grab each of the values we require, without the need to hardcode the index number.

let jsonData = pm.response.json()

_.each(jsonData.results, (result) => {
    pm.globals.set('firstName', result.name.first)
})

You can see in the image that we have extracted the "first" value and set this as the firstName global variable.

There’s a slight problem with this approach if there is more than 1 object. As we loop through the array, the variable is set but as there is more than 1 that value is overwritten with the last one. Not an ideal situation but we can add a couple of lines to our code to collect each of the first names, in the array.

This time we have created an empty array and assigned this to the firstNames variable. Next, within the loop, we are collecting each of the first names and using the .push() method to add these to the firstNames array.

Finally, when the loop has finished, we set a new firstNames global variable and use JSON.stringify() to save the array values as a string.

let jsonData   = pm.response.json()
let firstNames = []

_.each(jsonData.results, (result) => {
    firstNames.push(result.name.first)
})

pm.globals.set('firstNames', JSON.stringify(firstNames)) 

Now we can see that 5 different names have been set in the firstNames variable.


Just as a quick example - I’ll add a Test using a loop so we can see how this can be used to check for a certain value.

The API has a number of filters, one of which is to return a specific gender, we’re also returning 100 results and that would take a while to check each one manually so we can create a Test to do this for us in super quick time.

GET https://randomuser.me/api/?results=100&gender=female

let jsonData = pm.response.json()

pm.test('The `female` filter returns the correct gender', () => {
    _.each(jsonData.results, (result) => {
        pm.expect(result.gender).to.equal('female')
    })
})

12


So this was a basic walkthrough of how to extract data from a response body which has an array of objects. There are a number of different ways that we could do this using some of the different Lodash functions but for now, I’ve just kept it simple.

If this doesn’t make sense or you need to achieve something different, please reach out to me. :slight_smile:

8 Likes

Sending an array in a request using a data file in runner

I came across multiple questions around using an array in the part of a request body etc. using a data file in the collection runner, so here’s how you can get it working.

The solution is to extract the array out of the data variable, then since local variables have a higher scope than the data variable so you can stringify the array and store it in a local variable.
You can read more about the different types of variables and their scopes here.

You can also make use of a different type of variable type like the environment or global but then in that case you’ll have to give your variable a different name in the request body (if you’re confused here, don’t worry you’ll figure it out after reading further).

For eg:.
My data file is a JSON file and it has the following content in it:

[
  {
    "productLine": [
      {
        "id": "13jj443",
        "name": "postman"
      },
      {
        "id": "9039dds",
        "name": "newman"
      }
    ]
  },
  {
    "productLine": [
      {
        "id": "8349dfkl",
        "name": "postman-api"
      },
      {
        "id": "4590yuqp",
        "name": "api-network"
      }
    ]
  }
]

And I need to send the productLine array of each iteration as a part of my request body to the server.

Steps:

  1. In my Pre-request script, I need to get the data from the iteration data of the run.
    Code:

    let productLine = pm.iterationData.get('productLine');
    
  2. I need to stringify the productLine array and store it in a local variable (since local variables have higher precedence over data file variables so they will be used in the request-sending flow) in the script.
    Code:

    pm.variables.set('productLine', JSON.stringify(productLine));
    
  3. In my request body, I need to make sure I don’t have any quotes (") around my productLine variable that I am using:
    For eg:

    {
      "productLine": {{productLine}}
    }
    
  4. That would be all, fire it away!

2 Likes

HI @tmccann, me too, I have debug logging all over the place.
Found this nifty javascript ‘short circuiting’ trick to shorten it to one line

If you make your debug variable truthy, eg.

const debug = pm.globals.has("debug") && (pm.globals.get("debug") == 1);

so that debug will be either true or false
then simply use

debug && console.log('.. debug info ...');

I’ve found short circuiting really handy for this, but it can also reduce the unhandled exceptions (which can become a real nuisance in unattended execution)
eg, if your example normally returned a json response like

{
"result":{"success":true,"message":"the request succeeded"},
"value":"some json object"
}

then if you want to log the message with

debug && console.log(response.result.message);

would work fine as long as there is a message, but throws an exception if result wasn’t there.
Instead you could

debug && response.result && console.log(response.result.message);

which only tries to print message if there was a result.

(this relies on the concept of truthiness , check it out :grinning: )

2 Likes

@VincentD123 Thanks for the reply and welcome to the community.

That link to short circuiting is awesome.
This is the first time I have seen this and it’s something I am going to read into more as I can see how it would be useful.

2 Likes

Just a quick note on @jameshd’s Loosely Detecting Headers which I needed to do a week or so ago. Had a look at the Postman doc Headerlist object and down the page found the get(key) method.

pm.response.headers.get(‘Content-Type’).includes(‘application/json’)

this matches both your cases

However, it assumes the key is'Content-Type' :thinking: not 100% sure if the key parameter is case-sensitive, or if the server is obliged to use case accurate 'Content-Type'?

This approach is kind of bad. if you want afterwards to iterate inside the array (which of course we want to do that, it is the whole point of having arrays), then you can’t use this because you saved the array as a string, not as an array. fo that you need to transoform that string back to an array. for example:
var fisrtNames = pm.globals.get(“fisrtNames”); //this is my string extracted from a JSON array response on another request
var jsonData = JSON.parse(fisrtNames); // this is how I call back that string and transform it back to an array so I can actually use it