## Template Expressions Overview

Template Expressions are a robust mechanism for accessing information related to requests, responses, and other key aspects of the router’s operation. They enable conditional feature activation and allow for extracting and configuring values dynamically. An example use case involves conditionally blocking mutations:

```
security:
  block_mutations:
    enabled: true
    condition: "request.header.Get('x-block-mutation') == 'yes'"
```

In this example, the condition is evaluated each time a request is made. Template Expressions provide access to request details, including headers, URLs, and query parameters. However, not all fields are consistently available throughout the request lifecycle. For instance, authentication data becomes accessible only after successful authentication. During the build process, the router validates expressions. If an expression is invalid or does not return the expected type (such as a boolean or string), an error message is generated to ensure clarity and correctness.

### Template Language

The expressions are based on the [expr-lang](https://github.com/expr-lang/expr) template language. This language is characterized by its:

- **Safety** – Expressions are evaluated securely.
- **Speed** – The language is optimized for performance.
- **Side-effect-free operation** – Expressions are read-only and do not alter state.

To modify configurations or manipulate requests and responses, implementing a [custom module](https://cosmo-docs.wundergraph.com/router/custom-modules) is recommended.

#### Naming Conventions

- **Fields**: Use camelCase (e.g., `request.auth.claims`).
- **Methods**: Use PascalCase (e.g., `request.header.Get("Content-Type")`).
- **Utility Functions**: camelCase (e.g. trim) for the full list see [here](https://expr-lang.org/docs/language-definition).

## Expression Context

### **Request Object**

The `request` object is a read-only entity that provides details about the incoming client request. It is accessible at all times during the lifecycle of the request.

**Available Fields**:

- `request.method`
- `request.url.host`
- `request.url.path`
- `request.url.port`
- `request.trace.sampled`
- `request.error`

### Operation Object

- `request.operation`
- `request.operation.name`
- `request.operation.type` (possible values: `mutation` or `query`)
- `request.operation.hash` - Hash of the normalized operation.
- `request.operation.queryPlanHash` - The Hash used as the query plan cache key.
- `request.operation.sha256Hash` - SHA-256 hash of the original operation query string sent by the client.
- `request.operation.parsingTime` (time.Duration)
- `request.operation.persistedId`
- `request.operation.normalizationTime` (time.Duration)
- `request.operation.validationTime` (time.Duration)
- `request.operation.planningTime` (time.Duration)
- `request.operation.resolverAcquireDuration` (time.Duration)
- `request.operation.normalizationCacheHit` (bool)
- `request.operation.variablesNormalizationCacheHit` (bool)
- `request.operation.variablesRemappingCacheHit` (bool)
- `request.operation.persistedOperationCacheHit` (bool)
- `request.operation.planCacheHit` (bool)
- `request.operation.variables` - The operation variables sent with the request, as a JSON string.

`request.operation.*` fields are populated during HTTP request handling. They are not available for WebSocket subscription access logs, which reuse the expression context from the initial HTTP upgrade request.

#### Example expressions

```
hasPrefix(request.operation.name, 'Delete') == true
request.operation.sha256Hash != ''
request.operation.persistedId != ''
request.operation.planCacheHit == true
# Log the variables only when the variable remapping cache missed.
request.operation.variablesRemappingCacheHit ? '' : request.operation.variables
```

### Client Object

- `request.client`
- `request.client.name`
- `request.client.version`

#### Example expressions

```
request.client.name == 'CoolGraphQLClient'
```

### **Header Access**:

- `request.header.Get('Content-Type')` – Header retrieval is case-insensitive.

#### Example expressions

```
request.url.query.foo == 'bar' && request.method == 'POST'
request.header.Get('x-block-mutation') == 'yes'
```

### Request Body Object

The body object holds information related to the request body. **Available Fields**:

- `request.body.raw`

#### Example expressions

```
request.error != nil ? request.body.raw : ''
```

### **Authentication Object**

The `auth` object contains authentication-related information for the request.

**Available Fields**:

- `request.auth`
- `request.auth.isAuthenticated`
- `request.auth.type`
- `request.auth.claims`
- `request.auth.scopes`

#### Example expressions

```
'read:miscellaneous' in request.auth.scopes
request.auth.isAuthenticated
```

### **Subgraph Object**

The Subgraph object provides information about the current subgraph being accessed in the request.

#### Properties

- `subgraph.id` (string)
- `subgraph.name` (string)
- `subgraph.request` (SubgraphRequest)

### SubgraphRequest Properties

- `subgraph.request.error` (error)
- `subgraph.request.clientTrace` (ClientTrace)
- `subgraph.request.startTime` (int)

#### Example expressions

```
subgraph.name == 'products'
subgraph.request.error != nil
subgraph.request.clientTrace.connAcquireDuration > 1.0
```

### **Response Object**

The `response` object provides details about the outgoing response.

**Available Fields**:

- `response.body` (ResponseBody)

### ResponseBody Object

The body object holds information related to the response body.

**Available Fields**:

- `response.body.raw` (string)

#### Example expressions

```
request.error != nil ? response.body.raw : ''
```

### Subgraph Retry Expressions

You can use expressions to specify the conditions for retries upon subgraph request failures.

## Functions

You can use all the [built-in functions](https://expr-lang.org/docs/language-definition#built-in-functions) of the Expr language.

### Additional Notes

- A Request for Comments (RFC) is [open](https://github.com/wundergraph/cosmo/pull/1481) for feedback on the complete API specification. Future implementations will be driven by customer requirements.
