Skip to content

Instantly share code, notes, and snippets.

@erhhung
Created April 4, 2022 18:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erhhung/4d8884c014350364791587425259c8ea to your computer and use it in GitHub Desktop.
Save erhhung/4d8884c014350364791587425259c8ea to your computer and use it in GitHub Desktop.
Load external modules in Postman

This document describes one way to load external JavaScript modules into Postman pre-request or test scripts to augment the functionality of your own scripts.

In the collection pre-request script, export common utility functions (feel free to add additional functions for your own use case as this is a common technique for sharing code among individual requests):

// get latest version
_ = require('lodash');

// export common utility functions
pm.globals.set('util', String(() => ({

    // use the open interval hack to wait until async
    // operations are done before sending the request
    // in a pre-request script
    waitUntilDone(promise) {
        const wait = setInterval(() => {}, 300000);
        promise.finally(() => clearInterval(wait));
    },

    // promisified pm.sendRequest()
    sendRequest(req) {
        return new Promise(
            (resolve, reject) => pm.sendRequest(req, (err, res) => {
                if (!err && res.code / 100 < 4) return resolve(res);
                let message = `Request "${req.url||req}" failed (${res.code})`;
                if (err?.message) message += `: ${err.message}`;
                reject({message});
            }));
    },

    // load external library modules in order,
    // then return this[thisProp] or just this
    async loadModules(urls, thisProp=undefined) {
        const thisKeys = Object.keys(this);
        (await Promise.all(urls.map(this.sendRequest)))
            .forEach(res => eval(res.text()));

        const thisObj = _.omit(this, thisKeys);
        //console.log('KEYS: this', Object.keys(thisObj));
        return !thisProp && thisObj || thisObj[thisProp];
    },

    decodeJWT(jwt) {
        // return both header and claims
        return jwt?.split('.').slice(0, 2)
            .reduce((claims, encoded) => {
                const buf   = Buffer.from(encoded, 'base64');
                const props = JSON.parse(buf.toString('utf8'));
                return Object.assign(claims, props);
            }, {})
            || {};
    },
})));

Then, in the pre-request script of some request in the same collection, load modules that you need in an async manner (the sample code below loads moment.js; it should work equally well for other JavaScript modules that are distributed via CDN):

const util   = eval(pm.globals.get('util'))();
const vars   = pm.variables;
const coVars = pm.collectionVariables;

// this isn't important... just some sample code.
const jwt = util.decodeJWT(vars.get('app_token'));

util.waitUntilDone((async () => {

    const [
        {rat},    // get "revoked_at" in first API call
        {moment}, // load "moment.js" JavaScript modules
    ] = await Promise.all([

        util.sendRequest({
            url: `${vars.get('my_api_url')}/apps/${jwt.sub}/tokens/${jwt.jti}`,
            header: {
                Authorization: `Bearer ${vars.get('superuser_token')}`,
            },
        })
        .then(res => res.json())
        .catch(err => ({})),

        util.loadModules([
            'https://momentjs.com/downloads/moment.min.js',
            'https://momentjs.com/downloads/moment-timezone-with-data.min.js',
        ]),
    ]);

    // use "moment" as it's now loaded
    const tsToDate = ts => {
        const date = new Date(ts);
        let   str  = moment(date).format('L hh:mm:ss A');
        const tz   = moment.tz(date, moment.tz.guess());
        const dur  = moment.duration(date - new Date());
        return `${str} ${tz.zoneAbbr()} (${dur.humanize(true)})`;
    };

    vars.set('iat', tsToDate(jwt.iat));
    vars.set('exp', tsToDate(jwt.exp));
    vars.set('rat', tsToDate(rat));

})());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment