# Writing Functions Guide

A **function** component runs JavaScript code on the incoming message and passes it on.

{% hint style="info" %}
If you are planning to use the function again in other projects, you can create a specific component instead. Learn creating a new component (and functions writing in **.js** file of its project) in [**New Component Creation Tutorial**](/creators-studio/new-component-creation-tutorial/overview.md).
{% endhint %}

By convention, an incoming message is an object called **msg**, and the body of this message contained in the **msg.payload** property.

Other components may attach other properties to **msg**. Check their documentation when using.

## Writing a Function

For your convenience, you may open a wider editor field for a function component:&#x20;

![](/files/-MVbBebBzUXYHBZjeMSf)

#### Basics

* The default body of a function is **`return msg;`** that passes the incoming message without changes.
* If the function returns **`null`** there will be no outcoming message and the flow ends.
* The function doesn't have to return the same message object. It can construct a completely new object. For example:

```
var newMsg = { payload: msg.payload.length };
return newMsg;
```

{% hint style="info" %}
Note: a new message in this instance will lose all the properties of the incoming message. So in many situations, the function should keep the incoming message object when updating its properties. For example, the HTTP In/Response flow requires the **`msg.req`** and **`msg.res`** properties to be preserved end-to-end.
{% endhint %}

* For debuggging purposes use **`node.warn()`** that shows warnings in the sidebar. For example:

```
node.warn("my var xyz = " + xyz);
```

