Free Ebook cover API Gateways for Beginners: Managing, Securing, and Scaling Web APIs

API Gateways for Beginners: Managing, Securing, and Scaling Web APIs

New course

12 pages

Request and Response Transformation: Headers, Payloads, and Protocols

Capítulo 6

Estimated reading time: 10 minutes

+ Exercise

What “Transformation” Means at the Gateway

Request and response transformation is the set of gateway policies that modify what a client sends and what an upstream service receives (and vice versa) without requiring changes to the upstream code. This is useful when you need to expose a stable public API contract while upstream services evolve, or when different clients require different shapes of data.

Transformations typically happen in three places: (1) request metadata (headers, query string, path), (2) request/response bodies (payload mapping and content-type conversion), and (3) response shaping (filtering fields, adding metadata, normalizing errors). Because transformations can add CPU work and complexity, apply them deliberately and keep them observable (logs/metrics) so you can detect drift and performance impact.

Header Manipulation (Add, Remove, Rename)

Headers are the easiest and most common transformation surface. They carry identity, correlation, content negotiation, caching hints, and client context. A gateway can add, remove, or rename headers to match an upstream contract or enforce consistent behavior.

Add headers

  • Correlation IDs: If a client does not send a request ID, the gateway can generate one and forward it upstream (and echo it back in the response) to enable tracing.
  • Client context: Add X-Client-App, X-Client-Version, or a derived header like X-Geo-Country (from IP intelligence) if your upstream expects it.
  • Forwarded headers: Normalize Forwarded / X-Forwarded-For / X-Forwarded-Proto so upstream services can build correct absolute URLs.

Remove headers

  • Security: Strip headers that should never reach upstreams (for example, internal-only headers like X-Internal-User).
  • Prevent spoofing: Remove client-supplied X-Forwarded-For and replace it with the gateway’s computed value to avoid IP spoofing.
  • Reduce ambiguity: Remove duplicate or conflicting headers (for example, multiple Content-Type values).

Rename headers

Renaming is useful when you are migrating contracts. Example: clients send X-Request-Id but upstream expects X-Correlation-Id. The gateway can map one to the other.

# Conceptual mapping (policy-style pseudocode) add/rename/remove headers: if missing X-Request-Id: set X-Request-Id = generated_uuid() set X-Correlation-Id = header("X-Request-Id") remove header("X-Deprecated-Header")

Cautions for header transformations

  • Hop-by-hop headers: Be careful with headers like Connection, Keep-Alive, Transfer-Encoding, and Upgrade. Many gateways manage these at the proxy layer; rewriting them incorrectly can break connections.
  • Caching behavior: Changing Vary, Cache-Control, or ETag can change cache correctness. If you shape responses, ensure caching headers still match the actual payload.
  • Case and duplicates: HTTP header names are case-insensitive, but some libraries behave oddly with duplicates. Prefer a single canonical header name and a single value when possible.

Query String Mapping and Path Rewrites

When clients call a public API, they often use friendly query parameters and paths. Upstream services may use different names, formats, or resource layouts. Gateways can translate between these contracts.

Continue in our app.

You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.

Or continue reading below...
Download App

Download the app

Query string mapping

Common patterns include renaming parameters, changing formats, and applying defaults.

  • Rename: ?pageSize=50 to ?limit=50
  • Format conversion: ?from=2026-01-01 to ?start_date=1704067200 (epoch seconds)
  • Defaults: If sort is missing, set sort=created_at:desc
  • Allow-listing: Drop unknown query parameters to reduce accidental coupling and prevent upstream surprises.
# Example mapping (conceptual) incoming: GET /v1/orders?pageSize=50&from=2026-01-01 outgoing to upstream: GET /orders?limit=50&start_date=1704067200

Path rewrites

Path rewrites let you expose stable, versioned, or more user-friendly URLs while routing to different upstream resource layouts.

  • Version facade: Public /v1/customers/{id} to upstream /customers/{id}
  • Resource rename: Public /users to upstream /accounts
  • Composite paths: Public /stores/{storeId}/orders to upstream /orders?store_id={storeId}
# Example rewrite (conceptual) incoming: GET /v1/stores/42/orders outgoing: GET /orders?store_id=42

Cautions for query/path transformations

  • Coupling risk: The more your gateway “knows” about upstream parameter semantics, the more changes upstream can force on gateway policies. Keep mappings small and well-documented.
  • Observability: Log both the external request and the transformed upstream request (carefully redacting sensitive values) to debug mismatches.
  • Edge cases: Watch for URL encoding, repeated parameters (e.g., tag=a&tag=b), and trailing slashes.

