Scripting

Cyclr supports Javascript as its scripting language, allowing you to manipulate data before it’s sent as well as after it’s been retrieved. This can be useful when moving data between applications as what’s valid in one, may not be valid in another. Also, sometimes data just doesn’t quite “fit”.

Script can be used when building a Connector and on Steps in a Template or Cycle.

If you’re working on a Cycle in the Builder and need to perform a change to some data, click the Step Setup button on a Step then either use Inline Script in a Mapping for something simple, or expand the Advanced Settings area and enter some Script to tie in to Cyclr’s Events as described below.

For Inline Script, you must prefix the Javascript code with “=” (an equals sign), e.g.:

=(100 * 2)

or

=`[Mergefield]` === '' ? 'no value' : `[Mergefield]`;

It’s best to use ` characters (backticks) around string values being merged in as that will prevent carriage returns and the various quote characters from breaking your Script.

Events

Events are triggered at certain points allowing you to modify data. Script can be added at both the Connector and Method levels; Connector level event handlers will be called for all methods where as method level will only be called for that method. To add an event handler simply add a javascript function with the event name.

function eventName() {
    /* Handle event here */
}

before_webhook

Called when a webook request has been received and before anything else is done. Method is used to decide if the request should be continued or return a custom message to the caller.

Global objects
  • method_request: The webhook request body
  • method_request_headers: The webhook request headers
  • method_request_parameters: The webhook request parameters
  • method_endpoint: The webhook request URL
  • method_response: The response body for the request
  • method_response_headers: The response headers for the request
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true for the webhook to continue normal execution, false to stop execution of the request and send the response body/headers to the caller

after_webhook

Called after the webook has been caught.

Global object
  • method_response: object that was POSTed to the Cyclr webhook
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true for the webhook to continue normal execution, false to ignore the webhook request

before_action

Called before Cyclr makes a request to an external API.

Global objects
  • method_request: object the will be posted to the third party API
  • method_request_headers: HTTP headers for the request
  • method_request_parameters: Querystring parameters for the request
  • method_request_mergefields: mergefields for the request
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true to continue with the request to the third party API, false to abort the request (use throw for a more useful step error message)

after_action

Function is called when Cyclr has a response from an external API.

If a Method uses Paging, this function is called after each page is retrieved.

Global object
  • method_response: object that was received from the third party API. If the Method uses paging, this contains only the current page’s Response.
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true

after_action_paging

If this function is provided, it is called once after all pages of data have been retrieved, whether Paging has been implemented or not.

Global object
  • method_response: object that contains all of the Response data.
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true

after_error

Function is called when Cyclr received an error from an external API.

Global object
  • error_response: Details of the error, see : Handle Errors from Third Party APIs further down for more information on handling errors
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true

action_condition

Function is used to essentially combine a Method with a Decision Step, allowing a test to be performed that directs a Transaction down either the True or False exit points. Just by adding this function to a Step, Cyclr will add True and False exit points.

Global object
  • method_response: object that was received from the third party API.
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true for the Transaction to exit on the “True Route”, false to exit on the “False Route”

before_oauth2_authorise

Function is called before Cyclr makes an OAuth 2 authorise request.

Global object
  • method_endpoint: URL for the OAuth authorise endpoint
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true

before_oauth2_token

Called before Cyclr makes an OAuth 2 access token request.

Global object
  • method_request: Object that is going to be sent to the OAuth 2 access token endpoint
  • method_request_headers: HTTP headers for the request
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true

after_oauth2_token

Called after Cyclr makes an OAuth 2 access token request.

Global object
  • method_response: response object that was received from the OAuth 2 access token request
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true

before_oauth2_refresh

Called before Cyclr makes an OAuth 2 refresh token request.

Global object
  • method_request: request object that is going to be sent to the OAuth 2 refresh token request
  • method_request_headers: HTTP headers for the request
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true

after_oauth2_refresh

Called after Cyclr makes an OAuth 2 refresh token request.

Global object
  • method_response: response object that was received from the OAuth 2 refresh token request.
  • cycle_variables: Allows access to Cycle variables. Changes are not preserved.
  • return: true

Functions

http_request

Function to make external HTTP requests.

atob

Function to convert a Base64 encoded string to a string.

btoa

Function to convert a string to a Base64 string.

cyclr_sign

Function to sign a string.

For example,

var algorithm = 'HMAC-SHA1';
var signingKey = 'This is the signing key.';
var valueToSign = 'This is the string to sign.';

var signature = cyclr_sign(algorithm, signingKey, valueToSign);

Supported algorithms are: HMAC-SHA1, RSA-SHA1, RSA-SHA224, RSA-SHA256, RSA-SHA384, RSA-SHA512.

Exceptions

AuthSessionException

Exception to force the authentication session to be refreshed.

Upon getting this exception, Cyclr will call the Post Install Property Value Lookup Method to start a new session.

For example, an API returns 200 with an error code in the response when the session expires:

function after_action() {
    if (typeof method_response.error_code !== 'undefined' &&
        method_response.error_code === 'You are not logged on.') {
        throw new AuthSessionException();
    }
    return true;
}

If an API returns a non-2xx HTTP status code when the auth session expires, you should throw AuthSessionException in after_error:

function after_error() {
    if (method_error.statusCode.toString() == 403) {
        throw new AuthSessionException();
    }
    return true;
}

Libraries

Before calling any function from a library, please use require("Library Name");.

For example:

require("moment");

Moment.js

Library Name: moment

Description: Parse, validate, manipulate, and display dates and times in JavaScript.

External Documentation: https://momentjs.com/

CryptoJS

Library Name: crypto-js

Description: JavaScript library of crypto standards.

Warning: The output of encrypted data is always in a hex string. Formatting options CryptoJS.enc are not supported when calling toString.

External Documentation: https://github.com/brix/crypto-js

Connector scripting examples

Make External Requests

You can write a script to call external API endpoints. This is especially useful if the API returns a URL which contains the real response object.

For example, a webhook returns the following object to Cyclr:

{
    "event": "object.updated",
    "api_url": "http://httpbin.org/get"
}

Use http_request to call api_url and replace the webhook response with the updated object:

function after_webhook() {
    var request = {
        'method': 'GET',
        'url': method_response.api_url,
        'headers': {
            'Accept': 'application/json'
        }
    };

    var content = http_request(request).content;
    method_response = content;
    return true;
}

After calling api_url, Cyclr will then replace method_response with the content of the HTTP call.

Return false in the after_webhook function will stop Cyclr from running the webhook. You can use this trick to filter webhook events.

When calling the http_request function, you can specify the request using:

  • method: HTTP method, e.g. GET, POST, DELETE, PUT, etc.
  • url: URL for the HTTP request
  • parameters: Query string parameter
  • headers: HTTP headers
  • data: HTTP request data

Transform Key Value Pairs

Making use of key value pair responses requires the use of scripting, consider an API that returns the below representation of a contact.

{
    properties: [{
        "key": "email",
        "value": "example@example.com"
    }]
}

To access the email field we would add a field in the method response with a connector location of properties.email. However this would not work as the cyclr is looking in the response for a properties object with a property named email to get the value from. To solve the issue we would add the below function into the method scripts, this function will transform the properties array into an object with properties for each key value pair.

function after_action() {
    var original = method_response.properties;
    method_response.properties = {};

    for (var i = 0; i < original.length; i++) {
        var item = original[i];
        if (item['key'] == void(0))
            continue;

        var val = item['value'];
        if (val == void(0))
            continue;

        method_response.properties[item['key']] = val;
    }

    return true;
}

Now when cyclr runs the method if will get the following result back and the properties.email field will work as expected.

{
    properties: {
        "email": "example@example.com"
    }
}

For a corresponding request method, e.g. adding a contact, we would need the below function in the method scripts to perform the data transformation in reverse.

function before_action() {
    var original = method_request.properties;
    method_request.properties = [];

    for (var p in original) {
        method_request.properties.push({
            'key': p,
            'value': original[p]
        });
    }
    return true;
}

Modify Parameters

Besides the HTTP request body, you can also use scripting to modify HTTP headers (method_request_headers) and query string parameters (method_request_parameters).

function before_action() {
    var xmlData = '<Records><Record>';

    for (var p in method_request) {
        xmlData += '<Field val=""' + p + '"">' + method_request[p] + '</Field>';
    }

    xmlData += '</Record></Records>';
    method_request_parameters.xmlData = xmlData;
    return true;
}

In this example, we transformed the method request body to a XML string and saved the string as a new parameter called xmlData.

Handle Errors from Third Party APIs

The scripting engine can be used to catch and handle errors returned from third party APIs.

  • statusCode – the HTTP status code returned by the third party API
  • reasonPhrase – the reason phrase returned by the third party API
  • content – the body content of the response from the third party API
  • isError – indicates that the error is an error. default: true, set to false if using isWarning or isSuccess
  • isWarning – set to true for Cyclr to log the error as a warning
  • isSuccess – set to true to change the error to success, update content to contain the success step data

Example: change an error to a warning

function after_error() {
    if (method_error.statusCode.toString() == 400 && method_error.reasonPhrase == 'Email Address not valid') {
        method_error.isError = false;
        method_error.isWarning = true;
    }
    return true;
}

Example: change an error to a success

function after_error() {
    if (method_error.statusCode.toString() == 400 && method_error.reasonPhrase == 'Email Address not valid') {
        method_error.isError = false;
        method_error.isSuccess = true;
        method_error.content = '{}';
    }
    return true;
}

Limitations

  • Execution time: 30 seconds. Script running will time out after 30 seconds.
  • External HTTP requests: for security reasons, we will use the same authentication method as the connector and the same authentication value when the connector was installed by the user. You cannot use the script to access or modify the authentication value.
  • The cycle_variables object is only available through a Step’s Advanced Settings area, and not through Inline Script. Also, any changes made to it and its properties are not preserved.
Edit me