API Gateway Request Transformation — Headers, Bodies, URLs, and Protocol Translation
Why transform requests at the gateway?#
Your API gateway sits between clients and backend services. Clients send requests in one format. Backend services expect another. Instead of polluting every service with transformation logic, handle it once at the gateway.
Common scenarios:
- Legacy migration: Clients call the old API format, the gateway rewrites requests to the new service
- Multi-client support: Mobile and web clients send different payloads, the gateway normalizes them
- Security: Strip sensitive headers before forwarding, inject authentication tokens for internal services
- Protocol bridging: Clients send REST, backend services speak gRPC or SOAP
- Versioning: Route /v1 and /v2 requests to different backends while transforming payloads between versions
Header injection and manipulation#
Adding headers#
Inject headers that backend services need but clients should not send:
- X-Request-ID for distributed tracing (generate a UUID at the gateway)
- X-Forwarded-For and X-Real-IP to preserve client identity
- Authorization tokens for internal service-to-service calls
- X-Tenant-ID extracted from the JWT payload for multi-tenant routing
Removing headers#
Strip headers before forwarding to backends:
- Cookie headers when backends are stateless
- Authorization after the gateway validates the token (pass a simpler internal token instead)
- X-Powered-By and other fingerprinting headers from responses
Conditional headers#
Add headers based on request properties:
- If the client sends
Accept: application/xml, addX-Response-Format: xmlfor a backend that uses a custom header - If the request path starts with
/admin, injectX-Role: adminafter validating the JWT claims
Kong implementation#
plugins:
- name: request-transformer
config:
add:
headers:
- "X-Request-ID:$(uuid)"
- "X-Gateway-Version:2.0"
remove:
headers:
- "X-Internal-Debug"
replace:
headers:
- "Host:backend-service.internal"
AWS API Gateway (HTTP API)#
In AWS API Gateway, use parameter mapping in the integration:
{
"requestParameters": {
"overwrite:header.X-Request-ID": "$context.requestId",
"append:header.X-Forwarded-For": "$context.identity.sourceIp",
"remove:header.X-Debug": ""
}
}
Traefik middleware#
http:
middlewares:
add-headers:
headers:
customRequestHeaders:
X-Request-ID: "" # Traefik auto-generates
X-Gateway: "traefik"
customResponseHeaders:
X-Powered-By: "" # empty string removes the header
Body transformation#
Body transformation is more complex than header manipulation. The gateway must parse the body, modify it, and re-serialize it.
Request body modification#
Typical transformations:
- Add fields: Inject a
timestamporrequestIdinto every request body - Remove fields: Strip fields that backends should not receive (e.g., client-side metadata)
- Rename fields: Map
userNamefrom the client touser_namefor the backend - Restructure: Flatten nested objects or wrap flat payloads into the structure the backend expects
Kong body transformation#
plugins:
- name: request-transformer-advanced
config:
add:
body:
- "source:gateway"
- "processed_at:$(now)"
remove:
body:
- "client_metadata"
rename:
body:
- "userName:user_name"
- "emailAddress:email"
AWS API Gateway (REST API) with VTL#
AWS REST API uses Velocity Template Language (VTL) for body mapping:
#set($body = $util.parseJson($input.body))
{
"user_name": "$body.userName",
"email": "$body.emailAddress",
"source": "api-gateway",
"request_id": "$context.requestId",
"timestamp": "$context.requestTimeEpoch"
}
VTL is powerful but awkward. For complex transformations, consider using a Lambda authorizer or integration to preprocess the body.
Response body transformation#
Transform responses before they reach the client:
- Wrap all responses in a standard envelope:
{"data": ..., "meta": {"requestId": "..."}} - Remove internal fields (database IDs, internal status codes)
- Convert between formats (JSON to XML for legacy clients)
URL rewriting#
URL rewriting changes the path or query parameters before forwarding to the backend.
Path rewriting#
| Client sends | Backend receives | Pattern |
|---|---|---|
/api/v2/users/123 | /users/123 | Strip version prefix |
/products/shoes | /catalog/items?category=shoes | Path to query param |
/legacy/getUser?id=123 | /users/123 | Query param to path segment |
/store-a/products | /products with header X-Store: a | Path segment to header |
Kong route rewriting#
routes:
- name: strip-version
paths:
- /api/v2
strip_path: true
# /api/v2/users/123 becomes /users/123
For complex rewrites, use the post-function plugin with Lua:
-- Transform /legacy/getUser?id=123 to /users/123
local id = kong.request.get_query_arg("id")
if id then
kong.service.request.set_path("/users/" .. id)
kong.service.request.clear_query_arg("id")
end
Traefik path rewriting#
http:
middlewares:
strip-api-prefix:
stripPrefix:
prefixes:
- "/api/v2"
replace-path:
replacePathRegex:
regex: "^/legacy/getUser\\?id=(.*)"
replacement: "/users/$1"
AWS API Gateway path parameters#
{
"requestParameters": {
"overwrite:path": "/internal$context.path"
}
}
Request and response mapping#
Beyond simple field changes, sometimes you need to completely reshape payloads.
Aggregation pattern#
The gateway calls multiple backends and merges responses into one:
- Client sends
GET /user-profile/123 - Gateway calls
GET /users/123(user service) andGET /orders?user=123(order service) in parallel - Gateway merges both responses into a single payload
This is not pure transformation — it is composition. Kong, Traefik, and AWS API Gateway do not natively support this well. Consider:
- Kong: Use the
post-functionplugin or a custom plugin - AWS: Use a Lambda integration to orchestrate multiple calls
- Dedicated BFF: A Backend-for-Frontend service handles composition logic
Schema validation#
Before forwarding transformed requests, validate them against the expected schema:
# Kong request-validator plugin
plugins:
- name: request-validator
config:
body_schema: |
{
"type": "object",
"required": ["user_name", "email"],
"properties": {
"user_name": {"type": "string"},
"email": {"type": "string", "format": "email"}
}
}
AWS API Gateway supports request validation with JSON Schema models natively.
Protocol translation#
The most powerful gateway transformation: bridging between protocols.
REST to gRPC#
Clients send JSON over HTTP. The backend speaks gRPC (Protocol Buffers over HTTP/2).
Kong: Use the grpc-gateway plugin. Define a proto file, and Kong translates JSON requests into gRPC calls and serializes gRPC responses back to JSON.
Envoy (used by Istio, Consul Connect): The gRPC-JSON transcoder filter does the same thing. Define your proto file, and Envoy handles the translation.
AWS API Gateway: Use a VPC Link to an internal ALB that routes to gRPC services. The translation happens at the ALB or via a Lambda adapter.
REST to SOAP#
Legacy integrations sometimes require calling SOAP services. The gateway can:
- Accept a JSON REST request
- Build a SOAP XML envelope from the JSON fields
- Forward the SOAP request to the backend
- Parse the SOAP XML response
- Return JSON to the client
This is complex. For Kong, you would write a custom Lua plugin. For AWS, a Lambda integration handles the XML construction. For Traefik, use a middleware plugin or an external service.
GraphQL to REST#
API gateways can sit in front of REST services and expose a GraphQL interface:
- Apollo Router and GraphQL Mesh handle this natively
- Kong has a GraphQL plugin for rate limiting and caching but does not translate protocols
- AWS AppSync provides GraphQL-to-REST resolvers with VTL mapping templates
Transformation pipeline ordering#
Order matters. A typical transformation pipeline:
- Authenticate — validate JWT, API key, or mTLS
- Rate limit — reject excess traffic before doing expensive transformations
- Validate request — check the body against a schema
- Transform request — rewrite headers, body, URL
- Route — forward to the correct backend
- Transform response — reshape the backend response for the client
- Cache — store the transformed response for future requests
- Log — record the original request and final response
Getting the order wrong causes subtle bugs. For example, rate limiting after transformation wastes compute on requests that will be rejected.
Debugging transformations#
Transformations are invisible by default. When something breaks, you cannot see what the gateway sent to the backend.
Logging the transformed request#
- Kong: Enable the
file-logorhttp-logplugin to capture the request after transformation - Traefik: Set
accessLogwith headers and body capture enabled - AWS API Gateway: Enable CloudWatch execution logging with
Log full requests/responses data
Echo service#
Deploy a simple echo service in your staging environment that returns the exact request it received (headers, body, URL). Route traffic through the gateway to the echo service to verify transformations.
Incremental development#
Build transformations one step at a time. Add header injection first, verify it works, then add body transformation, verify again. Complex transformation chains with multiple plugins are hard to debug when built all at once.
Visualize your API gateway architecture#
Map out your gateway, transformations, and backend routing with interactive diagrams — try Codelit to generate architecture diagrams from a text prompt.
Key takeaways#
- Transform at the gateway, not in every service — centralize cross-cutting concerns
- Header manipulation is the simplest transformation — start here for tracing, auth, and security
- Body transformation requires parsing — use built-in plugins (Kong, AWS VTL) or Lambda/Lua for complex cases
- URL rewriting handles versioning and legacy migration — strip prefixes, remap paths, convert query params
- Protocol translation bridges REST to gRPC, SOAP, or GraphQL — powerful but complex, evaluate dedicated tools
- Order your transformation pipeline carefully — authenticate and rate-limit before transforming
Article #424 in the Codelit engineering series. Explore our full library of system design, infrastructure, and architecture guides at codelit.io.
Try it on Codelit
Chaos Mode
Simulate node failures and watch cascading impact across your architecture
Cost Estimator
See estimated AWS monthly costs for every component in your architecture
Related articles
Try these templates
OpenAI API Request Pipeline
7-stage pipeline from API call to token generation, handling millions of requests per minute.
8 componentsAPI Gateway Platform
Kong/AWS API Gateway-like platform with routing, auth, rate limiting, transformation, and developer portal.
8 componentsGraphQL API Gateway
Federated GraphQL gateway aggregating multiple microservice schemas with caching, auth, and rate limiting.
10 componentsBuild this architecture
Generate an interactive architecture for API Gateway Request Transformation in seconds.
Try it in Codelit →
Comments