# Operations

An Operation describes a specific action within the run of a particular workflow.

An action can be some HTTP request to a remote server, or an internal action. The operation needs to be associated with an app and an app_action. When an action is performed, the Payload is sent as the body of the request.

In addition, using the Input and Output objects, you can define actions that will be performed before or after the main action was performed. These objects are mainly useful for manipulating data before or after performing the operation.
There are two types of input / output functions: format_function and redis_functions.

As mentioned above, Payload is defined as the body of the request. The payload object has a fixed structure. For each key in the object, two values are attached: type and data.

# Type and Data

type and data are two fields that are related to each other.
Type can have one of five values: raw / request / redis / struct / get_by_lang. The purpose of type is to define how the data will be retrieved.
The purpose of data is to define what data will be sent in the request, in relation to the type defined.

# raw


Raw means that the value that should be sent in the request is exactly the value that is under data.

# For example:

Giving this example payload object:

payload:
    name:
        data: Bob Alice
        type: raw

The value that will eventually be sent is the exact value under data, so the request body will looks like:

{
  "payload": {
    "name": "Bob Alice"
  }
}

# request


Request means that the value that should be sent in the request is the value stored in the previous request, under the request-key that stored under data.
For each run of an operation, there is access to the response of the previous request.
Before each move to the next operation, we automatically fires flat function on the previous request. When you want to extract a value from the previous request in the current request, the type should be equal to the request, and the data should be the request-key after the flat function.

# For example:

Assume that previous request returned the following response:

{
  "message_data": {
    "message": {
      "body": "Hello world!"
    }
  }
}

We will move the response under flat, so the request-key will looks like that:

message_data.message.body

So, Giving this example payload object:

payload:
    name:
        data: message_data.message.body
        type: request

The value that will eventually be sent is the exact value under previous request, by the request-key stored on data.
So the request body of the current request will looks like:

{
  "payload": {
    "name": "Hello world!"
  }
}

# redis


Redis means that the value that should be sent in the request is the value stored in redis, under the redis-key that stored under data. Any response returned from rele.ai, is saved under redis. The redis-key under which each response is stored is determined by the flat function that creates this redis-key for each response.

# rkey_type

When the type is redis, an extra key named rkey_type is added to payload object.
Its value can be one of three:
hash_map: One of redis default types (opens new window). Retrieves data stored in redis as a hash map.
array: One of redis default types (opens new window). Retrieves data stored stored in redis as an array
hash_array: RELE.AI custom redis type. Retrieves data stored as a hash_map and returns it as an array.

Hash Array

hash array helps you build an array that is saved as a hash map. Suppose you set up redis for a particular operation as follows:

redis:
  type: hash_map
  field: hello_world

And the value saved in redis looks like this:

{
  "hello_world:0": "a",
  "hello_world:1": "b",
  "hello_world:2": "c",
}

Then, when you want to extract the values ​​as an array, you can access them as follows:

payload:
    hello_world:
        data: hello_world:\d+
        rkey_type: hash_array
        type: redis

And the value is going to be like this:

[a, b, c]

# For example:

Assume that one of your operations returned the following response:

{
  "message_data": {
    "message": {
      "body": "Hello world!"
    }
  }
}

We will move the response under flat, so the redis-key will looks like that:

hello_world_response:message_data:message:body

So, Giving this example payload object:

payload:
    name:
        data: hello_world_response:message_data:message:body
        rkey_type: hash_map
        type: redis

The value that will eventually be sent is the exact value under redis, by the redis-key stored on data.
So the request body will looks like:

{
  "payload": {
    "name": "Hello world!"
  }
}

NOTE

hello_world_response is an example of a field in redis for an operation. Each save to redis is basically a connection between the field defined in the operation under redis, and the result from the flat function for the response.

# For example:

For this redis configuration:

redis:
  type: hash_map
  field: hello_world_response

And this response object:

{
  "message_data": {
    "message": {
      "body": "Hello world!"
    }
  }
}

The redis-key will be:

hello_world_response:message_data:message:body

# struct


Struct means that the value that should be sent in the request is the value stored on runtime structs.
There are two runtime structs from which it is commonly used to extract data.
User - Contains all data about the user running the operation.
Org - Contains all the data about the organization that runs the operation.

# For example:

Giving this example payload object:

payload:
    userId:
        data: User.Id
        type: struct

The value that will eventually be sent is the exact value under User.Id struct property, so the request body will looks like:

{
  "payload": {
    "userId": "$USER_ID_FROM_RELE_AI_STRUCT"
  }
}

# get_by_lang


Get by lang means that the value to be sent in the request is the value in translations where its key is equal to the value found in data.

# For example:

Giving this example payload object:

payload:
    content:
        data: request_contact_first_name
        type: get_by_lang

And a translation object that looks like this:

type: Translations

key: request_contact_first_name

lang: en