Body Transformations (JSON Field Mapping)

Body transformations modify the payload itself. The most common case is JSON field mapping: renaming fields, changing nesting, converting types, and applying defaults. This is powerful but can be expensive and can create tight coupling between the gateway and both schemas.

Typical JSON mapping operations

  • Rename fields: customerId to customer_id
  • Move fields: addressLine1 into address.line1
  • Type conversion: "true" (string) to true (boolean), or numeric strings to numbers
  • Defaults: If currency missing, set currency="USD"
  • Drop fields: Remove client-only fields not accepted upstream
# External request body (client contract) { "customerId": "123", "addressLine1": "10 Main St", "newsletter": "true" } # Upstream request body (upstream contract) { "customer_id": 123, "address": { "line1": "10 Main St" }, "newsletter": true }

Validation vs transformation

Validation checks whether the input matches expectations; transformation changes it to match an upstream contract. In practice, you usually do both: validate the external contract first (to give the client a clear error), then transform to the upstream contract.

  • Validate early: Reject missing required fields, wrong types, and invalid formats before you spend time transforming.
  • Transform deterministically: Avoid “best effort” conversions that hide client mistakes (for example, silently turning invalid dates into null).

Cautions for body transformations

  • Latency and CPU: Parsing and rewriting JSON adds overhead. Large payloads amplify this cost.
  • Streaming limitations: Some transformations require buffering the entire body, which can increase memory use and reduce throughput.
  • Schema drift: If upstream adds/removes fields, your mapping can break. Treat mappings as code: version them, test them, and deploy them with change control.

Content-Type Conversion Basics

Sometimes clients and upstreams speak different formats. A gateway can perform basic content-type conversion, most commonly between JSON and form-encoded payloads, or between JSON and XML in legacy environments.

Common conversions

  • JSON to application/x-www-form-urlencoded: Useful when upstream expects classic form posts.
  • XML to JSON: Useful when exposing a modern API facade over a legacy XML service.
  • Content negotiation: Use Accept and Content-Type to decide what to produce/consume, but keep the supported set small.
# Example: JSON to form-encoded (conceptual) incoming Content-Type: application/json body: { "grant_type": "client_credentials", "scope": "read" } outgoing Content-Type: application/x-www-form-urlencoded body: grant_type=client_credentials&scope=read

Cautions for content-type conversion

  • Lossy mappings: XML attributes, mixed content, and repeated elements can map ambiguously to JSON. Define explicit rules and test with real payloads.
  • Character encoding: Ensure consistent UTF-8 handling and correct charset parameters when relevant.
  • Validation first: Validate the incoming payload before converting; otherwise you may generate confusing upstream errors.

Response Shaping (Filtering Fields, Adding Metadata)

Response shaping modifies what clients receive without changing what upstream returns. This is useful for hiding internal fields, reducing payload size for mobile clients, or adding gateway-generated metadata.

Filtering and projection

  • Remove sensitive fields: Strip internal IDs, debug fields, or fields that should not be public.
  • Reduce payload size: Return only a subset of fields needed by a given endpoint.
  • Consistent naming: Convert upstream snake_case to external camelCase (or the reverse) if your public contract requires it.
# Upstream response { "id": 10, "email": "a@example.com", "internal_notes": "VIP", "created_at": "2026-01-16T10:00:00Z" } # External response after shaping { "id": 10, "email": "a@example.com", "createdAt": "2026-01-16T10:00:00Z" }

Adding metadata

Gateways can add response headers or body fields that help clients operate reliably.

  • Echo correlation ID: Return X-Request-Id so clients can reference it in support tickets.
  • Pagination metadata: Add nextPageToken or links if the upstream uses a different pagination style.
  • Deprecation signals: Add headers like Deprecation or Sunset when you need to communicate lifecycle changes (ensure they match your API governance).

Cautions for response shaping

  • Caching correctness: If you shape responses differently per client (e.g., based on headers), ensure Vary reflects that or disable shared caching.
  • Error transparency: If you rewrite error bodies, preserve enough detail for clients while avoiding leakage of internal stack traces or identifiers.
  • Latency: Shaping requires parsing and rewriting; measure the added time and consider limiting shaping to endpoints where it provides clear value.

CORS Handling and Preflight Requests

