Expressions
Powerful templating language and formulas to manipulate data.
The concepts explained in this section are all very interdependent on one another, so we’ve added a cheatsheet to help you get started.
Expressions Overview
Expressions are a powerful feature in Tracecat that gives you fine-grained control over your action logic.
They are strings that can be evaluated into a value or data/object reference, prefixed with a context and wrapped in template ${{ ... }}
syntax.
We use JSONPath expressions (dot notation) to access data, objects, or functions inside JSON-like data structures.
In object-oriented programming terms, you can think of this as method invocation or attribute access on a specific context (analagous to a class or instance).
Some examples of expressions:
${{ SECRETS.my_secret.SUPER_SECRET }}
${{ ACTIONS.my_action.result }}
${{ FN.add(1, 2) }}
${{ INPUTS.my_input }}
${{ TRIGGER.my_trigger }}
Our convention is to use lower_snake_case
if you need to replace whitespace
in your paths.
We also support typecasting for expressions:
${{ <expression> -> <type> }}
Types we currently support are int
, str
, bool
, and float
.
For example, this expression will return the integer literal 3:
${{ FN.add(1, 2) -> int }}
Expression Contexts
An expression context is a top-level namespace that changes the behavior of an expression.
Tracecat expression contexts are all uppercase qualifiers, e.g. SECRETS
.
We use dot notation or JSONPath expressions to access data, objects, or functions in a particular context. We currently support the following contexts:
Qualifier | Expression syntax | Description |
---|---|---|
SECRETS | SECRETS.<name>.<key> | Secrets manager |
ACTIONS | ACTIONS.<jsonpath>.result | The active workflow’s execution results |
FN | FN.<fn_name>(<arg1>, <arg2>, ...) | Inline functions |
INPUTS | INPUTS.<jsonpath> | The active workflow’s static inputs |
TRIGGER | TRIGGER.<jsonpath> | The active workflow’s trigger inputs |
Template syntax
Tracecat’s template syntax takes inspiration from Github Actions, so it may feel familiar to you!
A template is a string with a ${{ ... }}
pattern that wraps an expression:
${{ <expression> }}
Templates can exist in two forms: full templates and inline templates.
Full templates
A full template is a sstring that only contains a single template with no surrounding whitespace:
"${{ ... }}"
It follow that when a full template wraps an expression, we call this a full expression:
"${{ <expression> }}"
The final datatype of the above expression depends on the return type of the expression and whether there is a typecast.
This expression will return integer literal 3
because FN.add(1, 2)
returns an integer:
"${{ FN.add(1, 2) }}"
In contrast, this expression will return string literal "3"
because FN.add(1, 2)
was cast to a string:
"${{ FN.add(1, 2) -> str}}"
In YAML, by convention we omit the quotes around full expressions:
actions:
- ref: my_action
action: example.action
args:
value: ${{ FN.add(1, 2) }}
Inline templates
An inline template is a string where all templates are in the string body:
"An inline template ${{ ... }} looks ${{ ... }} like this."
As you’d expect, the following is called an inline expression:
"An inline template ${{ <expression-1> }} looks ${{ <expression-2> }} like this."
The final datatype of the above expression is always a string.
For example, this expression:
"An inline template ${{ FN.add(1, 2) }} looks ${{ FN.add(1, 2) -> str }} like this."
will return string literal "An inline template 3 looks 3 like this."
:
In YAML, by convention we wrap quotes around inline expressions:
actions:
- ref: my_action
action: example.action
args:
value: "An inline template ${{ FN.add(1, 2) }} looks ${{ FN.add(1, 2) -> str }} like this."
Expression Types
Action Expressions
Action expressions are JSONPaths that target the ACTIONS
context. It references data or objects that are returned from completed actions.
${{ ACTIONS.<jsonpath>.result }}
For example, if you have an action that was defined with the following UDF in your workflow definition:
@registry.register(namespace="example", description="Adds two numbers.")
def add(lhs: int, rhs: int) -> int:
return lhs + rhs
and the following snippet of YAML in your workflow definition:
actions:
- ref: add_two_numbers
action: example.add
args:
lhs: 1
rhs: 2
Then anywhere else in your workflow definition and given add_two_numbers
has completed, you can use the ACTIONS.add_two_numbers.result
expression to access the result of the action.
Revisiting the example above, if you added another action to the same workflow:
actions:
- ref: add_two_numbers
action: example.add
args:
lhs: 1
rhs: 2
- ref: add_three_numbers
action: example.add
depends_on:
- add_two_numbers
args:
lhs: ${{ ACTIONS.add_two_numbers.result }} # This evaluates to 3!
rhs: 3
you can use upstream computations in your downstream actions.
Tracecat’s workflow engine doesn’t enforce that actions require hierarchical dependencies on other actions to use their results. So long an action in the same workflow is completed, another action can use its result.
Action expressions always contain the following predefined keys:
Key | Description |
---|---|
result | Contains the action’s result. |
result_typename | The Python type annotation of the action’s result. |
Input Expressions
Input expressions are JSONPath expressions that target the INPUTS
context.
${{ INPUTS.<jsonpath> }}
Given the following static workflow inputs:
inputs:
company: Tracecat
url: https://tracecat.com
contact:
email: founders@tracecat.com
location: San Francisco, CA
Some valid input expressions would look like:
${{ INPUTS.company }}
${{ INPUTS.url }}
${{ INPUTS.contact.email -> str }}
${{ INPUTS.contact.location }}
Trigger Expressions
Trigger expressions are JSONPath expressions that target the TRIGGER
context.
${{ TRIGGER.<jsonpath> }}
Given the following webhook call:
curl -X POST $WEBHOOK_URL -H "Content-Type: application/json" -d '{
"event_type": "update",
"source": "http://data-source.com",
"metadata": {
"time":"Thursday, May 20th 11:40pm",
"platform":"cool_platform"
}
}'
Some valid input expressions would look like:
${{ TRIGGER.event_type }}
${{ TRIGGER.metadata.time }}
Secret Expressions
Secret expressions are JSONPath expressions that target the SECRETS
context.
They allow you to pull created secrets from the Secrets Manager at runtime.
${{ SECRETS.<name>.<key> }}
Given the following secrets created like such:
curl -X PUT $TRACECAT__API_URL/secrets \
-H "Content-Type: application/json" \
-d '{
"type":"custom",
"name":"some_secret",
"keys":[
{
"key":"SOME_API_KEY",
"value": "SOME_SECRET_VALUE"
}
]
}'
To use SOME_SECRET_VALUE
in your workflow, you would use the following expression:
${{ SECRETS.my_secret.SOME_API_KEY }}
For instance, to make an API call:
actions:
- ref: my_action
action: core.http_request
args:
url: https://api.some-example.com
headers:
Authorization: Bearer ${{ SECRETS.some_secret.SOME_API_KEY }}
...
Function Expressions
Function expressions are expressions that target the FN
context.
${{ FN.<fn_name>(<arg1>, <arg2>, ...) }}
Our syntax allows for nested expressions, so you can use the result of one function as an argument to another function:
${{ FN.add(FN.add(1, 2), 3) }}
Supported Functions
Name | Description |
---|---|
less_than | less than comparison |
less_than_or_equal | less than or equal comparison |
greater_than | greater than comparison |
greater_than_or_equal | greater than or equal comparison |
not_equal | not equal comparison |
is_equal | equal comparison |
not_null | check if value is not null |
is_null | check if value is null |
regex_extract | extract match using regex pattern |
regex_match | check if text matches regex pattern |
regex_not_match | check if text does not match regex pattern |
contains | check if container contains item |
does_not_contain | check if container does not contain item |
length | get the length of a collection |
is_empty | check if collection is empty |
not_empty | check if collection is not empty |
add | add two numbers |
sub | subtract two numbers |
mul | multiply two numbers |
div | divide two numbers |
mod | get the modulus of two numbers |
pow | raise a number to a power |
sum | sum a collection of numbers |
join | join items in a list with a separator |
concat | concatenate multiple items into a string |
format | format a string |
and | logical and operation |
or | logical or operation |
not | logical not operation |
serialize_json | convert json to string |
from_timestamp | convert timestamp to datetime |
This list is not exhaustive, and we plan to add more functions in the future.
Typecasts
We support the following typecasts:
Type | Python Type |
---|---|
int | int |
float | float |
str | str |
bool | Custom bool - true for any truthy value, 1 , or upper/lower case true |
You can perform a typecast on an expression like so:
Evaluation Procedure
Before an action runs, Tracecat performs the following steps to evaluate the expressions in the action:
- Find all secrets that are declared in secret expressions
- Pull these into the execution context
- Evaluate all types of expressions in one pass
After doing the above it then proceeds to run the action’s associated UDF.
Cheatsheet
Terminology
Term | Description |
---|---|
Context | A top-level namespace that changes the behavior of an expression, e.g. SECRETS or ACTIONS |
Expression | A string that can be evaluated into a value or data/object reference, often involving a context . |
Template | A string holding an expression ${{ <expr> }} that evaluates into a value or data/object reference. |
Full template | A string that only contains one template: "${{ ... }}" |
Full expression | A full template string with an expression: "${{ <expr> }}" |
Inline template | All templates are inline, e.g. "An inline template ${{ ... }} looks like this." |
Inline expression | All templates have expressions and are inline, e.g. "An inline expression ${{ <expr> }} looks like this." |
Contexts
Qualifier | Description |
---|---|
SECRETS | Secrets manager context. The expression SECRETS.my_secret.SUPER_SECRET will return my_secret.SUPER_SECRET ’s stored value. |
ACTIONS | The active workflow’s execution context. Lets you access results from completed actions. |
FN | Inline functions. The expression FN.add(1, 2) will return 3 . |
INPUTS | The active workflow’s static inputs. Lets you access static inputs from the workflow definition. |
TRIGGER | The active workflow’s trigger inputs. Lets you access dynamic inputs from a webhook. |