Scripts API

Retrieving input data

Below is example code showing how to use the input and how to return data.

function callService(context){
  const firstArgument = context.getFirstParameter("firstArgument");
  const firstArgumentList = context.getParameters("firstArgument");
  const keySet = context.getInputParameters().keySet();
  const comboboxLabel = context.getData("GesCombobox1","label");
  const result = "service script constant " + firstArgument + " list value: " + firstArgumentList + " and first from list: " + firstArgumentList.get(0) + " keySet " + keySet;
  return [{'output': result}];
}

Input to Service Script

As input (parameter context in the code above) there is an object that provides the following methods:

  • List<String> getParameters(final String name); - retrieves a specific list from the input data map,

  • String getFirstParameter(final String name); - retrieves the first element from a specific list in the input data map or returns the value "null",

  • String getFirstParameter(final String name, final String defaultIfEmpty); - retrieves the first element from a specific list in the input data map, and if it does not exist or is empty returns the value "defaultIfEmpty",

  • Map<String, List<String>> getInputParameters(); - returns the entire input data map that it stores,

  • String isVisible(final String id); - retrieves whether the component with the specified id is visible,

  • String getValue(final String id); - retrieves the value of the component (also a session variable) with the specified id,

  • void setValue(final String componentId, final String value); - sets the value value of the component with the specified componentId. The rule for specifying componentId is the same as for getValue. When calling a script inside a composite component, to set the value of a component / session variable embedded in the same component, the componentId should be prefixed with the character @

NOTE! Attempting to execute setValue on a component that listens to another component or on a component to that other components listen to will result in throwing an exception.

  • String getData(final String id, final String attribute); - retrieves the value of a specific attribute for the component with the specified id

NOTE! The retrievable attributes depend on the component.

  • List<Map<String, String>> callService(String name, Map<String, List<String>> input); - enables calling a ServiceProxy,

  • ValidatorOutput validate(String name, Map<String, List<String>> input); - enables calling a validator

Output from Service Script

We can return the result of script execution in two ways:

  1. List of maps - the array of objects on output is parsed into a list of maps, then processed in the standard way.

  2. Single map - the return value is wrapped as a single-element list, then processed in the standard way.

Script output with an example list:

  return [{'output': 'result1'},{'output': 'result2'},{'output': 'result3'}];

Logging

Input logging is automatic

Manual logging should comply with the description in Logging in ScriptCode

function callService(context) {
    const sessionVariable = context.getValue("@sessionVar");
    Logger.info('Session variable value [arg1={}, arg2={}]', nonsensitive('arg1 nonsensitive test'), sessionVariable);
    return [{'sessionVar':sessionVariable }];
}

Throwing business exceptions

It is possible to throw a business exception from within the script. Sample code:

function callService(context) {
    const firstArgument = context.getFirstParameter('firstArgument');
    let builder =  context.getErrorPageDefinitionBuilder();
    builder.body('body');
    context.throwBusinessException(builder);
    return [{'firstOutput': firstArgument}];
}

Possible methods that can be called on the context object:

context.getErrorPageDefinitionBuilder() .body(string) .styleName(string) .msg(string) .pageTitle(string) .pageTitleKey(string) .sidebarSlot2TextContent(string) .sidebarSlot2(string) .sidebarSlot1TextContent(string) .sidebarSlot1(string) .retryButtonAvailable(string) .retryButtonAvailable(boolean) .logobarTitle(string) .logobarTitleKey(string) .logobarDescription(string) .bodyTextContent(string) .parameter(String key, String value) .cause(Throwable cause) .redirectUrl(string) .redirectDelayInMillis(string) .businessFormIdentifier(string)

Saving temporary data

It is possible to save certain data between service calls. The object used for this is registry.

Possible methods that can be called on the registry:

  • save(namespace, id, data) - save data

  • saveVersion(namespace, id, data, version) - save data with version verification. If the version field is not set or is empty - save without verification. If the value of the version field does not match the current version of the stored data, the request will end with an error.

  • get(namespace, id) - retrieve data

  • getVersion(namespace, id) - retrieve object { data: 'saved data', version: 'current data version' }

  • delete(namespace, id) - delete data.

Data are stored in namespaces (namespace in methods) determined by administrators. Each namespace can have a data TTL. By default it is 90 days. Providing the same id across multiple save calls updates the data associated with that id. The data version is a unique identifier generated with each data save.

The object requires a running EximeeRegistry application to function correctly.

Examples:

context.registry().save('test', '123123', 'temporary data');
context.registry().get('test', '123123'); // will return 'temporary data'
const item = context.registry().getVersion('test', '123123'); // will return object {data,version}
context.registry().saveVersion('test','123123', 'new data', item.version); // version matches, save will succeed
context.registry().saveVersion('test','123123', 'new data', 'some other version'); // version mismatch, save will fail
context.registry().delete('test','123123');

Retrieving the context of the logged-in user

It is possible to retrieve the context of the currently logged-in user who fills out the request.

APIs
/**
 * The form security context, containing security-related data. After implementation this topic will include the identity of the current user.
 */
interface SecurityContext {
  /**
   * Identity of the current user
   */
  getCurrentUser(): Identity | null;
}
 
interface ScriptApi {
  // ...
  /**
   * Retrieving the current user context
   */
  getSecurityContext(): SecurityContext;
}
 
/**
 * Representation of a user role
 */
interface Role {
  name: string;
}
 
/**
 * Representation of a user identity
 */
interface Identity {
  /**
   * Identifier of the user's identity. In the context of this topic always 'current'
   */
  id: string;
  /**
   * Username. In the context of this topic this is the employee's SKP.
   */
  username?: string;
  /**
   * User roles
   */                              
  roles?: Role[];
 
  /**
   * User's first name
   */
  firstName?: string;
 
