Transform Route Parameters for URL Rewrite
This guide explains how to transform incoming route parameter values in an inbound policy before the URL Rewrite handler uses them to build the upstream URL. This pattern is useful when your public API paths use different naming conventions than your internal backend.
Overview
When you use the URL Rewrite handler, it builds the upstream URL by
interpolating values like ${params.resourceType} directly from the incoming
route parameters. Sometimes, however, you need to change those values before
the rewrite happens. Common scenarios include:
- Value mapping — translating a public-facing parameter like
orderto an internal value likecustomerorder - Case normalization — converting
Productstoproductsbefore forwarding - Path translation — mapping user-friendly slugs to internal identifiers
The recommended approach is to read the route parameters in an inbound policy,
transform them, store the results on
context.custom, and reference the
transformed values in the URL Rewrite pattern.
Step-by-Step Example
The solution has three parts: an inbound policy that reads request.params
and stores transformed values on context.custom, a URL Rewrite handler
that references those values using ${context.custom.*} in the
rewritePattern, and route configuration that wires the two together.
Imagine your public API exposes a route like /api/:resourceType/:resourceId,
but your backend expects the resource type to be prefixed with customer. A
request to /api/order/123 should be forwarded to
https://backend.example.com/api/customerorder/123.
1. Write the Inbound Policy
Create a custom inbound policy that reads the route parameters, transforms the
values, and stores them on context.custom:
modules/transform-params.ts
2. Register the Policy
Add the policy to config/policies.json:
config/policies.json
3. Configure the Route
Define the route in config/routes.oas.json with the inbound policy and a URL
Rewrite handler that references context.custom:
config/routes.oas.json
With this configuration, a request to /api/order/123 flows through the
pipeline as follows:
- The route matches with
params.resourceType = "order"andparams.resourceId = "123" - The
transform-paramsinbound policy runs and setscontext.custom.transformedResourceType = "customerorder" - The URL Rewrite handler builds the upstream URL:
https://backend.example.com/api/customerorder/123
Common Pitfall: Modifying request.params Directly
Do not try to transform route parameters by constructing a new ZuploRequest
with modified params and expecting the URL Rewrite handler to pick them up.
A common first attempt is to create a new
ZuploRequest with different params:
Code
In practice, the URL Rewrite handler evaluates ${params.*} against the
route-level parameters rather than the request object returned by a policy. This
means the rewritten URL may contain undefined segments instead of your
transformed values. Use context.custom for reliable interpolation of
transformed values — the URL Rewrite handler's rewritePattern fully supports
${context.custom.*}, and values set in an inbound policy are available when
the handler runs.
Variations
Using a Lookup Map
For more complex mappings where the transformation is not a simple string operation, use a lookup object:
modules/transform-params-map.ts
Transforming Multiple Parameters
You can transform any number of route parameters and store each on
context.custom. Reference them individually in the rewrite pattern:
modules/transform-multiple-params.ts
Then use both values in the rewrite pattern:
Code
Combining with Body Transformation
If your API also needs to transform values in the request body alongside route
parameters, you can handle both in the same inbound policy. Create a new
ZuploRequest with a modified body while storing the route parameter
transformations on context.custom:
modules/transform-params-and-body.ts
Best Practices
- Use descriptive keys on
context.custom— names likecontext.custom.transformedResourceTypeare easier to debug than generic keys likecontext.custom.value - Log transformations — use
context.logto record original and transformed values so you can trace issues in production - Validate before transforming — return an appropriate error response (using
HttpProblems) if a parameter value is unexpected, rather than forwarding bad data to your backend - Keep the policy focused — if your transformation logic is complex, consider splitting it into a separate utility module imported by the policy
Next Steps
- URL Rewrite Handler — full reference for rewrite patterns and available interpolation variables
- Custom Code Patterns — common patterns for writing inbound policies, outbound policies, and handlers
- ZuploContext — reference for
context.customand other context properties - ZuploRequest — reference for
request.paramsand constructing new requests - User-Based Backend Routing — a related
pattern using
context.customwith URL Rewrite for routing by user identity