Validate and set request body defaults
Verified Code examples on this page have been automatically tested and verified.Use the default() and fail() CEL functions with json(), merge(), and toJson() to control what happens when a field is absent from the request. default(expression, fallbackValue) returns the expression if it resolves, and the fallback if it does not. The fallback can be a value to substitute a default, or fail(), which skips the transformation entirely when the field is absent.
Before you begin
- Set up an agentgateway proxy.
- Install the httpbin sample app.
Apply default values to optional fields
The gateway inspects the JSON request body and fills in missing fields with default values before forwarding to the upstream. This configuration lets the upstream rely on certain fields always being present without requiring the client to send them.
In this example, model and max_tokens are optional. If a client omits them, the gateway adds the defaults before the request reaches the upstream.
Create an AgentgatewayPolicy resource with your transformation rules.
kubectl apply -f- <<EOF apiVersion: agentgateway.dev/v1alpha1 kind: AgentgatewayPolicy metadata: name: transformation namespace: httpbin spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: httpbin traffic: transformation: request: body: 'toJson(json(request.body).merge({"model": default(json(request.body).model, "gpt-4o"), "max_tokens": default(json(request.body).max_tokens, 2048)}))' EOFThe expression breaks down as follows:
json(request.body): Parses the raw request body string into a map.default(json(request.body).model, "gpt-4o"): Ifmodelis absent, adds the default value"gpt-4o".default(json(request.body).max_tokens, 2048): Ifmax_tokensis absent, adds the default value2048..merge({...}): Applies the resolved values to the body, overwriting any existing keys.toJson(...): Serializes the resulting map back to a JSON string for the request body.
Send a request that omits the optional fields. Verify that defaults are applied in the forwarded body.
curl -vi http://$INGRESS_GW_ADDRESS:80/post \ -H "host: www.example.com:80" \ -H "content-type: application/json" \ -d '{"messages": [{"role": "user", "content": "hello"}]}'curl -vi localhost:8080/post \ -H "host: www.example.com" \ -H "content-type: application/json" \ -d '{"messages": [{"role": "user", "content": "hello"}]}'Example output:
< HTTP/1.1 200 OK HTTP/1.1 200 OK < content-type: application/json content-type: application/json ... { "data": "{\"max_tokens\":2048,\"messages\":[{\"content\":\"hello\",\"role\":\"user\"}],\"model\":\"gpt-4o\"}", ... }The
modelandmax_tokensdefaults are applied because they were not included in the original request.
Skip a transformation when a field is absent
Using fail() as the fallback in default(expression, fail()) skips the transformation entirely when the field cannot be resolved. This configuration is useful when you want to forward a value only if it actually exists in the request, rather than forwarding a placeholder or empty string.
In this example, the x-user-id request header is set from the user_id field in the request body. If user_id is present, the header is injected. If it is absent, the transformation is skipped and the header is not set.
Update the AgentgatewayPolicy resource with your transformation rules.
kubectl apply -f- <<EOF apiVersion: agentgateway.dev/v1alpha1 kind: AgentgatewayPolicy metadata: name: transformation namespace: httpbin spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: httpbin traffic: transformation: request: set: - name: x-user-id value: 'default(json(request.body).user_id, fail())' EOFSend a request that includes
user_idin the body. Verify that thex-user-idheader is present in the forwarded request.curl -vi http://$INGRESS_GW_ADDRESS:80/post \ -H "host: www.example.com:80" \ -H "content-type: application/json" \ -d '{"user_id": "user123", "messages": [{"role": "user", "content": "hello"}]}'curl -vi localhost:8080/post \ -H "host: www.example.com" \ -H "content-type: application/json" \ -d '{"user_id": "user123", "messages": [{"role": "user", "content": "hello"}]}'Example output:
< HTTP/1.1 200 OK HTTP/1.1 200 OK ... { "headers": { "Content-Type": ["application/json"], "Host": ["www.example.com"], "User-Agent": ["curl/8.7.1"], "X-User-Id": ["user123"] }, ... }Send a request that omits
user_id. Verify that thex-user-idheader is absent.curl -vi http://$INGRESS_GW_ADDRESS:80/post \ -H "host: www.example.com:80" \ -H "content-type: application/json" \ -d '{"messages": [{"role": "user", "content": "hello"}]}'curl -vi localhost:8080/post \ -H "host: www.example.com" \ -H "content-type: application/json" \ -d '{"messages": [{"role": "user", "content": "hello"}]}'Example output:
< HTTP/1.1 200 OK HTTP/1.1 200 OK ... { "headers": { "Content-Type": ["application/json"], "Host": ["www.example.com"], "User-Agent": ["curl/8.7.1"] }, ... }The
X-User-Idheader is absent becauseuser_idwas not present in the request body andfail()caused the transformation to be skipped.
Cleanup
You can remove the resources that you created in this guide.kubectl delete AgentgatewayPolicy transformation -n httpbin