  /**
   * User's last name
   */
  lastName?: string;
}

When running the script without a logged-in user context the method context.getSecurityContext() will return the value null

Example usage of the user context in a script

function callService(context) {
    context.getSecurityContext().getCurrentUser();               
  // return: { id: 'current', username: '100001', firstName: 'Jan', lastName: 'Kowalski', roles: [{name: 'role_001'}, {name: 'role_002'}] }
    // Checking if the logged-in user has the role "role_001".
    var hasRole = context.getSecurityContext().getCurrentUser().roles.map(x=> x.name).includes("role_001");
     
    // Retrieving the login of the currently logged-in user. 
    var username = context.getSecurityContext().getCurrentUser().username;
}

Retrieving application configuration

The functionality to retrieve application configuration is available for scripts (scriptService), script tasks (scriptTask) and validation scripts (validationScript).

In scripts it is possible to retrieve the application configuration

interface Api {
    config: {
        v1: {
          get(key: string): string;
          getOrDefault(key: string, defaultValue: string): string;
        }
    }
}

Example script retrieving configuration:


function callService(context) {
    let value1
    try {
        value1 = api.config.v1.get("application.url");
    } catch (e) {
        value1 = "default"
    }
 
    let value2 = api.config.v1.get("application.url");
 
    let value3 = api.config.v1.getOrDefault("not_existing_key", "defaultValue")
 
    return [{'value1': value1, 'value2': value2, 'value3': value3}];
}

Processing xlsx files

It is possible to read xlsx files attached to the request. For this purpose use the xlsx-sheet-handling-module and the endpoint it provides /xlsx/v1 - the module is currently provided separately, appropriate access configuration to the service must be made in ScriptApi. The module should be given a request:

{
    content: string
}

where in content we pass the file in base64 form. In this form it is passed to the service when we map an uploader to input (in the case of multiple files in the uploader this is a list). In the response we will receive a map divided as: sheet → row → column

{
    "sheet": {
        "1": {
            "A": { "test"
                }
            }
    }
}

field

function callService(context) {
    let files = context.getParameters("uploader");
 
    if (files.size() === 0) {
        return [{}];
    }
 
    let header = {};
    let body = {'content': files.get(0)}
 
    try {
        let response = api.rest.v1.post('excelDocument', { pathParams: ['xlsx', 'v1'] }, header , body);
     
        return [{'output': JSON.stringify(response.body)}];
    } catch (error) {
        Logger.info(error );
        return [{'output': 'An error occurred'}];
    }
 
}

Retrieving Content content

From a script you can retrieve the content of an artifact Content (textContent) created in Eximee Designer, using the function: api.repository.v1.textContent. This function returns an object that has contents for each of the defined translations. To get the content for a given translation we use the function language. Example usage:

const artifactName = "stopka";
const artifactVersion = "*";
const language = "pl";
 
const artifactContent = api.repository.v1.textContent(artifactName, artifactVersion);
const footerPl = artifactContent.language(language).text();

If we are not sure that the parameters we provided are correct, we can handle exceptions using try catch:

const artifactName = "stopka";
const artifactVersion = "*";
const language = "pl";
 
let artifactContent;
try {
    artifactContent = api.repository.v1.textContent(artifactName, artifactVersion);
} catch (error) {
    return [{'output': "No artifact named: " + artifactName + " and version: " + artifactVersion}]
}
 
let footerPl;   
try {
    footerPl = artifactContent.language(language).text();  
} catch (error) {
    return [{'output': "No translation was found in the artifact for language: " + language}];
}
 
return [{'output': footerPl}];

Mathematical operations in ScriptCode

More information in Mathematical operations in ScriptCode

Operations and access to process data

More information in Operations and access to process data

Retrieving request statuses

More information in Retrieving request statuses

Data model

More information in Data model API

Other examples

Populating the Combobox component (Value selection field)

The script populates Value selection field of the Combobox based on the provided 'locale' parameter.

Outputs id, Each component should have a label (, and description should be connected to the appropriate combobox fields, respectively id, text, and description.

Combobox populating script:

function callService(context) {
    const locale = context.getFirstParameter('locale');
    if (locale === 'pl') {
        return [
            { 'id': 1, 'label': 'Value 1', 'description': 'Description 1', },
            { 'id': 2, 'label': 'Value 2', 'description': 'Description 2' }
        ];
    } else if (locale === 'en') {
        return [
            { 'id': 1, 'label': 'Label 1', 'description': 'Description 1', },
            { 'id': 2, 'label': 'Label 2', 'description': 'Description 2' }
        ];
    } else {
        return [
            { 'id': 1, 'label': 'Default translation value 1', 'description': 'Description 1', },
            { 'id': 2, 'label': 'Default translation value 2', 'description': 'Description 2' }
        ];
    }
}

Retrieving file names from the Attachments component

The script uses the method getData(), which retrieves the value of a specific attribute for the component with the specified id. For the Attachments component the names of added files are specified using the attribute fileNames and they come from the request as a string in JSON format (e.g. ["name1.png", "name2.png"]), therefore it is necessary to transform this string into an object using the method JSON.parse.

function callService(context) {
    const attachment1 = JSON.parse(context.getData("@GesUploadFile1", "fileNames"));
    const attachment2 = JSON.parse(context.getData("@GesUploadFile2", "fileNames"));
}

Retrieving the value of a Combobox from a repeatable section

The script uses the method getData(), which retrieves the value of a specific attribute for the component with the specified id. For the Value picker from a list component the values (labels) of given keys are specified using the label attribute.

for (let i=0; i<10; i++)  {
        let id = "GesRepeatableSection1.row" + i + ".GesCombobox1";
        let label = context.getData(id, "label");
}

Last updated

Was this helpful?