BLOG

The Postman Always Pings Twice

Postman is a handy tool that can help you do full stack integration testing of your APIs. Learn how to use it without requiring any panic flips.

For all the value of unit tests, sometimes there’s no replacement for testing an entire application in situ. By hitting your API endpoint in a running system, in one fell swoop you can test the functionality of both your code and deployment integration. This philosophy is popular for web-facing applications, with tools such as Selenium letting you exercise the functionality of your website, but similar tools are available for applications that can expose themselves via REST-style APIs.

Probably the most popular of these collaboration platforms for API development and testing is Postman. Part of Postman’s popularity, no doubt, is because it has a free version, but it also has a lot of useful features and can scale to enterprise needs if you’re willing to fork out some dough.

But James, I hear you say, I can test my endpoints using wget or curl! Yes, and you can also start a fire using two rocks. But when there’s a blowtorch sitting right there, wouldn’t you rather use it? (Note: The author in no way endorses using a blow torch to kindle a fire, and any claims that he does so regularly are base slander.)

The problem with poking at your API using command-line tools such as wget and curl is that APIs don’t live in isolation. Frequently, you need to pass the results of one REST call to the next. For example, consider endpoints protected by SSO authentication. You authenticate yourself on one endpoint, take the cookie it provides as a result, and then stick it in the header of subsequent requests to an entirely different endpoint. Yes, you can accomplish that using command-line tools and a bunch of intermediate “glue” code to extract the cookie and pass it on, but Postman basically lets you do it for free.

In this tutorial, I show you how to use Postman to extract data from one API call and pass it forward to another. (I don’t tackle SSO, though.) For the purposes of demonstration and to appease my flipper-fixated editor, herein I write some tests against the open-source PinballMap.com REST API, which lets you access a crowdsourced map of public pinball machines.

To start, fire up Postman. Once the application is launched, we can prevent long-term headaches by creating an environment. An environment is a way to specify a bunch of attributes; you can easily change those attributes and settings by switching from one environment to another. This is handy when you need to switch among development, testing, and production endpoints with the same test suite. Rather than duplicating all the tests with three different endpoints, you can define a “host” variable with different values for each platform you test.

In this case, we only know the URL for the production endpoint, but let’s use an environment anyway to show how it’s done.

After we add this environment, the variable called “host” is available whenever this environment is selected. If we had other tiers to test against, we could create a “dev” or “test” environment using a different value.

Once the environment is squared away, it’s time to create a collection. Collections are groups of requests that you can string together into a suite of tests, passing values between them.

Collections can have their own variables. So, for example, you could define the common portion of the API URL in a variable and use it in requests. This can be handy if, say, your REST API incorporates a version number (as Pinball.com does). Put in the version number as a variable; when the API is bumped a version, you can test against the new one by changing the version in one place, rather than in every request.

Another nice feature of Postman is that you can define a collection’s authorization mechanism; then, whatever authentication you choose is carried over onto all the requests you make.

With our environment and collection set up, we’re finally ready to write some requests. We start by requesting a list of all the regions where there is pinball table data.

We include that “host” variable in the URL for the request, which is replaced with the value defined by our selected environment. When we send the request, we get back a boatload of data in JSON format, which Postman nicely pretty-prints for us. (You can get the raw view as well, should you want it.)

But we don’t just want to fetch the data. We want to test it, and we want to extract values to use for subsequent calls. That duty is fulfilled by the “Tests” tab, where you can plop in JavaScript. In this case, I wrote a simple status code sanity test and a piece of code to pull out the region name of the first record and put it in a variable.

pm.test("Status code is 200", function () {
    pm.response.to.have.status(200);
});

let jsonData = pm.response.json()

postman.collectionVariables.set('regionname', jsonData.regions[0].name)

The JSON tree can be walked the same way you’d access JSON data in any other JavaScript code.

You have a choice of scopes for your variables. In this case, we save it at the collection level, which means that it’s available to any other request in the collection. You can also save it as an environment variable, globally, or as even a temporary variable only available during the current test run. (The latter has the disadvantage that you can’t use it if you run the requests one by one, but it’s nice to know about.)

Now that we have a region name, we can get a list of all the locations in that region (which includes the tables available in that location). The URL for that request is:

/api/v1/region/:region/locations.json

To replace the “:region” segment with the region name we got from the first request, we create a new request with the URL:

{{host}}/api/v1/region/{{regionname}}/locations.json

The {{host}} portion is replaced with the variable we defined in our environment. The {{regionname}} comes out of the collection variable set in the previous request.

That’s the start. You can continue to write further tests, exploring the JSON data and validating results. One critical thing to remember is that because we’re querying a live database, values can change over time. Your tests shouldn’t assume that any particular record will be returned as the results of a request. You should also remember that if you play the Pirates of the Caribbean machine at Antonio’s Pizza & Pasta in Buelton, CA, it has a very weak left flipper.

Selenium is super-powerful – but it has its weaknesses, too. This white paper explores the primary reasons Selenium tests fail.

James Turner

by James Turner

James Turner is a developer with over 40 years of experience spanning technologies from LISP Machines and Z80 assembly language to Docker, Swift, and Java. He is the author of two books on Java development and one on iOS enterprise development. He lives in Southern New Hampshire along with his wife and son, and is currently developing mobile applications for a Fortune 50 company.