# 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 _ |
← Workflows Application →