Skip to content

How can I visualize an API mashup in Postman?

I have a REST API of classical actors that I want to visualize in Postman. The image URL of an actor is not in the API, so I will need to create a mashup from a combination of the core API and another API.

1. Prerequisites

The core API/endpoint is at http://henke.atwebpages.com/postman/actors/actors.json:

{
  "area": {
    "name": "United States",
    "type": null
  },
  "release-groups": [
    {
      "primary-type": "Actor",
      "fullname": "Katharine Hepburn",
      "id": "Q56016",
      "born": "1907"
    },
    {
      "primary-type": "Actor",
      "fullname": "Humphrey Bogart",
      "id": "Q16390",
      "born": "1899"
    }
  ],
  "country": "US",
  "name": "Classical Actors",
  "life-span": {
    "begin": "1899",
    "ended": true,
    "end": "2003"
  }
}

The image URLs of Katharine Hepburn and Humphrey Bogart are at:
http://henke.atwebpages.com/postman/actors/coverart/Q56016.json and
http://henke.atwebpages.com/postman/actors/coverart/Q16390.json, respectively.

The corresponding JSONS, Katharine Hepburn:

{
  "images": [
    {
      "front": true,
      "thumbnails": {
        "small": "https://upload.wiki [...] 220px-Tom_cruise_1989.jpg",
        "large": "https://upload.wiki [...] -TomCruiseDec08MTV_cropped.jpg"
      },
      "back": false,
      "edit": 18084161
    },
    {
      "back": true,
      "edit": 39938947,
      "front": false,
      "thumbnails": {
        "small": "https://upload.wiki [...] -Katharine_Hepburn_promo_pic.jpg",
        "large": "https://upload.wiki [...] Tom_Cruise_by_Gage_Skidmore_2.jpg"
      }
    }
  ]
}

and Humphrey Bogart:

{
  "images": [
    {
      "edit": 40403385,
      "back": true,
      "thumbnails": {
        "small": "https://upload.wiki [...] 220px-Humphrey_Bogart_1940.jpg",
        "large": "https://upload.wiki [...] px-TomCruiseByIanMorris2010.jpg"
      },
      "front": false
    },
    {
      "edit": 40403384,
      "back": false,
      "thumbnails": {
        "small": "https://upload.wiki [...] 220px-Tom_cruise_1989.jpg",
        "large": "https://upload.wiki [...] -TomCruiseDec08MTV_cropped.jpg"
      },
      "front": true
    }
  ]
}

where I have truncated the links of the images for better readability.

Note in the core API how each object/person has a unique id (Q56016 for Katharine Hepburn and Q16390 for Humphrey Bogart) and a fullname. The other endpoints have – for each object in the release-groups array of the core API – the same unique identifier, along with a link to an image/portrait. Thus, information from all three endpoints is needed to list each actor with a matching image.

2. The desired resulting mashup

Obviously, the problem is solved if the data in the APIs can be combined together in such a way that – for each identifier – both the name and the image link are supplied:

[
  {
    "name": "Katharine Hepburn",
    "image": "https://upload.wiki [...] -Katharine_Hepburn_promo_pic.jpg"
  },
  {
    "name": "Humphrey Bogart",
    "image": "https://upload.wiki [...] 220px-Humphrey_Bogart_1940.jpg"
  }
]

Then it remains to visualize the data in Postman.

3. Methodology

I will write all code in a single Tests script of a Postman request. That request is just a dummy that serves no other purpose than to start running the Tests script.

To construct the mashup and then display the result, it would be convenient to use the well-known Fetch API and then get the images by using Promise.all.

One caveat is that Postman does not implement the Fetch API.
But luckily there is an answer that explains how to mimic the fetch() command in Postman.
It can be done as follows:

function fetch (url) {
  return new Promise((resolve, reject) => {
    pm.sendRequest(url, function (_, fetchResponse) {
      resolve(fetchResponse);
    });
  });
} // ^^ No Fetch API in Postman! But see https://stackoverflow.com/a/67588692

Since this fetch() function returns a promise, it should (hopefully) work the same way as fetch() in any modern web browser.

The rest of the Tests section should construct the result. Note how Promise.all needs to be chained/nested with the first request fetch(urlOuter) – because it needs data from it.
This is analogous to the second Stack Snippet of this answer.
Finally, the result should be visualized: 1

const lock = setTimeout(() => {}, 43210);
const fullnames = [];
const urls = [];
const urlOuter = 'http://henke.atwebpages.com/postman/actors/actors.json';
fetch(urlOuter).then(responseO => responseO.json()).then(responseBodyO => {
  const tblHeader = responseBodyO.name;
  const actors = responseBodyO['release-groups'];
  for (const item of actors) {
    fullnames.push(item.fullname);
    urls.push('http://henke.atwebpages.com/postman/actors/coverart/' +
        item.id + '.json');
  }
  return Promise.all(urls.map(url => fetch(url)
    .then(responseI => responseI.json())
    .then(responseBodyI => responseBodyI.images.find(obj =>
      obj.back === true).thumbnails.small)))
    .then(imageURLs => {
      clearTimeout(lock); // Unlock the timeout.
      const actorNames = fullnames.map(value => ({ name: value }));
      const actorImages = imageURLs.map(value => ({ image: value }));
      const actorsAndImages = actorNames.map(
        (item, i) => Object.assign({}, item, actorImages[i]));
      console.log('actorsAndImages:n' + JSON.stringify(actorsAndImages));
      const template = `<table>
        <tr><th>` + tblHeader + `</th></tr>
        {{#each responseI}}
        <tr><td>{{name}}<br><img src="{{image}}"></td></tr>
        {{/each}}
      </table>`;
      pm.visualizer.set(template, { responseI: actorsAndImages });
    });
}).catch(_ => {
  console.error('Failed to fetch - ' + urlOuter);
});

