Request Transformation in API Gateway — Modify Headers, Paths, and Bodies
In this tutorial, you will learn about Request Transformation in API Gateway. We cover key concepts, practical examples, and best practices to help you master this topic.
Request transformation allows an API gateway to modify incoming requests headers, paths, query parameters, and bodies before forwarding them to backend services, decoupling external API contracts from internal implementations.
What You'll Learn
- Common request transformations: path rewrite, header injection, body transformation
- How to decouple external API versions from internal service versions
- Security transformations like stripping sensitive headers
Why It Matters
Backend services evolve independently of the public API. An external client might call /api/v2/users, but the backend is /users on a different port. Request transformation lets the gateway bridge these differences without requiring client or backend changes.
Real-World Use
Durga Antivirus Pro's public API uses /v1/threats/report, but the threat analysis service expects /report with a service-specific authentication header. The gateway rewrites the path, strips the public API key, and injects internal auth headers before forwarding.
flowchart LR
Client["Client\n/v1/users/42"] --> GW["Gateway\nTransform"]
GW -->|"Rewrite to /users/42"| Backend["Backend\nService"]
style GW fill:#dbeafe,stroke:#2563eb
Path Rewriting
Path rewriting changes the URL path before forwarding. The client sees a different path than the backend receives.
from flask import Flask, request
import requests
import re
app = Flask(__name__)
PATH_RULES = [
(r"^/api/v1/users/(.*)$", "http://user-srv:8080/users/{}"),
(r"^/api/v1/orders/(.*)$", "http://order-srv:8080/api/orders/{}"),
]
@app.route("/api/v1/<path:rest>")
def transform_and_proxy(rest):
full_path = f"/api/v1/{rest}"
for pattern, backend_template in PATH_RULES:
match = re.match(pattern, full_path)
if match:
backend_url = backend_template.format(*match.groups())
resp = requests.request(
method=request.method,
url=backend_url,
data=request.get_data(),
headers=request.headers
)
return (resp.content, resp.status_code, resp.headers.items())
return {"error": "Route not found"}, 404
Header Injection and Stripping
The gateway adds headers for internal use and removes headers that should not reach the backend:
def prepare_forwarding_headers(original_headers):
internal_headers = ["X-Internal-Token", "X-Debug", "X-Forwarded-For"]
headers = {}
for key, value in original_headers:
if key not in internal_headers:
headers[key] = value
headers["X-User-ID"] = getattr(request, "user_id", "anonymous")
headers["X-Gateway-Version"] = "2.1.0"
return headers
Body Transformation
Sometimes the request body format must change. The gateway can parse, transform, and re-serialize:
import json
def transform_request_body(original_body):
data = json.loads(original_body)
transformed = {
"user": {
"id": data.get("user_id"),
"name": data.get("full_name"),
"email": data.get("email_address"),
},
"metadata": {
"source": "gateway",
"timestamp": data.get("created_at"),
},
}
return json.dumps(transformed)
@app.route("/api/signup", methods=["POST"])
def signup():
new_body = transform_request_body(request.get_data().decode())
resp = requests.post(
"http://user-service:8080/register",
data=new_body,
headers={"Content-Type": "application/json"}
)
return resp.content, resp.status_code
Common Mistakes
1. Modifying the Request Body for All Routes
Body transformation should be route-specific. A generic catch-all body transform may break routes that expect the original format.
2. Not Updating Content-Length Headers
After modifying the request body, update the Content-Length header. An incorrect length causes connection timeouts or truncated requests.
3. Forwarding Internal Headers from Clients
The gateway must strip any X-Internal-* headers from incoming requests. A malicious client could inject them to impersonate internal services.
4. Breaking Query Parameters
When rewriting paths, ensure query parameters are preserved. Append ?original_qs to the rewritten URL.
5. Synchronous Transformations Under Load
CPU-intensive transformations (XML-to-JSON conversion) should be async or queue-based to avoid blocking the gateway event loop.
Practice Questions
- Why is path rewriting useful for API Versioning?
- What headers should the gateway strip from incoming requests?
- Why must
Content-Lengthbe recalculated after body transformation? - How can body transformation help migrate from legacy API formats?
- What is the risk of CPU-intensive transformations in the gateway?
Answers:
- The public API can expose stable URLs (
/v1/users) while internally routing to different service versions without client changes. - All
X-Internal-*headers, authentication tokens after validation, andX-Forwarded-*headers that could spoof identity. - The gateway adds or removes bytes during transformation, so the original length is incorrect. A mismatch causes connection errors.
- The gateway can transform XML to JSON or snake_case to camelCase, allowing legacy backends to serve modern clients without changes.
- CPU-intensive transformations block the gateway event loop, increasing latency for all requests. Offload to background workers or async processing.
Challenge: Design a transformation pipeline that accepts camelCase JSON from clients, transforms to snake_case for backends, and transforms responses back to camelCase.
FAQ
Mini Project
Build a gateway that transforms incoming requests: rewrite /api/v2/products/{id} to /internal/products/{id}, strip Authorization header after validation, add X-Forwarded-Proto, and convert request body from camelCase to snake_case.
What's Next
Continue with Response Aggregation in Gateway to combine multiple backend responses, or explore Circuit Breaker Pattern for fault tolerance.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro