Expressions
Expressions are a powerful way to define the conditions under which specific actions in a traffic policy are triggered. Expressions are written in the Common Expression Language (CEL) and allow you to evaluate various traffic attributes, such as headers, paths, IP addresses, and more.
Each expression must evaluate to true
for the corresponding actions in a rule to be executed. If a rule contains no expressions, it will always evaluate to true
, causing its actions to be applied to all matching traffic.
Available Elements
Expressions in traffic policies can reference a variety of elements, including:
- Traffic Policy Variables: These allow you to access metadata about the connection or request, such as certificate details, headers, client IP, geo-location and more.
- Traffic Policy Macros: Macros simplify complex conditions, enabling reusable patterns across expressions and policies.
- Action Variables: Some actions may provide additional variables, enabling deeper customization based on specific action outcomes.
Use-Cases
Expressions give you the flexibility to:
- Filter traffic: Evaluate headers, IP addresses, or other attributes to decide if traffic should match a given rule.
- Route traffic: Forward traffic based on factors such as geolocation, protocol, or path.
- Control flow: Implement more complex routing decisions based on dynamic conditions, ensuring optimal traffic handling.
Common Examples
Match Based on Header
expressions:
- req.headers["authorization"][0] == "Bearer my-token"
Match Requests to a Specific Path
expressions:
- req.path.startsWith("/api/v1/")
Match by Country
expressions:
- conn.client_ip.geo.location.country_code == "US"
Writing Expressions
Basic Syntax
Expressions are written in CEL and are similar to expressions in languages like C, JavaScript, or Python. They can include variables, literals, and operators.
Variables
Variables refer to values. For example, identity
might refer to a user object.
expressions:
- identity.age >= 18 // Checks if the user's age is 18 or more.
View list of available variables
Literals
CEL supports several literal types:
- Boolean:
true
,false
- Integer:
42
,-7
- String:
"hello"
,'world'
- List:
[1, 2, 3]
- Map:
{"key1": "value1", "key2": "value2"}
Operators
CEL provides a rich set of operators for arithmetic, comparison, and logical operations:
- Arithmetic:
+
,-
,*
,/
,%
- Comparison:
==
,!=
,<
,<=
,>
,>=
- Logical:
&&
,||
,!
Using Arithmetic
5 * (3 - 1) // Evaluates to 10
Using Comparison and Logical Operators
// Checks if the user is 18 or older and is in the US
identity.age >= 18 && identity.country == "US"
Strings
String Concatenation
To combine strings, use the +
operator:
"Hello, " + "world!" // Results in "Hello, world!"
String Functions
CEL provides several built-in functions to work with strings, enabling you to perform transformations, query information, or compare strings.
size()
Returns the number of characters in the string:
size("Hello") // Evaluates to 5
startsWith()
Checks if the string starts with a specified substring:
"Hello, world".startsWith("Hello") // Evaluates to true
endsWith()
Checks if the string ends with a specified substring:
"Hello, world".endsWith("world") // Evaluates to true
matches()
Determines if the string matches a regular expression pattern:
"Hello, world".matches("H.*d") // Evaluates to true
contains()
To check if a string contains another string:
"Hello, world!".contains("world") // Evaluates to true
Advanced String Manipulation
Regular Expressions
CEL's matches()
function allows you to use regular expressions for pattern matching. This can be powerful for validation or extracting parts of strings:
// Evaluates to true for a valid email format
"user@example.com".matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$")
Concatenation and Interpolation
While direct string interpolation isn't a feature in CEL, concatenation can be used to dynamically construct strings:
// Interpolates number to string
"Your order number is: " + string(order_number)
Working with Unicode
Strings in CEL are Unicode and can handle a wide range of characters:
// Evaluates to 5, as there are 5 characters in this Japanese greeting
size("こんにちは")
String Comparison
String comparison in CEL is case-sensitive and uses the standard comparison operators:
"apple" == "Apple" // Evaluates to false due to case difference
"apple" < "banana" // Alphabetically compares strings, evaluates to true
Lists
A list in CEL is an ordered collection of elements. You can perform various operations on lists, including checking if an item is contained within a list, accessing elements by their index, and iterating over elements.
Creating a List
var my_list = [1, 2, 3, 4]
Checking for Membership
To check if a value exists in a list, use the in
operator:
2 in my_list; // Evaluates to true
5 in my_list; // Evaluates to false
Accessing Elements
Access elements by their index (0-based):
// Accesses the second element, evaluates to 2
my_list[1];
Counting Elements
Returns the number of elements in the list:
size(my_list) // Evaluates to 4
Iterating Over a List
Use a comprehension to iterate over elements in a list and apply logic:
// Doubles each value in the list, resulting in [2, 4, 6, 8]
[value * 2 for value in my_list]
Filtering a List
Filter a list to include only certain elements:
// Keeps only values greater than 2, resulting in [3, 4]
[value for value in my_list if value > 2]
Membership in Lists
The in
operator is versatile and can be used to check for membership in both lists:
// For maps (checks keys)
"apple" in { apple: 1, banana: 2 } // true
Maps
A map in CEL is a collection of key-value pairs. Keys are unique, and each key maps to exactly one value. You can check for the presence of keys, access values by their keys, and iterate over keys or values.
Creating a Map
var my_map = { a: 1, b: 2, c: 3 }
Checking for Key Presence
To check if a key is present in a map, use the in
operator:
"a" in my_map; // Evaluates to true
"d" in my_map; // Evaluates to false
Accessing Values
Access values by their keys:
// Accesses the value for the key "a", evaluates to 1
my_map["a"]
Counting Elements
Returns the number of key-value pairs present in the map:
size(my_map) // Evaluates to 3
Iterating Over a Map
You can iterate over the keys or values of a map using a comprehension:
// Extracts all keys, resulting in ["a", "b", "c"]
[key for key, value in my_map]
// Extracts all values, resulting in [1, 2, 3]
[value for key, value in my_map]
Checking for a Condition in a Map
Use exists
or all
macros to check if any or all elements in a collection meet a condition:
// Checks if any key in the map starts with "a"
my_map.exists(key, key.startsWith("a")) // Evaluates to true
// Checks if all values in the map are greater than 0
my_map.all(value, value > 0) // Evaluates to true
Membership in Maps
The in
operator is versatile and can be used to check for membership in maps:
// For maps (checks keys)
"apple" in { apple: 1, banana: 2 } // true