# Scripts API

## Retrieving input data <a href="#skrypty-scriptservice-pobieraniedanychwejsciowych" id="skrypty-scriptservice-pobieraniedanychwejsciowych"></a>

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

```javascript
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 the service script <a href="#skrypty-scriptservice-wejsciedoskryptserwisu" id="skrypty-scriptservice-wejsciedoskryptserwisu"></a>

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 it stores,
* String **isVisible**(final String id); - retrieves information whether the component with the specified id is visible,
* String **getValue**(final String id); - retrieves the value of the component (including 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 providing componentId is the same as for getValue.\
  When invoking the script inside a composite component, in order to set the value of a component / session variable embedded in the same component, componentId must be prefixed with the character **@**

> **WARNING!** Attempting to execute **setValue** on a component that listens to another component or on a component **to** that is listened to by other components will result in an exception being thrown.

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

> **WARNING!** The available attributes depend on the component.

* List\<Map\<String, String>> **callService**(String name, Map\<String, List\<String>> input); - enables calling ServiceProxy,
* ValidatorOutput **validate**(String name, Map\<String, List\<String>> input); - enables calling the validator

## Output from the service script <a href="#skrypty-scriptservice-wyjsciezeskryptserwisu" id="skrypty-scriptservice-wyjsciezeskryptserwisu"></a>

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

1. **List of maps** - the output array is parsed into a list of maps, and then processed in the standard way.
2. **Single map** - the return value is wrapped as a single-element list, and then processed in the standard way.

\
Output from the script with an example list:

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

## Logging <a href="#skrypty-scriptservice-logowanielogowanie" id="skrypty-scriptservice-logowanielogowanie"></a>

Logging input data is automatic

Manual logging should be consistent with the description in [Logging in ScriptCode](https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/logika-biznesowa/scriptcode/logowanie-w-scriptcode)

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

## Throwing business exceptions

Business errors have been described in detail on the page [Error pages](https://docs.eximee.com/documentation/documentation-en/interfejs-uzytkownika/formularze/tworzenie-formularza/strony-bledow#bledy-biznesowe).

## Saving temporary data <a href="#skrypty-scriptservice-zapisdanychtymczasowych" id="skrypty-scriptservice-zapisdanychtymczasowych"></a>

It is possible to save certain data between service calls. This is handled by the object `registry`.

Possible methods that can be called on the object `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 the object { data: 'saved data', version: 'current data version' }
* delete(namespace, id) - delete data.

Data are stored in namespaces (namespace in methods) set by administrators. Each namespace can be assigned a data lifetime. 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 each time the data is saved.

{% hint style="info" %}
For correct operation, the object requires a running EximeeRegistry application.
{% endhint %}

{% hint style="danger" %}
**Saving data using EximeeRegistry is not intended for storing anything permanently!**
{% endhint %}

**Examples:**

```javascript
context.registry().save('test', '123123', 'temporary data');
context.registry().get('test', '123123'); // returns 'temporary data'
const item = context.registry().getVersion('test', '123123'); // returns the object {data,version}
context.registry().saveVersion('test','123123', 'new data', item.version); // matching version save succeeds
context.registry().saveVersion('test','123123', 'new data', 'some other version'); // mismatched version save fails
context.registry().delete('test','123123');

```

## Retrieving the context of the logged-in user <a href="#skrypty-scriptservice-pobieraniekontekstuzalogowanegouzytkownika" id="skrypty-scriptservice-pobieraniekontekstuzalogowanegouzytkownika"></a>

{% hint style="warning" %}
Feature available from platform version: 2.3403.0

The feature works on requests run in the webforms application with oauth authorization configured.\
It does not work on requests run in the Eximee Dashboard application
{% endhint %}

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

<details>

<summary>API</summary>

```
/**
 * Form security context, containing security-related data. After implementing this topic, it will contain the identity of the current user.
 */
interface SecurityContext {
  /**
   * Identity of the current user
   */
  getCurrentUser(): Identity | null;
}
 
interface ScriptApi {
  // ...
  /**
   * Retrieve the current user context
   */
  getSecurityContext(): SecurityContext;
}
 
/**
 * Representation of a user role
 */
interface Role {
  name: string;
}
 
/**
 * Representation of a user identity
 */
interface Identity {
  /**
   * User identity identifier. In the context of this topic always 'current'
   */
  id: string;
  /**
   * User name. In the context of this topic, this is the employee's SKP.
   */
  username?: string;
  /**
   * User roles
   */                              
  roles?: Role[];
 
  /**
   * User first name
   */
  firstName?: string;
 
  /**
   * User last name
   */
  lastName?: string;
}
```

</details>

{% hint style="info" %}
When running the script without a logged-in user context, the method **`context.getSecurityContext()`** will return the value **null**
{% endhint %}

Example use of the user context in a script

