Introduction

Flows allow you to string together a number of predefined steps (like making an HTTP request or sending an email), either before triggering a Smart Clause, or in  response to a Smart Clause emitting an event. Steps are executed in the order defined in the flow, and only responds to input provided by you, the user.

Steps in a flow need to be able to reference each other's outputs, for instance, when a value returned by an HTTP step has to be used in an Email step to formulate a notification to send to the user.

To facilitate this, Flows include a simple expression language to allow the user to define step inputs that depend on the outputs of previous steps in a flow.

Flow Output Context

A flow is a graphical integration environment that allows the user to define a collection of steps that are executed in a specific order, when triggered by some trigger input.

Steps are executed in the order that they are defined in in the flow, and the user can reference the outputs of previous steps in the flow in a step's input when creating the flow, thus making steps dependent on each other.

The context every step can reference consists of an object with a single attribute called step, which is an array of objects, each representing the context for a single step in the flow. Every step currently only exposes a single attribute in its context, and that is output. The output of the first element in the array (step[0].output) represents the input to the entire flow (ie the output of the entity that triggers the flow).

step[n].output (where n > 0) contains the output of the nth user-defined step in the flow.

Organisation Vault Context

In Clause, Organisation secrets (which, for example,  includes API tokens generated when adding an app) are stored in a service called The Vault.

These vault secrets can also be referenced using flow expressions, and are all exposed in an attribute called vault.

{{% vault.SecretName.SecretAttribute %}}

Vault Secrets are always name spaced against a SecretName, and accessed by a SecretAttribute. The way to, for instance, access the ApiKey attribute of a connected service called MyService, would be through the following reference:

{{% vault.MyService.ApiKey %}}

Flow Expressions

Flow expressions can be used in two contexts:

  1. string, for instance when the user is entering a url or email address
  2. object, for instance when the user is defining an attribute in a JSON payload that has to be sent to an HTTP service. 

String expressions

A flow string expression is a reference enclosed in brace-percentage, percentage-brace. For example, the flow expression:

{{% step[1].output.key %}}

Refers to the key attribute returned by the step at index 1.

User-defined steps start at index n=1, and index n=0 always represents the input to the flow: the trigger payload for trigger flows, the emitted obligation for action flows.

Examples:

Given the following payload sent as POST body to a trigger flow:

{
  "Person": {
    "Name": "Peter Peterson",
    "Age": 34
  }
}

The Name attribute can be referenced in any of the steps in the flow as {{%step[0].output.Person.Name%}}

If the first user-defined step (step 1) returns the array:

[ "Peter Peterson", "John Johnson" ]

The second element in the array can be referenced as {{% step[1].output[1] %}}

Let's say the second user-defined step then outputs the following object:

{
  "Persons": [
    {
      "Name": "Peter Peterson",
      "Age": 34
    },
    {
      "Name": "John Johnson",
      "Age": 34
    }
  ]
}

The second Person's Name attribute can be referenced in subsequent steps as {{%step[2].output.Persons[1].Name%}}

Single-expression flow expressions will always return an item whose type matches the target. In other words, given the object above, {{%step[2].output.Persons[1]%}} will return an object, and {{%step[2].output.Persons[1]%}} will return an array.

 In contrast {{%step[2].output.Persons[1]%}} {{%step[2].output.Persons%}} will return a string (the object and the array, serialised and concatenated).

In-object expressions

In the context of an object input, for instance when defining the body of an HTTP request, the above way of defining flow expressions can become awkward.

Inside an object, we will always evaluate an object with a $flowExp attribute as containing a reference to a previous step output (or flow input, where n = 0).

In the following example, for instance, we are defining the body of the http request to be the entire input of the flow, as is.

{
  "$flowExp": "step[0].output"
}

Two things to take note of:

  1. the omission of the brace-percentage markers around the expression
  2. the fact that the entire object (or sub-object) will be replaced by whatever is matched by the reference, not just the expression itself. 

In a slightly more complex example, we might want to send the entire payload of an obligation emitted by a contract to an external service, as the obligation attribute of the HTTP payload. This would be achieved as such:

{
  "obligation": {
    "$flowExp": "step[0].output"
  }
}

For more complex expressions and transformations, we provide a JSON transformation step, which evaluates a freeform JSONata expression.