Reference

proxy.toml Reference

proxy.toml reference for API route configuration, header injection, dynamic routes, path parameters, payload filters, and status normalization.

proxy.toml Reference

Placed in app/proxy.toml to configure API routing for Application Modules.

[[route]]
# Path pattern with dynamic parameter capture
path = "/api/v1/pools/{pool_id}/volumes/{vol_id}"
target = "https://backend.internal/v2/pools/{{ request.params.pool_id }}/vols/{{ request.params.vol_id }}"

# Forward these headers from the client
forward_headers = ["Accept", "Authorization"]

# Inject secure headers from the backend
[route.inject_headers]
"Authorization" = "Bearer ${env.API_TOKEN}"

# Inbound payload transformation (client contract -> backend payload)
[route.request_filter]
"tera!" = '{"volume_name": "{{ request.params.vol_id }}", "size_bytes": {{ body.size_gb * 1024 }}}'

# Outbound payload transformation (backend response -> client contract)
[route.response_filter]
"jmespath!" = '{"id": id, "status": state}'

# Status code and header normalization
[route.response_mapping]
status_from_body = [
  { when = "response.status == 'failed'", return_status = 400 }
]
override_headers = { "Content-Type" = "application/json" }

# Graph-driven dynamic routes
[[route]]
origin_resource = "provider"
match_on = [{ property = "type", value = "internal" }]
path = "/api/{{ origin_resource.name }}/*"
target = "{{ origin_resource.api_url }}/"

Variables like ${env.X} use fast regex expansion. Variables like {{ env.X }} use full Tera templating and have access to the request context object (for HMAC signing).

Path Patterns & Dynamic Parameters

Routes support path templates with curly brackets {param_name}, e.g. /api/v1/pools/{pool_id}/volumes/{vol_id}:

  • Captured path variables are extracted automatically into request.params.<key>.
  • request.params can be referenced in target URLs, inject_headers, request_filter, and response_filter.

Inbound Request Transformation (request_filter)

The request_filter intercepts incoming client bodies before dispatching upstream:

  • "tera!": Renders a new payload string. Receives body (parsed JSON if valid, else raw string), request.params, request.method, graph context, and secrets.
  • "jmespath!" / "jp!": Executes a JMESPath transformation against the inbound JSON body.

Response Status & Header Mapping (response_mapping)

Normalizes backend status codes and headers to enforce a consistent client contract:

  • status_from_body: Evaluates conditional expressions (when) using Tera against the final response JSON. If condition renders true, overrides the HTTP response status with return_status.
  • override_headers: Injects or replaces headers returned to the client.

Context Variables

The following context is available during Tera templating (for target, headers, filters, and responses):

  • request.method: HTTP method (e.g., GET, POST).
  • request.path: The URI path of the request.
  • request.params: Key-value map of path parameters captured from {param} route placeholders.
  • request.host: The Host header or X-Forwarded-Host.
  • request.scheme: The HTTP scheme (http or https).
  • request.base_url: Combination of scheme and host.
  • request.query: Object containing all query string parameters.
  • request.query_values: Concatenated values of sorted query arguments (useful for signing).
  • request.headers: Object containing incoming request headers.
  • request.body: The raw text of the incoming HTTP body.
  • request.timestamp: Epoch time in seconds.
  • origin_resource: Properties of the currently matched graph node (if origin_resource is defined).

Dynamic Request Signatures:

For APIs that require every request to be cryptographically signed (such as Exoscale’s v2 API)

# app/proxy.toml
[[route]]
path = "/api/exoscale"
target = "https://api-ch-dk-2.exoscale.com/v2"
forward_headers = ["Accept", "User-Agent"]
[route.inject_headers]
"Content-Type" = "application/json"
"Authorization" = """
{%- set expires = request.timestamp + 600 -%}
{%- set msg = request.method ~ " " ~ request.path ~ "\n" ~ request.body ~ "\n" ~ request.query_values ~ "\n\n" ~ expires -%}
{%- set sig = msg | hmac_sha256(key=env.EXOSCALE_API_SECRET, encoding="base64") -%}
EXO2-HMAC-SHA256 credential={{ env.EXOSCALE_API_KEY }}{% if request.signed_query_args %},signed-query-args={{ request.signed_query_args }}{% endif %},expires={{ expires }},signature={{ sig -}}
"""

Action Routing

Proxy requests directly to dynamically exposed Runner services using action://<module_id>/<action_name>/<path>.

[[route]]
path = "/acme/*"
target = "action://cert-manager/start_acme_gateway/acme"

The controller will automatically locate the running service, resolve its dynamically allocated port, and tunnel the traffic.