Skip to content

ProcurePro Example

The code below is an example of a process connecting to ProcurePro. ProcurePro authenticates with a static access token passed as a query parameter rather than through MODLR's built-in OAuth 2.0 flow, so this is an Advanced Integration.

INFO

This process requires a ProcurePro access token, stored as a Secret rather than hardcoded in the process.

Library Code

A small client for the ProcurePro API. Save this as a Process Library and load it with script.library.

js
class ProcurePro {

    constructor(token) {
        this.token = token;
        this.baseUrl = "https://app.procurepro.co/external/api/customer-bi/v1/";
        this.debug = false;
    }

    enableDebug(debug) {
        this.debug = debug;
    }

    request(method, path, headers = {}, body = {}) {
        const fullUrl = this.buildUrl(path);

        const requestHeaders = {
            "Accept": "application/json",
            ...headers
        };

        const response = web.request(method, fullUrl, requestHeaders, body, false);

        if (this.debug) {
            console.log(`[DEBUG] ${fullUrl}: ${response.status}`);
        }

        if (response.status >= 200 && response.status < 300) {
            return JSON.parse(response.body);
        }

        if (response.status === 429) {
            throw new Error("Rate limited by ProcurePro (HTTP 429).");
        } else if (response.error) {
            throw new Error(response.error);
        } else {
            throw new Error(`Unexpected response status: ${response.status}`);
        }
    }

    get(path, parameters = {}, headers = {}) {
        const queryString = this.buildQueryString(parameters);
        return this.request("GET", path + queryString, headers);
    }

    post(path, data, headers = {}) {
        return this.request("POST", path, headers, data);
    }

    buildQueryString(parameters) {
        if (Object.keys(parameters).length === 0) {
            return "";
        }

        return "?" + Object.entries(parameters)
            .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
            .join('&');
    }

    buildUrl(path) {
        const trimmedPath = path.startsWith("/") ? path.substring(1) : path;

        let fullUrl = `${this.baseUrl}${trimmedPath}`;

        const hasQueryString = fullUrl.includes("?");
        const separator = hasQueryString ? "&" : "?";

        fullUrl += `${separator}access_token=${encodeURIComponent(this.token)}`;
        return fullUrl;
    }
}

Process Code

js
script.library("api/procurepro.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 ProcurePro(security.getSecret("PROCUREPRO_ACCESS_TOKEN"));

    try {
        const projects = api.get("project.json");
        console.log(`Projects returned: ${projects.length}`);
        console.log(projects);
    } catch (e) {
        console.log("Something went wrong");
        console.log(e);
    }
}

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.');
}