The most surprising thing about transforming requests with Match and Replace is that it’s not about finding and changing strings; it’s about conditionally rerouting and modifying entire requests based on their intent.
Let’s say you have a service that handles user profiles, but you’ve just launched a new, more performant version of the API. You want to transparently migrate traffic without users noticing. Here’s how you could use Match and Replace to achieve that.
Imagine your old API endpoint is /v1/users/{userId} and the new one is /v2/users/{userId}.
Here’s a configuration snippet that demonstrates this in action:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: HTTPFilter
metadata:
name: user-profile-redirect
spec:
type: envoy.filters.http.router
config:
route_table:
routes:
- match:
# This is the critical part: matching the incoming request path.
prefix: /v1/users/
route:
# This tells Envoy where to send the request *after* transformation.
cluster: user-profile-v2
# This is where the magic happens: modifying the request.
request_headers_to_add:
- header:
key: x-original-path
value: "%REQ(X-ENVOY-ORIGINAL-PATH)%" # Captures the original path before rewrite
# The actual path rewrite.
prefix_rewrite: /v2/users/
In this configuration:
match: We’re looking for any request that starts with/v1/users/.route.cluster: If the match is successful, Envoy will attempt to route this request to theuser-profile-v2cluster. This cluster would be configured to point to your new API instances.request_headers_to_add: This is a bit of a side-effect, but useful for debugging. We’re adding a headerx-original-paththat captures the original request path before any rewrite. This can be invaluable for tracing.route.prefix_rewrite: This is the core transformation. Envoy will take the incoming request path (e.g.,/v1/users/123) and replace the/v1/users/prefix with/v2/users/, effectively turning it into/v2/users/123before sending it to theuser-profile-v2cluster.
The beauty here is that the client making the request never knows the path changed. They still send /v1/users/123, and the gateway seamlessly handles the transition to the new /v2/users/123 endpoint. This is how you can perform zero-downtime migrations or even implement A/B testing strategies by routing a percentage of traffic to a new endpoint while the rest goes to the old one, all managed at the gateway level.
The prefix_rewrite directive operates on the path after any host or scheme matching has occurred but before the request is sent to the upstream cluster. This means you can match on broad patterns and then surgically alter specific parts of the request path to align with new service versions or internal routing conventions. It’s not just about simple string substitution; it’s a powerful tool for orchestrating traffic flow and ensuring compatibility between evolving services.
You can also use this for more complex scenarios, like stripping away versioning information from external requests before they hit internal services that don’t use it, or adding common headers required by all backend services.
The next concept you’ll want to explore is how to conditionally apply these transformations based on request headers or query parameters, not just the path.