Skip to main content

SSJS Script Template

Jumpstart your coding with best practice fueled SSJS Template.

Some like to start with a blank slate. Some - from a well-crafted template. I'm in the #TeamTemplate, and here you can see my SSJS one. Check the bottom of this page for a walkthrough.

SSJS Template Code#

<script runat='server'>    /* -------------------------------------------------------------------------
    Short description of the purpose of the script.
    1. Global Variables    1.1. API Endpoint    1.2. Error Handling    2. Helper Functions    2.1. Debugging    2.2. Error handling    3. {{Section Name}}    ...
    -------------------------------------------------------------------------- */
    Platform.Load('core', '1');    // Uncomment below if you will be using SOAP API via WSProxy in the script    // var soap = new Script.Util.WSProxy();
    /* ----------------------------------------------------------------------- */    /* ---------------------- 1. GLOBAL VARIABLES ---------------------------- */    /* ----------------------------------------------------------------------- */
    var endpoint, headerNames, headerValues, payload, response, parsedResponse;    var debugging = false;
    /* ---------------------- 1.1. API Endpoint------------------------------- */    var clientID = 'CLIENT_ID';    var clientSecret = 'CLIENT_SECRET';    var clientBase = 'API_BASE_URI';
    /* -------------------- 1.2. Error Handling------------------------------- */    var scriptName = 'SCRIPT_NAME';    var errorDE = 'ERROR_DATA_EXTENSION';    var errorURL = 'ERROR_CLOUD_PAGE_URL';
    /* ----------------------------------------------------------------------- */    /* ---------------------- 2. HELPER FUNCTIONS ---------------------------- */    /* ----------------------------------------------------------------------- */
    /* ---------------------- 2.1. Debugging --------------------------------- */
    /**    * @function debugValue    * @description Outputs provided description and SSJS value to front-end in a type-safe & consistent way    * @param {string} description - Describes meaning of the second parameter in the output    * @param {*} value - The value that needs to be debugged    */    function debugValue(description, value) {        Write(description + ': ' + (typeof value == 'object' ? Stringify(value) : value) + '<br><br>');    };
    /* ---------------------- 2.2. Error handling ---------------------------- */
    /**    * @function handleError    * @description Adds the error with context to error logging Data Extension and redirects to error page.    * @param {Object} error - The caught error object. Can come from the try/catch block or be manually created.    * @param {string} error.message - First error key stores short error message describing the issue.    * @param {string} error.description - Second error key stores detailed error path helping with root cause analysis    */    function handleError(error) {        if (debugging) {            debugValue('Found error', error);        } else {            // Remember that if your Logging Data Extension is in Shared Folder, you need to add the "ENT." prefix to name            Platform.Function.InsertData(errorDE, ['ID', 'ScriptName', 'ErrorMessage', 'ErrorDescription'], [GUID(), scriptName, error.message, error.description]);            Platform.Response.Redirect(errorURL + '?error=' + error.message + '&error_description=' + error.description);        };    };
    try {    /* ----------------------------------------------------------------------- */    /* ----------------------- 3. {{SECTION NAME}} --------------------------- */    /* ----------------------------------------------------------------------- */
    /**    * There can be just one section for simpler scripts, or there can be multiple.    * As your code grow, split it into separate numbered sections for easier navigation.    * Always try to make each section coherent with code logic to make the split meaningful.    */
    // if (debugging) debugValue('{{API Call Name}} Response', response);
    } catch (error) {        handleError(error);    }
</script>

SSJS Template Description#

Table of Contents#

    /* -------------------------------------------------------------------------
    Short description of the purpose of the script.
    1. Global Variables    1.1. API Endpoint    1.2. Error Handling    2. Helper Functions    2.1. Debugging    2.2. Error handling    3. {{Section Name}}    ...
    -------------------------------------------------------------------------- */

The opening section of the template does two things:

  1. Briefly informs everyone what the purpose of this script is
  2. Describes the high-level structure of the script to allow for quick navigation

Read more on that approach in my SSJS Style Guide.

Global Variables#

    /* ----------------------------------------------------------------------- */    /* ---------------------- 1. GLOBAL VARIABLES ---------------------------- */    /* ----------------------------------------------------------------------- */
    var endpoint, headerNames, headerValues, payload, response, parsedResponse;    var debugging = false;
    /* ---------------------- 1.1. API Endpoint------------------------------- */    var clientID = 'CLIENT_ID';    var clientSecret = 'CLIENT_SECRET';    var clientBase = 'API_BASE_URI';
    /* -------------------- 1.2. Error Handling------------------------------- */    var scriptName = 'SCRIPT_NAME';    var errorDE = 'ERROR_DATA_EXTENSION';    var errorURL = 'ERROR_CLOUD_PAGE_URL';

This section is responsible for storing all key variables. There are two main types I like to keep here:

Multiuse empty variables#

var endpoint, headerNames, headerValues, payload, response, parsedResponse;

In this category, you will find variables used multiple times within various parts of the script, but their specific values have too short lifespan to warrant a separate variable.

By declaring them here, I don't have to use var later in the script, and therefore I don't have to worry about the order of the code if I make some changes during the refactoring phase.

There is also a second reason - defining them before the try/catch block, even without any value, will allow accessing its value after that block. Read more about that in Debugging & Error Handling.

Customizable variables#

    var debugging = false;
    /* ---------------------- 1.1. API Endpoint------------------------------- */    var clientID = 'CLIENT_ID';    var clientSecret = 'CLIENT_SECRET';    var clientBase = 'API_BASE_URI';
    /* -------------------- 1.2. Error Handling------------------------------- */    var scriptName = 'SCRIPT_NAME';    var errorDE = 'ERROR_DATA_EXTENSION';    var errorURL = 'ERROR_CLOUD_PAGE_URL';

The second type I store here are customizable global variables:

  • changing from script to script or
  • controlling the script's behaviour (like configurational ones or the debugging variable described in detail here)

The template contains the API Endpoint section that I frequently use, but if your script does not need it - delete it to optimize and simplify the code.

Helper Functions#

    /* ----------------------------------------------------------------------- */    /* ---------------------- 2. HELPER FUNCTIONS ---------------------------- */    /* ----------------------------------------------------------------------- */
    /* ---------------------- 2.1. Debugging --------------------------------- */
    /**    * @function debugValue    * @description Outputs provided description and SSJS value to front-end in a type-safe & consistent way    * @param {string} description - Describes meaning of the second parameter in the output    * @param {*} value - The value that needs to be debugged    */    function debugValue(description, value) {        Write(description + ': ' + (typeof value == 'object' ? Stringify(value) : value) + '<br><br>');    };
    /* ---------------------- 2.2. Error handling ---------------------------- */
    /**    * @function handleError    * @description Adds the error with context to error logging Data Extension and redirects to error page.    * @param {Object} error - The caught error object. Can come from the try/catch block or be manually created.    * @param {string} error.message - First error key stores short error message describing the issue.    * @param {string} error.description - Second error key stores detailed error path helping with root cause analysis    */    function handleError(error) {        if (debugging) {            debugValue('Found error', error);        } else {            // Remember that if your Logging Data Extension is in Shared Folder, you need to add the "ENT." prefix to name            Platform.Function.InsertData(errorDE, ['ID', 'ScriptName', 'ErrorMessage', 'ErrorDescription'], [GUID(), scriptName, error.message, error.description]);            Platform.Response.Redirect(errorURL + '?error=' + error.message + '&error_description=' + error.description);        };    };

In this section, I keep all the helper functions used multiple times in the script or are battle-tested and shared across various scripts.

In the template, you can find my two favourite ones that I use in every single script.

To learn more about them, check out detailed descriptions of debugValue and handleError functions.

You Should Know

If the script will be used in JSON Code Resource backend I modify those two functions a bit by:

  1. Changing the debugValue Write to: Write(' --- ' + description + ': ' + (typeof value == 'object' ? Stringify(value) : value) + ' --- '); as break line tag will not work.

  2. Removing the Platform.Response.Redirect from handleError as we don't want backend redirects. The errorURL variable follows suit.

In many cross-cloud scenarios I also use AMPScript runner, but as it is more use case specific solution, I don't keep it in base template.

I prefix all functions with documentation comments.

Script Body#

    try {    /* ----------------------------------------------------------------------- */    /* ----------------------- 3. {{SECTION NAME}} --------------------------- */    /* ----------------------------------------------------------------------- */
    /**    * There can be just one section for simpler scripts, or there can be multiple.    * As your code grow, split it into separate numbered sections for easier navigation.    * Always try to make each section coherent with code logic to make the split meaningful.    */
    } catch (error) {        handleError(error);    }

The final part of the template is where I'm adding the main part of the script. It's wrapped in try/catch (more on that here) and - if the script is long - split into sections.