Hi, casual Postman user here
TL;DR: I have an API request which, as its result, has some parameters to call a second API request. The parameters are pushed to a scope visible by both. How do I call another request outside a Collection Run from the post-request code?
The only solutions I’m aware of are:
- Place the two API requests on a single folder or even in a single collection, and run them in order.
- Forget the second request, just use
fetch()
from within the post-request code.
None are really acceptable, for the reasons below
[Full question text takes about 8 minutes reading time]
Disclaimer: By “casual user” I mean that Postman is not my primary tool for calling APIs, doing testing, and so forth. However, it’s incredibly useful for simple API testing, without much fuss. In other words: I use Postman as a glorified version of cURL. It’s neater, it has lots of bells and whistles, it does a little more hand-holding (and error checking!), and, of course, it persists everything forever on the cloud (unlike quick-and-dirty shell scripts which get ‘lost’ easily enough…).
After the disclaimer, here is my issue. I would love to be able to chain together just two simple isolated requests, or possibly more, picked out of a pool of possibilities. I do not want to write endless duplicated collections, one for each sequence. I do not even need to do a very complex, data-driven, automated testing solution, like it’s shown on this thread and a few other besides that. Most involve a much more complex testing environment than what I need; I’m also using very basic APIs with a reduced set of possible requests.
Suppose that there are, say, only 6 possible requests for a particular credits-based API, named A, B, C, D, E, and F. However, some have an implicit dependency — part of the returned data from the first request are parameters to pass to the next request, which will be sequentially called. At the end, let’s say, F, will almost always be called, which essentially returns how much credits are still left after the others have been called (F, by itself, doesn’t ‘consume’ credits, but abusing the system by making unnecessary requests is frowned upon).
This API essentially contacts a remote facility to process images. The first request, let’s call it A, sends the image as raw binary data, and possibly some extra parameters to let the system know what kind of image processing is desired. The response will include some metadata on the image (or an error) and a different API endpoint, from where the processed image can be downloaded — on a separate request.
So, in this scenario, A gets called with a payload for remote processing, and the response includes some data (usually a GUID of some sort) to retrieve the processed image using the request C. Calling C without any valid data (well, beyond authentication) will produce an error, so it does not make any sense to test C on its own. C is only important in the context of having previously called A (and, of course, there is a timeout — after some hours, the images will be deleted from the servers — both the raw, unprocessed image as well as the process).
From the perspective of a simple, manual test, one presses Send
for making a request to A (after selecting a file for upload), and it returns the image ID. This gets extracted from its JSON container and stored into a Postman variable, in an accessible scope for the collection.
Then, the human operator can manually launch C. C relies upon that Postman variable in scope to have a valid ID. If that isn’t the case (checked on the pre-processing script), well, then it throws an error and aborts. But if the variable is set and looks plausible (it has the expected format), then C is invoked. This time, the body of the response will include the processed file, which the manual operator can then save locally at will. All of that is pretty straightforward and doesn’t require a huge amount of knowledge (or I woudn’t be able to do it).
You might ask… what about B? Why did I skip it?
Well, B is a separate entry point. Here, instead of sending the payload as part of the request, you send an URL to the image you wish to process, which has presumably be placed on a public repository of some sort. While the request for B is quite different — now it uses JSON in its body, as opposed to a raw image — it nevertheless returns exactly the same kind of response as in the case of the A → C sequence: the remote system will, again, reply with some metadata and the processed image ID.
From the perspective of the system invoking the request, the response from B is absolutely identical to the response from A. In Postman, there seems not to be a way of somehow storing the post-processing code separately from the individual requests (more on that later), so wha I did was to duplicate A and just change the body to be sent. The rest is identical — duplicated code, which I hate, but it seems to be the only way to do it (or maybe not…).
So, now I have two mini-workflows, with clearly defined sequences.:
A → C
B → C
Now, for such a basic scenario, one might argue that the collection is so simple that all I could do is to place A, B, and C (and possibly F, which will run afterwards to show how many credits have been ‘consumed’ so far) in the same Collection, and just run them in sequence. But you see where the problem is: A must invoke C immediately after it receives a response. B might be called after A, or in parallel via A, or even before A, so long as it calls C independently. My naïve approach of storing the image ID in a variable in scope will thus have dramatic consequences from potential race conditions.
Still, I believe that, by very carefully checking for the proper sequence (and using setNextRequest()
as intended, it might be possible to use the Collection Runner.
Since at the end of the request, the user very likely will want to know how many credits are left, presumably request F will follow either one of them:
A → C → F
B → C → F
Now, let’s tackle D and E. These are ‘variants’ of… A, B, and C. In other words: in some cases, after invoking C, there might be additional imaging data to be retrieved, e. g., there might be more than one image available — such as images in different sizes and formats, downloaded separately via different requests at different hierarchical levels. Or the file format requested for the final image might be different than the original one. Or the image original might get called in a completely different way. In fact, it’s even possible to ‘chain back’ the response (since it contains a valid URL, after all) in order to select a different tool in the chain:
A → C → D → E → F
B → E → F
…
and so forth.
While the multiple options for the next request might be programatically defined (as seen
on the quoted issue, above), and such ‘programming’ can conceivably replace the usual flow of a Collection Run by a custom-made one, I don’t quite see how multiple, unrelated sequences of workflows can be accomplished without either
- creating multiple collections and/or folders, each with its own sequence, thus requiring duplicating requests over and over again in each collection/folder; or
- writing your own workflow system (again, as can be seen in the linked thread above).
Neither is an acceptable solution for me. In the first scenario, dealing with several duplicates which quickly get out of sync is a painful mess, to be avoided; in the second scenario, I would just like to point out that it defeats the purpose of using Postman at all. I could simply stick to good, old shell scripts with cURL calls (or do something fancy in Go), instead of spending time tinkering with Postman’s programming capabilities so that, well, Postman behaves un-Postman-y — which would ultimately make no sense at all.
I’m also aware that you can have collection-wide functions (and possibly folder-wide too?), which, however, will be run for every request in the collection. Obviously, each request can run just a conditional branch in a function which handles the possible cases. In other words, instead of having per-request pre- and post-processing scripts, there would be just one, collection-wide, which would set up everything properly for each request. While I sort of dislike that approach (again, I’m reminded of shell scripts calling cURL…), it seems doable.
Another possibility would be to consolidate some of the requests which are sufficiently similar into a single one. Consider the two very similar workflows, A → C → F
and B → C → F. In my use case, A and B essentially only differ in the way the image is sent for processing: in A, it’s a raw file as payload; in B, it’s an URL instead. You could have a combined request, AB, which would check for the presence of a raw payload and tweak parameters so that A is called; else, it would check for the presence of a JSON body with a link to an image, and behave as B; if none were preset, it would simply just abort with an error.
This is feasible for those (few) cases when the difference in requests is mostly due to different parameters, the rest (including the actual API request) remaining essentially the same (including the rsponse!). Thus, the ambiguous A→ C → F
and B → C → F would be replaced with a single folder for AB → C → F instead. That might work, with proper documentation on how AB is used in practice. It might be harder to incorporate D, E and others, which have much more complex relationships. But it’s a possibility. Another advantage with this approach is keeping the request descriptions similar in Postman to what the actual API looks like.
And, of course, you can make fetch()
calls on the post-request code, to avoid having C completely. In essence, therefore, I would just have an ‘ABC’ request. It certainly works, even with some extra bells and whistles (having fetch()
properly wait until the request completes, and so forth), but… it’s hardly the ‘original API’ any more. Instead, it’s a mini-application on its own.
One might argue that the API I’m following is not necessarily a good example, breaking several good practice rules from ‘true’ REST. I would be the first to agree with that. However, most APIs I come across are relatively basic, very simple, and hardly ever follow ‘true’ REST or any similar fully documented API framework. Nevertheless, I need to test them out, and what attracts me most to Postman is the ease with which so many things are already pre-implemented ‘out of the box’, so you essentially focus only on getting the URLs right, pass the adequate parameters, and let Postman deal with the rest.
On the other hand, using the more advanced capabilities of Postman in order to create a fully-fledged application — a test suite, if you will — is a different usage of Postman, IMHO (as a casual user… remember?). Postman is a great proof-of-concept prototype builder. As a fully-fledged application framework… well, you can certainly use it that way. But it’s just not worth the time of essentially duplicating everything — on Postman and my own application — just to be sure that I got it right…
Perhaps there is something hidden deep in the documentation which I totally missed. Perhaps there is life beyond postman.setNextRequest()
. Perhaps there is really a much simpler way of chaining requests in an ad-hoc way — such as a hidden variable somewhere which can contain the name of a (chained) request (or its ID) which gets fired just after the
Any suggestions on how to think about Postman differently are welcome.
Additional Platform Details
Postman version 11.14.1
UI Version: 11.14.1-ui-240925-1856
Desktop Platform Version: 11.14.0 (11.14.0)
System version details for the client running Postman:
macOS Big Sur 11.7.9 (20G1426)