```javascript
function callService(context) {
    context.getSecurityContext().getCurrentUser();               
  // return: { id: 'current', username: '100001', firstName: 'Jan', lastName: 'Kowalski', roles: [{name: 'role_001'}, {name: 'role_002'}] }
    // Checking whether the logged-in user has the "role_001" role.
    var czyMaRole = 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 <a href="#skrypty-scriptservice-pobieraniekonfiguracjiaplikacji" id="skrypty-scriptservice-pobieraniekonfiguracjiaplikacji"></a>

{% hint style="warning" %}
Feature available from platform version: 3.190.0

The feature works on requests run as [Business application](https://docs.eximee.com/documentation/documentation-en/wprowadzenie/aplikacja-biznesowa)
{% endhint %}

{% hint style="info" %}
The application configuration retrieval feature is available for scripts (scriptService), script tasks (scriptTask), and script validators (validationScript).
{% endhint %}

In scripts, it is possible to retrieve the application configuration

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

Example script retrieving configuration:

```javascript

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 <a href="#skrypty-scriptservice-przetwarzanieplikowxlsx" id="skrypty-scriptservice-przetwarzanieplikowxlsx"></a>

{% hint style="warning" %}
Required module xlsx-sheet-handling-module
{% endhint %}

It is possible to read xlsx files attached to the request. To do this, use the xlsx-sheet-handling-module and its provided endpoint */xlsx/v1* - the module is currently provided separately; appropriate configuration of access to the service in ScriptApi must be performed. The following request should be passed to the module:

```javascript
{
    content: string
}
```

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

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

Example:

```javascript
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 <a href="#skrypty-scriptservice-pobieraniezawartoscitresci" id="skrypty-scriptservice-pobieraniezawartoscitresci"></a>

{% hint style="warning" %}
Feature available from platform version: **3.332.0**
{% endhint %}

From the script level, 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 contains content for each of the defined translations. To retrieve the content for a given translation, we use the function `language`. Example usage:

```javascript
const nazwaArtefaktu = "stopka";
const wersjaArtefaktu = "*";
const jezyk = "pl";
 
const artefaktTresci = api.repository.v1.textContent(nazwaArtefaktu, wersjaArtefaktu);
const stopkaPl = artefaktTresci.language(jezyk).text();
```

{% hint style="danger" %}

1. function **`textContent`** throws an exception if it cannot find an artifact with the specified parameters
2. function **`language`** throws an exception if it cannot find a translation in the specified language
   {% endhint %}

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

```javascript
const nazwaArtefaktu = "stopka";
const wersjaArtefaktu = "*";
const jezyk = "pl";
 
let artefaktTresci;
try {
    artefaktTresci = api.repository.v1.textContent(nazwaArtefaktu, wersjaArtefaktu);
} catch (error) {
    return [{'output': "No artifact found with name: " + nazwaArtefaktu + " and version: " + wersjaArtefaktu}]
}
 
let stopkaPl;   
try {
    stopkaPl = artefaktTresci.language(jezyk).text();  
} catch (error) {
    return [{'output': "No translation found in the artifact for language: " + jezyk}];
}
 
return [{'output': stopkaPl}];


```

## Mathematical operations in ScriptCode

More information in [Mathematical operations in ScriptCode](https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/logika-biznesowa/scriptcode/skrypty-scriptservice/api-skryptow/operacje-matematyczne-w-scriptcode)

## Process data operations and access

More information in [operacje-i-dostep-do-danych-procesu](https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/logika-biznesowa/scriptcode/skrypty-scriptservice/api-skryptow/operacje-i-dostep-do-danych-procesu "mention")

## Retrieving request statuses

More information in [Retrieving request statuses](https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/logika-biznesowa/scriptcode/skrypty-scriptservice/api-skryptow/pobieranie-statusow-wnioskow)

## Data model

More information in [Data model API](https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/model-danych/wykorzystanie-modelu-danych/api-modelu-danych)

## Other examples

### Populating the value selection list (Combobox) component <a href="#skrypty-scriptservice-przykladowyskryptzasilajacykomponentpolewyboruwartoscizlisty-combobox-example" id="skrypty-scriptservice-przykladowyskryptzasilajacykomponentpolewyboruwartoscizlisty-combobox-example"></a>

The script populates **Value selection list** from a list (Combobox) based on the passed 'locale' parameter.

Outputs **id**, **label**, and **description** should be connected to the appropriate combobox fields, respectively **id**, **text**, and **description**.

Script populating the combobox:

```javascript
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 component **Attachments** the names of added files are specified using the attribute **fileNames** and come from the request as a JSON-formatted string (e.g. *\["name1.png", "name2.png"]*), therefore it is necessary to transform this string into an object using the method **JSON.parse**.

{% hint style="warning" %}
**WARNING!** Method **getData()** uses the component id, so the script is not universal - for each request the appropriate component id must be provided **Attachments**:
{% endhint %}

```javascript
function callService(context) {
    const zalacznik1 = JSON.parse(context.getData("@GesUploadFile1", "fileNames"));
    const zalacznik2 = JSON.parse(context.getData("@GesUploadFile2", "fileNames"));
}
```

### Retrieving the values of the value selection list (Combobox) from a repeatable section <a href="#skrypty-scriptservice-fragmentskryptupobierajacegowartoscipolawyboruwartoscizlisty-comboboxa-zsekcji" id="skrypty-scriptservice-fragmentskryptupobierajacegowartoscipolawyboruwartoscizlisty-comboboxa-zsekcji"></a>

The script uses the method **getData()**, which retrieves the value of a specific attribute for the component with the specified id. For the component **Drop-down list value selector** the values (labels) of the given keys are specified using the attribute **label.**

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/logika-biznesowa/scriptcode/skrypty-scriptservice/api-skryptow.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