value: Can you share with me the contact's first name?

The value that will eventually be sent is:

{
  "payload": {
    "content": "Can you share with me the contact's first name?"
  }
}

# Input and Output

In some cases, we would like to run a number of operations before or after the operation we define runs.
For example, in some cases we would like to change one of the values ​​before or after sending the request for the operation, or delete some values from redis before or after the operation.

# format_function


The purpose of format_function is to modify data before or after sending a request.
Each object within the format fucntion defines several fields within it:
operation - what action we want to perform.
output - under which key in redis we want to save the result.
value - where the value on which we will execute the format is located.

Currently, we support four types of format_function: decrement increment encode_base64 get_length

  • decrement - decrease value.
  • increment - increase value.
  • encode_base64 - encode to base64.
  • get_length - returns the length of the value. For an array, it will return the length of the array, for string it will return the number of characters, and for an object it will return the number of keys in the object.

The result of the format function value, will be saved under a redis-key composed of a redis field defined in the same operation, plus the output defined in the format function.

# For example:

Assume for some example operation, you set the input object as follows:

input:
    format_function:
        - operation: increment
          output: increment_result
          args:
            amount: 1
          value:
            data: some:redis:path
            type: redis
            rkey_type: hash_map

And this redis configuration:

redis:
  type: hash_map
  field: hello_world_response

This means that the value found in redis under the key some:redis:path will be retrieved, an increment operation in 1 will be performed on the retrieved value - and the result will be saved under:

hello_world_response:increment_result

# redis_functions


The purpose of redis_functions is to change data on redis before or after the operation is execute.
For example, suppose we want to delete values ​​under a certain key in redis before or after the operation, or we want to place a value on a certain value in redis before or after the operation.
Each object within the redis fucntions defines several fields within it:
operation - what action we want to perform.
path - path for the values on redis.
Currently, we support three types of redis_functions: delete_keys set_field

  • delete_keys - delete values from redis.
  • set_field - set value to redis.

# For example:

Assume for some example operation, you set the output object as follows:

output:
    redis_functions:
        - operation: delete_key
          path: users-names*

The result will be that at the end of the operation run, all the keys in redis under the key users-names will be deleted.

# operation_type


NOTE

Relevant only for output operations.

Defines whether the session should be dropped after the operation, or continue.
You would like to use drop_session for the last operation in the workflow, or for an operation that handles errors.

# For example:

Assume for some example operation, you set the output object as follows:

output:
    operation_type: drop_session

The result will be that the current user's session will be deleted, including all the information that was in redis, and the workflow will stop running.

# Next and OnError

next and on_error points to the operations that should be execute after the current operation.
In the case of next, if the operation is completed successfully, the next operation that will run is the operation that next points to.
In the case of on_error, if the operation fails, the next operation that will run is the operation that on_error points to.

data attribute can hold:
workflow - Determines which workflow we are currently running
next - Pointer to the key of the next workflow/operation
rematch (optional) - In case the operation points to another workflow, we can set this flag to true - thus causing the match function to run again and determine which workflow should run.

# For example:

Assume for some example operation, you set next and on_error as follows:

# define on error selector
on_error:
  selector:
    - type: operation
      data:
        workflow: example-workflow
        next: send_error_message_to_user

# define next operation selector
next:
  selector:
    - type: operation
      data:
        workflow: example-workflow
        next: process-user-a

In case of success the next operation will be process-user-b and in case of failure the next operation will be send_error_message_to_user.

# Creating an Operation

The following is a full example of an Operation config. It creates a simple "Hello World" Operation within RELE.AI.

# define the type of the configuration
type: Operation

# define the selector instance
# point to the app action selector
selector:
    workflow:
      - hello_world
    app: whatsapp
    app_action: example-ac-id

# define the next operation pointers
next:
  selector:
    - type: operation
      data:
        workflow: hello_world
        next: process-user-b

# define the next operation in case of an error
on_error:
  selector:
    - type: operation
      data:
        workflow: example-workflow
        next: send_error_message

# define the payload data that will be sent to the
# integrated application
payload:
    limit:
        data: 100
        type: raw

# define as the starting point for the workflow
is_root: true

# define the input functions
# those functions fires before operation
# execution
input:

# define the output functions
# those functions fires after operation
# execution
output:

# define the redis-key and
# redis-type for the response
redis:
    field: hello_world_response
    type: hash_map

# the app identifier
key: hello-world

# Attribtues

Attribute Name Type Description
type string Define the configurations type. Full list of support types can be found here
is_root boolean determine if the operation is the first one on the flow
payload Payload The request body
next Next Pointer to the next operation
on_error OnError Defines the operation that will run in case of an error
input WorkflowEntryConditions The input functions
output WorkflowEntryConditions The output functions
redis Redis Redis object for response
key string A config identifier - must includes only a-b or 0-9 or _