In Postman:

Mashup Tests script in Postman

4. Does it work?

So does it work? – The answer is both yes and no.

  • On the good side, I could create the desired JSON mashup result as in section 2 above.
  • On the bad side, the visualization fails:

Result of Promise.all in Postman

The message Set up the visualizer for this request is typical when the call to pm.visualizer.set() has been forgotten. But I did not forget it. So what is wrong?

5. How to replicate my attempt in Postman

Replicating my attempt in Postman should be straightforward.
Assuming you are using the desktop version of Postman, do as follows:

  1. Download and save
    http://henke.atwebpages.com/postman/actors/Promise.all-Actors.pm_coll.json
    in a suitable place on your hard drive.

  2. In Postman, Ctrl + O > Upload Files > Promise.all-Actors.pm_coll.json > Import.
    You should now see Promise.all-Actors among your collections in Postman.

  3. Collections > Promise.all-Actors > DummyRequest > Send.

  4. In the Postman Response Body, click Visualize.

  5. Done! – If everything worked as intended, you should now see the output as above.

References


1 Don’t get confused by the lines const lock = setTimeout(() => {}, 43210); and clearTimeout(lock);. – Their only purpose is to serve as a workaround for a known bug.

Answer

The message Set up the visualizer for this request is typical when the call to pm.visualizer.set() has been forgotten. But I did not forget it. So what is wrong?

As already touched upon, the problem is that Postman does not natively support promises. 1
What does that mean? – Well, apparently it means that a function such as pm.visualizer.set() cannot be called from within the callback of a Promise. It has to be called from within the callback of pm.sendRequest(). Note that by the construction of the fetch() function the corresponding Promise is actually outside of the pm.sendRequest() callback!

1. Achieving the desired result and visualizing it

In other words, you need to replace all occurrences of fetch() with pm.sendRequest().
You also need to implement your own version of Promise.all, since it relies upon promises, something you don’t have in a native Postman script.
Fortunately, such an implementation was posted in an answer the day before yesterday.

After making those changes, here is the code for the Tests section, starting with the initializations: 2

const lock = setTimeout(() => {}, 43210);
const fullnames = [];
const urls = [];
const urlOuter = 'http://henke.atwebpages.com/postman/actors/actors.json';

The main part – slightly unconventionally formatted – to avoid vertical scrolling:

pm.sendRequest(urlOuter, (_, responseO) => {
  const tblHeader = responseO.json().name;
  const actors = responseO.json()['release-groups'];
  for (const item of actors) {
    fullnames.push(item.fullname);
    urls.push('http://henke.atwebpages.com/postman/actors/coverart/' +
        item.id + '.json'); }
  const images = [];
  let countDown = urls.length;
  urls.forEach((url, index) => {
    asynchronousCall(url, imageURL => {
      images[index] = imageURL;
      if (--countDown === 0) { // Callback for ALL starts on next line.
        clearTimeout(lock); // Unlock the timeout.
        const actorNames = fullnames.map(value => ({ name: value }));
        const actorImages = images.map(value => ({ image: value }));
        const actorsAndImages = actorNames.map(
          (item, i) => Object.assign({}, item, actorImages[i]));
        console.log('actorsAndImages:n' + JSON.stringify(actorsAndImages));
        const template = `<table>
          <tr><th>` + tblHeader + `</th></tr>
          {{#each responseI}}
          <tr><td>{{name}}<br><img src="{{image}}"></td></tr>
          {{/each}}
        </table>`;
        pm.visualizer.set(template, { responseI: actorsAndImages });
      }
    });
  });
  function asynchronousCall (url, callback) {
    pm.sendRequest(url, (_, responseI) => {
      callback(responseI.json().images.find(obj => obj.back === true)
        .thumbnails.small); // Individual callback.
    }); } });

In Postman:

Mashup Tests script in Postman

2. Does it work?

Yes! – It works:

Result of Promise.all in Postman

3. How to replicate my solution in Postman

Assuming you are using the desktop version of Postman, do as follows:

  1. Download and save
    http://henke.atwebpages.com/postman/actors/Actors.pm_coll.json
    in a suitable place on your hard drive.

  2. In Postman, Ctrl + O > Upload Files > Actors.pm_coll.json > Import.

  3. Collections > Actors > DummyRequest > Send.

  4. In the Postman Response Body, click Visualize.

  5. Done! – You should now see the output as above.

References


1 I hope Postman will support promises in a future version.
2 Again, don’t get confused by the lines const lock = setTimeout(() => {}, 43210); and clearTimeout(lock);. – Their only purpose is to serve as a workaround for a known bug.