Skip to content

Zambion Example

The code below is an example of a process connecting to Zambion. Zambion authenticates using the OAuth 2.0 client credentials grant against its own token endpoint rather than MODLR's built-in OAuth 2.0 flow, so this is an Advanced Integration.

INFO

This process requires a Zambion client ID and secret, stored as Secrets rather than hardcoded in the process.

Library Code

A small client for the Zambion API, handling authentication (requesting and refreshing an access token) and wrapping authenticated GET requests. Save this as a Process Library and load it with script.library.

js
function ZambionApi(clientId, secret, scope = "api1") {
    this.baseUrl = "https://api2.zambion.com/api/SecuredApi/";
    this.authUrl = "https://oauth.zambion.com/connect/token";
    this.clientId = clientId;
    this.secret = secret;
    this.scope = scope;

    this.accessToken = null;
    this.accessTokenExpiry = null;

    this.login = function () {
        this.accessToken = this.getAccessToken();
    };

    this.getAccessToken = function () {
        const body = `grant_type=client_credentials&client_id=${this.clientId}&client_secret=${this.secret}&scope=${this.scope}`;
        const response = web.post(this.authUrl, { "Content-Type": "application/x-www-form-urlencoded" }, body);

        if (response.status >= 200 && response.status < 300) {
            const tokenData = JSON.parse(response.body);
            // Refresh a little early so we never use a token that's about to expire mid-request.
            this.accessTokenExpiry = new Date(new Date().getTime() + (tokenData.expires_in * 1000) - 100000);
            return tokenData.access_token;
        } else if (response.error) {
            console.log(`Error occurred while authenticating with ${this.authUrl}: ${response.error}`);
            return null;
        } else {
            console.log(`Failed to authenticate with ${this.authUrl}, status code: ${response.status}.`);
            return null;
        }
    };

    this.ensureAccessToken = function () {
        if (!this.accessToken || new Date() > this.accessTokenExpiry) {
            this.accessToken = this.getAccessToken();
        }
    };

    this.getRequest = function (endpoint, parameters = []) {
        this.ensureAccessToken();

        const params = parameters.map(param => {
            const key = Object.keys(param)[0];
            return param[key] === "" ? key : `${key}=${param[key]}`;
        });

        let url = this.baseUrl + endpoint;
        if (params.length > 0) {
            url += `?${params.join("&")}`;
        }

        const response = web.get(url, { "Authorization": `Bearer ${this.accessToken}` });

        if (response.status >= 200 && response.status < 300) {
            return JSON.parse(response.body);
        } else if (response.error) {
            console.log(`Error occurred while requesting ${url}: ${response.error}`);
            return null;
        } else {
            console.log(`Failed request to ${url}, status code: ${response.status}.`);
            return null;
        }
    };

    this.login();

    return this;
}

Process Code

This example pulls the Zambion StaffList endpoint and logs the result.

js
script.library("libraries/zambionapi.js");

function pre() {
    // This function is called once before the process is executed.
    // Use this to setup prompts.
    script.log('process pre-execution parameters parsed.');
}

function begin() {
    // This function is called once at the start of the process
    script.log('process execution started.');

    const api = new ZambionApi(security.getSecret("ZAMBION_CLIENT_ID"), security.getSecret("ZAMBION_CLIENT_SECRET"));
    const staff = api.getRequest("StaffList");

    if (!staff) {
        return;
    }

    console.log(`Staff returned: ${staff.length}`);
    console.log(staff);
}

function data(record) {
    // This function is called once for each line of data on the second cycle
    // Use this to build dimensions and push data into cubes
}

function end() {
    // This function is called once at the end of the process
    script.log('process execution finished.');
}