See [**Logging events**](/creators-studio/writing-functions-guide.md#logging-events) for more details.

## Multiple Outputs

The function component can have multiple outputs. For example, all the messages with "simon" msg.topic will go to the second output here:

```
if (msg.topic === "simon") {
   return [ null, msg ];
} else {
   return [ msg, null ];
}
```

The following function will return the incoming message without changes to the first output and its payload length to the second one:

```
var newMsg = { payload: msg.payload.length };
return [msg, newMsg];
```

The number of outputs points are set up in the bottom property: &#x20;

![](/files/-MVpvwxdss_dZ7njiEGI)

## Multiple Messages

If one of returning messages will be also an array, the corresponding output will show multiple messages.&#x20;

```
var msg1 = { payload:"output 1, message 1" };
var msg2 = { payload:"output 1, message 2" };
var msg3 = { payload:"output 1, message 3" };
var msg4 = { payload:"output 2" };
return [ [ msg1, msg2, msg3 ], msg4 ];
```

In the next example, the function converts the input string to an array of words and returns them as multiple messages.

```
var multiMsg = [];
var words = msg.payload.split(" ");
for (var word in words) {
    multiMsg.push({payload:words[word]});
}
return [ multiMsg ];
```

## Sending messages asynchronously

Use a **`node.send()`** function to send messages immediately.&#x20;

![](/files/-MVvZMTfF9OplP8PMSAd)

An asynchronous action function before sending a message.

```
someAsynchAction(msg, function(result) {
    msg.payload = result;
    node.send(msg);
});
return;
```

The **function** component will clone every message object you pass to **`node.send`** to ensure there is no unintended modification of message objects that get reused in the function.

The **function** can forbid the runtime to clone the first message passed to `node.send` by passing in `false` as a second argument to the function. It would do this if the message contains something that is not otherwise cloneable, or for performance reasons to minimize the overhead of sending messages:

```
node.send(msg,false);
```

### Finishing with the message

To signal the runtime that asynchronous message handling is finished the function should call **`node.done()`**. And the runtime will properly track messages through the system. &#x20;

![](/files/-MVvbMq0dNn0BjGMrIvz)

## Running code on start

In a **Setup** tab, you can provide code that will run when the component is started.&#x20;

For example, you can initialize values in a local context that the main function will use:

```
if (context.get("currentLevel") === undefined) {
    context.set("currentLevel", 100)
}
```

The **Setup** function can return a Promise if it needs to complete asynchronous work before the main Function can start processing messages. Any messages that arrive before the **Setup** function has completed will be queued up, and handled when it is ready.

## Tidying up

You can tidy up any outstanding requests and close any connection on flow redeployment in two ways:

* add a close event handler:

```
node.on('close', function() {
    // tidy up any async code here - shutdown connections and so on.
});
```

* or add code to the **Close** tab in the edit dialog.

## Logging events

If you want the component to log some information to console use these functions:

```
node.log("Something going on");
node.warn("Pay attantion to this");
node.error("There is a problem");
//and additionally:
node.trace("Log some internal detail not needed for normal operation");
node.debug("Log something more details for debugging the component's behaviour");
```

The **`warn`** and **`error`** messages also get sent to the flow editor debug tab.

## Handling errors

When the function encounters it returns nothing, but a catch component can log the problem. See the [**catch**](/creators-studio/standard-components/common.md#catch) component description.

A **catch** component can be triggered when the function calls **`node.error()`** with the original message as a second argument:

```
node.error("there is an error", msg);
```

![](/files/-MVvuPaR6KFRKRG6ndad)

## Storing data

Beside the **`msg`** object, the function can store data in the context store.

There are three predefined variables to access context:

* **context**: the component's local context
* **flow**: the flow context, the variable value is available for other components in the flow
* **global**: the value is accessible in the global (all flows) scope&#x20;

{% hint style="info" %}
Note: these variables are the **function** component way to deal with context. In [**custom components**](/creators-studio/new-component-creation-tutorial/component.js.md#component-context), it's done differently.
{% endhint %}

A function can access context in common or asynchronous mode. The built-in context stores provide both modes. Some stores may only provide asynchronous access and will throw an error if they are accessed synchronously.

Getting a value:

```
var getCount = flow.get("count");
```

Setting a value:

```
flow.set("count", 111);
```

For example, here the function counts how many times it has been run:

```
// create the counter = 0 if it doesn't exist, or get the value from context
var count = context.get('count')||0;
count += 1;
// store the value back to context
context.set('count',count);
// attach it to the output msg object
msg.count = count;
return msg;
```

### **Get and Set multiple values**

The rule is the same as with multiple outputs: use an array.

```
var values = flow.get(["count", "colour", "length"]);
...
flow.set(["count", "colour", "temperature"], [123, "red"]);
```

{% hint style="info" %}
Note that in this instance **`length`** will be set to **`null`** due to missing value.
{% endhint %}

### **Asynchronous context access**

Use an extra callback parameter for the **`get`** and **`set`** functions to access the context store asynchronously.

```
// Get single value
flow.get("count", function(err, getCount) { ... });

// Get multiple values
flow.get(["count", "colour"], function(err, count, colour) { ... })

// Set single value
flow.set("count", 123, function(err) { ... })

// Set multiple values
flow.set(["count", "colour", [123, "red"], function(err) { ... })
```

The first argument passed to the callback, **`err`**, is only set if an error occurred when accessing context.

The asynchronous version of the count example becomes:

```
context.get('count', function(err, count) {
    if (err) {
        node.error(err, msg);
    } else {
        // initialise the counter to 0 if it doesn't exist already
        count = count || 0;
        count += 1;
        // store the value back
        context.set('count',count, function(err) {
            if (err) {
                node.error(err, msg);
            } else {
                // make it part of the outgoing msg object
                msg.count = count;
                // send the message
                node.send(msg);
            }
        });
    }
});
```

### **Multiple context stores**

A function can configure multiple context stores. For example, both a **memory** and **file** based store could be used.&#x20;

To identify the store to use add an optional parameter to the  **`get`**/**`set`** context functions.

```
// Get value - sync
var functionCount = flow.get("count", storeName);

// Get value - async
flow.get("count", storeName, function(err, functionCount) { ... });

// Set value - sync
flow.set("count", 111, storeName);

// Set value - async
flow.set("count", 111, storeName, function(err) { ... })
```

### **Global context**

The global context can be pre-populated with objects when Apps Editor starts. This is defined in the main *settings.js* file under the `functionGlobalContext` property.

For example, learn how to [**Load additional modules**](/creators-studio/writing-functions-guide.md#load-additional-modules) within the function component using global context.

## Adding status

You can add status markers to the **function** component by calling special functions:

```
node.status({fill:"red",shape:"ring",text:"disconnected"});
node.status({fill:"green",shape:"dot",text:"connected"});
node.status({text:"text status"});
node.status({});   // clears the status
```

See how it's done in [**custom components**](/creators-studio/new-component-creation-tutorial/component.js.md#components-workspace-status). The parameters and the result are the same.

## Load additional modules

To use additional modules within the function component they must be loaded in global context. The module must be loaded to the main **settings.js** file and added to the **`functionGlobalContext`** property.

```
functionGlobalContext: {
    externalModule:require('external')
}
```

at which point, the module can be referenced within a function as `global.get('externalModule')`.

Modules loaded from your settings file must be installed in the same directory as the settings file. To do this open the project terminal and run:

```
npm install name_of_external_module
```

## API Reference

The following objects are available within the Function node.

#### **node**

* `node.id` : the id of the Function node - *added in 0.19*
* `node.name` : the name of the Function node - *added in 0.19*
* `node.log(..)` : [log a message](/creators-studio/writing-functions-guide.md#logging-events)
* `node.warn(..)` : [log a warning message](https://docs.aitheon.com/creators-studio/writing-functions-guide#logging-events)
* `node.error(..)` : [log an error message](https://docs.aitheon.com/creators-studio/writing-functions-guide#logging-events)
* `node.debug(..)` : [log a debug message](https://docs.aitheon.com/creators-studio/writing-functions-guide#logging-events)
* `node.trace(..)` : [log a trace message](https://docs.aitheon.com/creators-studio/writing-functions-guide#logging-events)
* `node.on(..)` : [register an event handler](https://docs.aitheon.com/creators-studio/writing-functions-guide#sending-messages-asynchronously)
* `node.status(..)` : [update the node status](https://docs.aitheon.com/creators-studio/writing-functions-guide#adding-status)
* `node.send(..)` : [send a message](https://docs.aitheon.com/creators-studio/writing-functions-guide#sending-messages-asynchronously)
* `node.done(..)` : [finish with a message](https://docs.aitheon.com/creators-studio/writing-functions-guide#sending-messages-asynchronously)

#### **context**

* `context.get(..)` : get a component-scoped context property
* `context.set(..)` : set a component-scoped context property
* `context.keys(..)` : return a list of all node-scoped context property keys
* `context.flow` : same as `flow`
* `context.global` : same as `global`

#### **flow**

* `flow.get(..)` : get a flow-scoped context property
* `flow.set(..)` : set a flow-scoped context property
* `flow.keys(..)` : return a list of all flow-scoped context property keys

#### **global**

* `global.get(..)` : get a global-scoped context property
* `global.set(..)` : set a global-scoped context property
* `global.keys(..)` : return a list of all global-scoped context property keys

#### **APPS**

* `APPS.util.cloneMessage(..)` : safely clones a message object so it can be reused

#### **env**

* `env.get(..)` : get an environment variable

### **Other modules and functions**

The **function** component also makes the following modules and functions available:

* `Buffer` - the Node.js `Buffer` module
* `console` - the Node.js `console` module (`node.log` is the preferred method of logging)
* `util` - the Node.js `util` module
* `setTimeout/clearTimeout` - the javascript timeout functions.
* `setInterval/clearInterval` - the javascript interval functions.

{% hint style="info" %}
Note: the **function** component automatically clears any outstanding timeouts or interval timers whenever it is stopped or re-deployed.
{% endhint %}


---

# 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.aitheon.com/creators-studio/writing-functions-guide.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.
