Gravitee Expression Language (EL) is used to query and manipulate object graphs and dynamically configure various aspects and policies of an API. It allows you to reference values from the current API transaction to use expressions to create dynamic filters, routing rules, and policies that respond to specific conditions or parameters.
EL is an extended version of the Spring Expression Language (SpEL) that augments standard SpEL capabilities by providing additional object properties inside the expression language context. As an extension of SpEL, all capabilities detailed in the SpEL documentation are available in EL. However, Gravitee has implemented customizations that are detailed below.
{% hint style="info" %} Object properties
Custom properties and attributes have special meanings in the Gravitee ecosystem:
- Custom Properties: Defined at the API level and read-only during the Gateway's execution of an API transaction. You can learn more about how to set an API's custom properties here.
- Attributes: Scoped to the current API transaction and can be manipulated during the execution phase through the
assign-attributes
policy. Attributes are used to attach additional information to a request or message via a variable that is dropped after the API transaction is completed. {% endhint %}
The following sections define the scope and usage of EL:
The information below summarizes:
- Object properties added to the EL context
- How attributes are accessed for v4 and v2 APIs
- Commonly used operators and functions
{% tabs %} {% tab title="Syntax" %} Expressions
Expressions in Gravitee are enclosed in curly braces {}
and begin with the #
symbol. Both dot notation and bracket notation are supported for accessing the properties of an object.
Example: {#context.attributes['user'].email}
{% hint style="info" %} Dot notation vs bracket notation
Please note that dot notation will not work with special characters:
{#request.headers.my-header}
<- This will result in an error
Bracket notation should be used for property names that include a space or a hyphen, or start with a number:
{#request.headers['my-header']}
{% endhint %}
Lists
Expressions can be used to assign lists, e.g., {({'admin', 'writer'})}
- The outer enclosing brackets start and end the EL expression
- The parentheses indicates an object is being instantiated
- The list comprises the inner brackets and enclosed values, e.g.,
{'admin', 'writer'}
{% endtab %}
{% tab title="Object properties" %} EL allows you to reference certain values injected into the EL context as object properties. The available object properties will be further detailed in later sections. EL adds the following root-level object properties:
{#api.properties}
: Contains custom properties defined by the API publisher for that Gateway API.{#dictionaries}
: Contains custom dictionaries defined by the API publisher for that Gateway API.{#endpoints}
: Contains information about the Gateway API's respective endpoints.{#request}
: Contains information about the current API request.{#response}
: Contains information about the current API response.{#message}
: Contains information about the current API message.{#node}
: Contains information about the node hosting the instance of the Gateway handling the API transaction. {% endtab %}
{% tab title="Attributes" %}
The attributes
object property contains attributes that are automatically created by the APIM Gateway during an API transaction or added during the execution phase through the Assign Attributes policy. However, attributes fall into one of two categories based on API type:
{#context.attributes}
: Contains attributes associated with v2 APIs or v4 Proxy APIs. A v4 Proxy API is created using the Proxy upstream protocol method.{#message.attributes}
: Contains attributes associated with v4 Message APIs. These APIs are created using the Introspect messages from event-driven backend method.
See the v4 API creation wizard for more details. {% endtab %}
{% tab title="Operators" %} EL supports various operators, such as arithmetic, logical, comparison, and ternary operators. Examples of commonly used operators in Gravitee include:
- Arithmetic operators:
+, -, *, /
- Logical operators:
&& (logical and), || (logical or), ! (logical not)
- Comparison operators:
==, !=, <, <=, >, >=
- Ternary operators:
condition ? expression1 : expression2
{% endtab %}
{% tab title="Functions" %} EL provides a variety of built-in functions to manipulate and transform data in expressions. Examples of commonly used functions in Gravitee include:
- String functions:
length(), substring(), replace()
#jsonPath
: Evaluates ajsonPath
on a specified object. This function invokesJsonPathUtils.evaluate(…)
, which delegates to the Jayway JsonPath library. The best way to learn jsonPath syntax is by using the online evaluator.#xpath
: To evaluate anxpath
on some provided object. For more information regarding XML and XPath, see XML Support - Dealing with XML Payloads in the SpEL documentation.
As an example of how jsonPath
can be used with EL, suppose you have a JSON payload in the request body that contains the following data:
{
"store": {
"book": [
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
]
}
}
To extract the value of the price
property for the book with title
"The Lord of the Rings," you can use the following expression:
{#jsonPath(#request.content, "$.store.book[?(@.title=='The Lord of the Rings')].price")}
{% endtab %}
{% endtabs %}
Using EL, you can access information about an API transaction through several root-level objects that are injected into the EL context: custom properties, dictionaries, and endpoints.
{% tabs %}
{% tab title="Custom properties" %}
As an API publisher, you can define custom properties for your API. These properties are automatically injected into the expression language context and can be referenced during an API transaction from the {#api.properties}
root-level object property.
- Get the value of the property
my-property
defined in an API's custom properties using{#api.properties['my-property']}
- Get the value of the property
my-secret
defined and encrypted in an API's custom properties using{#api.properties['my-secret']}
to pass a secured property to your backend
{% hint style="info" %} Encrypted custom properties
When accessing an encrypted custom property, Gravitee's Gateway will automatically manage the decryption and provide a plain text value. {% endhint %} {% endtab %}
{% tab title="Dictionaries" %}
Dictionaries work similarly to custom properties, but you need to specify the dictionary ID as well as the dictionary property name. Dictionary properties are simply key-value pairs that can be accessed from the {#dictionaries}
root-level object property.
Get the value of the dictionary property dict-key
defined in dictionary my-dictionary-id
using {#dictionaries['my-dictionary-id']['dict-key']}
.
{% endtab %}
{% tab title="Endpoints" %}
When you define endpoints for your API, you need to give them a name that is a unique identifier across all endpoints of the API. This identifier can be used to get an endpoint reference (i.e., a URI) from the {#endpoints}
root-level object property.
When you create an API, a default endpoint is created that corresponds to the value you set for the backend property. This endpoint can be retrieved with EL by using the following syntax: {#endpoints['default']}
.
{% endtab %}
{% endtabs %}
EL can be used to access request properties and attributes as described below.
The object properties you can access from the {#request}
root-level object property and use for API requests are listed below.
{% tabs %} {% tab title="Table" %}
Object Property | Description | Type | Example |
---|---|---|---|
content | Body content | string | - |
contextPath | Context path | string | /v2/ |
headers | Headers | key / value | X-Custom → myvalue |
host | The host of the request. This is preferable to using the Host header of the request because HTTP2 requests do not provide this header. | string | gravitee.example.com |
id | Identifier | string | 12345678-90ab-cdef-1234-567890ab |
localAddress | Local address | string | 0:0:0:0:0:0:0:1 |
method | HTTP method | string | GET |
params | Query parameters | key / value | order → 100 |
path | Path | string | /v2/store/MyStore |
pathInfo | Path info | string | /store/MyStore |
pathInfos | Path info parts | array of strings | [,store,MyStore] |
pathParams | Path parameters | key / value | storeId → MyStore (see Warning for details) |
pathParamsRaw | Path parameters | string | /something/:id/** |
paths | Path parts | array of strings | [,v2,store,MyStore] |
remoteAddress | Remote address | string | 0:0:0:0:0:0:0:1 |
scheme | The scheme of the request (either http or https ) | string | http |
host | string | ||
ssl | SSL session information | SSL object | - |
timestamp | Timestamp | long | 1602781000267 |
transactionId | Transaction identifier | string | cd123456-7890-abcd-ef12-34567890 |
uri | URI | string | /v2/store/MyStore?order=100 |
version | HTTP version | string | HTTP_1_1 |
{% tab title="Examples" %}
- Get the value of the
Content-Type
header for an incoming HTTP request using{#request.headers['content-type']}
- Get the second part of the request path using
{#request.paths[1]}
{% endtab %} {% endtabs %}
When APIM Gateway handles an incoming API request, some object properties are automatically created or added during the execution phase through the Assign Attributes policy. These object properties are known as attributes. Attributes can be accessed from the {#context.attributes}
root-level object property.
Some policies (e.g., the OAuth2 policy) register other attributes in the request context. For more information, refer to the documentation for individual policies.
Request context attributes and examples are listed below.
{% tabs %} {% tab title="Table" %}
Object Property | Description | Type | Nullable |
---|---|---|---|
api | Called API | string | - |
api-key | The API key used (for an API Key plan) | string | X (for no API Key plan) |
application | The authenticated application making incoming HTTP requests | string | X (for Keyless plan) |
context-path | Context path | string | - |
plan | Plan used to manage incoming HTTP requests | string | - |
resolved-path | The path defined in policies | string | - |
user-id | The user identifier of an incoming HTTP request: * The subscription ID for an API Key plan * The remote IP for a Keyless plan | string | - |
{% tab title="Examples" %}
- Get the value of the
user-id
attribute for an incoming HTTP request using{#context.attributes['user-id']}
- Get the value of the
plan
attribute for an incoming HTTP request using{#context.attributes['plan']}
{% endtab %} {% endtabs %}
The object properties you can access in the ssl
session object from the {#request.ssl}
root-level object property are listed below.
{% tabs %} {% tab title="Table" %}
Object Property | Description | Type | Example |
---|---|---|---|
clientHost | Host name of the client | string | client.domain.com |
clientPort | Port number of the client | long | 443 |
client | Client information | Principal object | - |
server | Server information | Principal object | - |
{% tab title="Example" %}
Get the client HOST from the SSL session using {#request.ssl.clientHost}
{% endtab %}
{% endtabs %}
The client
and server
objects are of type Principal
. A Principal
object represents the currently authenticated user who is making the request to the API and provides access to various user attributes such as username, email address, roles, and permissions.
The Principal
object is typically used with security policies such as OAuth2, JWT, or basic authentication to enforce access control and authorization rules on incoming requests. For example, a policy can check if the current user has a specific role or permission before allowing them to access a protected resource.
If the Principal
object is not defined, client
and server
object values are empty. Otherwise, there are domain name attributes you can access from the {#request.ssl.client}
and {#request.ssl.server}
Prinicipal
objects as shown in the table below:
{% hint style="warning" %} Limitation on arrays
All attributes of the Principal
object are flattened to be accessed directly with dot or bracket notation. While some of these attributes can be arrays, EL will only return the first item in the array. To retrieve all values of an attribute, use the attributes
object property shown in the table and examples below.
{% endhint %}
{% tabs %} {% tab title="Table" %}
Object Property | Description | Type | Example |
---|---|---|---|
attributes | Retrieves all the Prinicipal object's domain name attributes | key / value | "ou" → ["Test team", "Dev team"] |
businessCategory | Business category | string | - |
c | Country code | string | FR |
cn | Common name | string | - |
countryOfCitizenship | RFC 3039 CountryOfCitizenship | string | - |
countryOfResidence | RFC 3039 CountryOfResidence | string | - |
dateOfBirth | RFC 3039 RFC 3039 DateOfBirth | string | 19830719000000Z |
dc | Domain component | string | - |
defined | Returns true if the Principal object is defined and contains values. Returns false otherwise. | boolean | - |
description | Description | string | - |
dmdName | RFC 2256 directory management domain | string | - |
dn | Fully qualified domain name | string | - |
dnQualifier | Domain name qualifier | string | - |
e | Email address in Verisign certificates | string | - |
emailAddress | Email address (RSA PKCS#9 extension) | string | - |
gender | RFC 3039 Gender | string | "M", "F", "m" or "f" |
generation | Naming attributes of type X520name | string | - |
givenname | Naming attributes of type X520name | string | - |
initials | Naming attributes of type X520name | string | - |
l | Locality name | string | - |
name | Name | string | - |
nameAtBirth | ISIS-MTT NameAtBirth | string | - |
o | Organization | string | - |
organizationIdentifier | Organization identifier | string | - |
ou | Organization unit name | string | - |
placeOfBirth | RFC 3039 PlaceOfBirth | string | - |
postalAddress | RFC 3039 PostalAddress | string | - |
postalCode | Postal code | string | - |
pseudonym | RFC 3039 Pseudonym | string | - |
role | Role | string | - |
serialnumber | Device serial number name | string | - |
st | State or province name | string | - |
street | Street | string | - |
surname | Naming attributes of type X520name | string | - |
t | Title | string | - |
telephoneNumber | Telephone number | string | - |
uid | LDAP User id | string | - |
uniqueIdentifier | Naming attributes of type X520name | string | - |
unstructuredAddress | Unstructured address (from PKCS#9) | string | - |
{% tab title="Examples" %}
- Get the client DN from the SSL session:
{#request.ssl.client.dn}
- Get the server organization from the SSL session:
{#request.ssl.server.o}
- Get all the organization units of the server from the SSL session:
{#request.ssl.server.attributes['ou'][0]}
{#request.ssl.server.attributes['OU'][1]}
{#request.ssl.server.attributes['Ou'][2]}
- Get a custom attribute of the client from the SSL session:
{#request.ssl.client.attributes['1.2.3.4'][0]}
- Determine if the SSL attributes of the client are set:
{#request.ssl.client.defined}
{% endtab %} {% endtabs %}
The object properties you can access for API responses from the {#response}
root-level object property are listed below.
{% tabs %} {% tab title="Table" %}
Object Property | Description | Type | Example |
---|---|---|---|
content | Body content | string | - |
headers | Headers | key / value | X-Custom → myvalue |
status | Status of the HTTP response | int | 200 |
{% tab title="Example" %}
Get the status of an HTTP response: {#response.status}
{% endtab %}
{% endtabs %}
The object properties you can access for API messages from the {#message}
root-level object property are listed below. A message (either sent or received) may also contain attributes that can be retrieved via {#message.attributes[key]}
.
{% hint style="info" %} The EL used for a message does not change based on phase. EL is executed on the message itself, so whether the message is sent in the subscribe or publish phase is irrelevant. {% endhint %}
{% tabs %} {% tab title="Table" %}
Object Property | Description | Type | Example |
---|---|---|---|
attributeNames | The names of the attributes | list / array | - |
attributes | Attributes attached to the message | key / value | - |
content | Content of the message | string | - |
contentLength | Size of the content | integer | - |
error | Flag regarding the error state of the message | boolean | - |
headers | Headers attached to the message | key / value | - |
id | ID of the message | string | - |
metadata | Metadata attached to the message | key / value | - |
{% tab title="Examples" %}
- Get the value of the
Content-Type
header for a message using{#message.headers['content-type']}
- Get the size of a message using
{#message.contentLength}
{% endtab %} {% endtabs %}
A node is a component that represents an instance of the Gravitee Gateway. Each node runs a copy of the Gateway that is responsible for handling incoming requests, executing policies, and forwarding requests to the appropriate upstream services. The object properties you can access for nodes from the {#node}
root-level object property are listed below.
{% tabs %} {% tab title="Table" %}
Object Property | Description | Type | Example |
---|---|---|---|
id | Node ID | string | 975de338-90ff-41ab-9de3-3890ff41ab62 |
shardingTags | Node sharding tag | array of string | [internal,external] |
tenant | Node tenant | string | Europe |
version | Node version | string | 3.14.0 |
zone | Zone the node is grouped in | string | europe-west-2 |
{% tab title="Example" %}
Get the version of a node : {#node.version}
{% endtab %}
{% endtabs %}
In previous examples, we showed various ways to manipulate objects available in the EL context. You can also mix root-level object property usage to provide an increasingly dynamic configuration.
For example, to retrieve the value of an HTTP header where the name is based on an API custom property named my-property
, use {#request.headers[#api.properties['my-property']]}
.
You can use the EL to update some aspects of policy configuration. The policy specifies if it supports EL or not by including a Condition section in the Policy Studio configuration.
Assign attributes policy supports EL conditions
You can use the EL to set a condition of execution (see 'conditional policies and flows conditions') and it is possible to use logical operators such as &&
or ||
, as shown in the example below:
{#request.headers['my-header'] != null && #request.headers['my-header'][0] =="my-value"}
{% hint style="info" %} Alternate equality check
You can use the equals()
method instead of ==
. When you use .equals()
, it is recommended to put the string first to prevent an error. For example, if #request.headers['my-header']
is null
, then 'my-value'.equals(#request.headers['my-header'])
will prevent an error.
{% endhint %}
In case of an error when using EL, an exception will be raised :
The template evaluation returns an error. Expression: {#context.error}
If debugging your expression is difficult, consider the following example for guidance:
Assume {#request.content.length() >= 10}
is the conditional expression on a flow. When testing, you are expecting the condition to evaluate to false
and stop the flow from executing, but the flow continues to function unexpectedly. To check the actual output of the #request.content.length()
expression, use the Assign Attributes policy as shown in the arcade below.
{% @arcade/embed flowId="Q5mHqjjdv2gzuuVwLffu" url="https://app.arcade.software/share/Q5mHqjjdv2gzuuVwLffu" %}