CEL in YAML and example expressions
How to embed CEL expressions in YAML configuration, plus worked examples for common use cases.
CEL in YAML
When writing CEL expressions in agentgateway, typically they are expressed as YAML string values, which can cause confusion. Any string literals within the expression need to be escaped with additional quotes.
These examples all represent the same CEL expression, a string literal "hello".
doubleQuote: "'hello'"
doubleQuoteEscaped: "\"hello\""
singleQuote: '"hello"'
blockSingle: |
'hello'
blockDouble: |
"hello"These examples all represent the same CEL expression, a variable request:
doubleQuote: "request"
singleQuote: 'request'
block: |
requestThe block style is often the most readable for complex expressions, and also allows for multi-line expressions without needing to escape quotes.
Example expressions
Review the following examples of expressions for different use cases.
Default function
You can use the default function to provide a fallback value if the expression cannot be resolved.
Request header fallback with example of an anonymous user:
default(request.headers["x-user-id"], "anonymous")Nested object fallback with example of light theme:
default(json(request.body).user.preferences.theme, "light")JWTJWT (JSON Web Token)A compact, URL-safe token format used for securely transmitting information between parties. JWTs are commonly used for authentication and authorization in agentgateway. claim fallback with example of default “user” role:
default(jwt.role, "user")Logs, traces, and observability
# Include logs where there was no response or there was an error
filter: |
!has(response) || response.code > 299
fields:
add:
user.agent: 'request.headers["user-agent"]'
# A static string. Note the expression is a string, and it returns a string, hence the double quotes.
span.name: '"openai.chat"'
gen_ai.usage.prompt_tokens: 'llm.input_tokens'
# Parse the JSON request body, and conditionally log...
# * If `type` is sum, val1+val2
# * Else, val3
# Example JSON request: `{"type":"sum","val1":2,"val2":3,"val4":"hello"}`
json.field: |
json(request.body).with(b,
b.type == "sum" ?
b.val1 + b.val2 :
b.val3
)Authorization
mcpAuthorization:
rules:
# Allow anyone to call 'echo'
- 'mcp.tool.name == "echo"'
# Only the test-user can call 'add'
- 'jwt.sub == "test-user" && mcp.tool.name == "add"'
# Any authenticated user with the claim `nested.key == value` can access 'printEnv'
- 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"'Rate limiting
remoteRateLimit:
descriptors:
# Rate limit requests based on a header, whether the user is authenticated, and a static value (used to match a specific rate limit rule on the rate limit server)
- entries:
- key: some-static-value
value: '"something"'
- key: organization
value: 'request.headers["x-organization"]'
- key: authenticated
value: 'has(jwt.sub)'