Cross-Origin Resource Sharing (CORS) is a browser security mechanism that controls whether a web page can call an API from a different origin. Gateways commonly centralize CORS so upstream services do not need to implement it consistently.

Key headers

  • Access-Control-Allow-Origin: Which origins are allowed (avoid using * when credentials are involved).
  • Access-Control-Allow-Methods: Allowed HTTP methods.
  • Access-Control-Allow-Headers: Allowed request headers (especially custom headers).
  • Access-Control-Allow-Credentials: Whether cookies/credentials are allowed (requires a specific origin, not *).
  • Access-Control-Expose-Headers: Which response headers the browser can read.
  • Access-Control-Max-Age: How long the browser can cache preflight results.

Preflight (OPTIONS) requests

For “non-simple” requests (e.g., custom headers or methods like PUT), browsers send an OPTIONS preflight request before the actual call. A gateway can respond to preflight directly without forwarding to upstream, reducing load and avoiding inconsistent upstream behavior.

# Preflight request (browser) OPTIONS /v1/orders Origin: https://app.example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: content-type,x-request-id # Preflight response (gateway) 204 No Content Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS Access-Control-Allow-Headers: content-type,x-request-id Access-Control-Max-Age: 600

CORS cautions

  • Origin reflection: If you dynamically echo Origin, validate it against an allow-list to avoid opening your API to any site.
  • Credentials: If Access-Control-Allow-Credentials: true, you must not use * for Access-Control-Allow-Origin.
  • Consistency: Ensure both preflight and actual responses include the required CORS headers; otherwise browsers will still block the call.

A Practical Transformation Sequence (External Contract → Upstream Contract → External Contract)

A reliable approach is to treat the gateway as a contract adapter with a clear pipeline. The goal is predictable behavior: clients get consistent validation errors, upstreams receive exactly what they expect, and clients receive a stable external response shape.

Step 1: Validate the external input shape

  • Validate headers: Require or forbid certain headers (e.g., require Content-Type: application/json for JSON endpoints; reject unexpected Content-Encoding if unsupported).
  • Validate query/path: Check required parameters, allowed values, and formats (e.g., pageSize range).
  • Validate body schema: Ensure required fields exist and types/formats are correct (e.g., customerId is numeric, email is valid).
# Example validation rules (conceptual) require header Content-Type == "application/json" require query param pageSize in [1..100] require body.customerId is integer require body.newsletter is boolean

Step 2: Transform the request to the upstream contract

  • Headers: Add correlation ID, rename headers, strip spoofable headers.
  • Query/path: Rewrite paths and map query parameters to upstream names and formats.
  • Body: Map JSON fields, convert types, apply defaults, remove unsupported fields.
  • Content-type: Convert payload format if the upstream requires a different Content-Type.
# External request (client) POST /v1/orders?pageSize=50 Header: X-Request-Id: abc-123 Body: { "customerId": "123", "items": [{"sku":"A1","qty":"2"}] } # Transformed upstream request POST /orders?limit=50 Header: X-Correlation-Id: abc-123 Body: { "customer_id": 123, "lines": [{"sku":"A1","quantity": 2}] }

Step 3: Transform the upstream response to the external contract

  • Status and headers: Optionally normalize headers (e.g., echo X-Request-Id), and ensure CORS headers are present for browser clients.
  • Body shaping: Rename fields, filter internal fields, and add external metadata (e.g., pagination links).
  • Error normalization: If you standardize error shapes, map upstream error formats into your public error contract while preserving an internal correlation ID for debugging.
# Upstream response { "order_id": 999, "customer_id": 123, "internal_state": "RISK_REVIEW" } # External response { "orderId": 999, "customerId": 123, "metadata": { "requestId": "abc-123" } }

Operational cautions for the full pipeline

  • Test transformations like code: Use contract tests with sample requests/responses to catch schema drift.
  • Measure added latency: Track gateway processing time separately from upstream time; transformations can become the bottleneck.
  • Minimize transformation scope: Prefer small, targeted mappings over large “do everything” policies that are hard to maintain.

Now answer the exercise about the content:

Why should an API gateway validate an external request before transforming it for an upstream service?

You are right! Congratulations, now go to the next page

You missed! Try again.

Validating first helps reject missing fields, wrong types, or invalid formats with a clear error before doing potentially expensive transformations. This avoids confusing upstream errors and unnecessary CPU/latency.

Next chapter

API Versioning and Lifecycle Management Through the Gateway

Arrow Right Icon
Download the app to earn free Certification and listen to the courses in the background, even with the screen off.