API Gateway Patterns: More Than Just a Reverse Proxy
API gateway patterns extend far beyond routing — authentication, rate limiting, aggregation, and the BFF pattern make gateways a critical architectural component. Here's how to use them effectively.

James Ross Jr.
Strategic Systems Architect & Enterprise Software Developer
More Than a Traffic Cop
The typical description of an API gateway — a single entry point that routes requests to backend services — undersells what it actually does and undersells the architectural decisions involved in using one well.
An API gateway is a cross-cutting infrastructure component that handles capabilities every API needs but no single service should own: authentication verification, rate limiting, request transformation, response aggregation, logging, and caching. When you centralize these concerns at the gateway layer, individual services become simpler. When you do it wrong, the gateway becomes a bottleneck, a configuration nightmare, or a hidden point of coupling between your services.
Here's how to use API gateways effectively.
The Core Responsibilities
Routing
The basic function: receive a request at /api/orders/123, forward it to the OrderService at http://order-service:8080/orders/123, and return the response. This is what people mean by "reverse proxy" — and it's the smallest part of what an API gateway should do.
What makes routing valuable in a gateway vs a plain reverse proxy: the gateway can route based on multiple criteria — path, query parameters, HTTP method, request headers, API version — and can perform transformations on the way in or out. It can rewrite paths (external /api/v2/orders routes to internal /orders), strip authentication headers before forwarding, or inject headers the downstream service expects.
Authentication and Authorization
Every API needs authentication. But authentication is not a service-level concern — it's a cross-cutting concern. If authentication logic lives in every microservice, you've created an N-way coordination problem: every service needs the same auth library, every service needs to be updated when auth changes, every service adds latency for auth verification.
The gateway pattern: validate tokens at the gateway. If the token is invalid, reject the request before it ever reaches a service. If it's valid, inject the identity information as a trusted header that downstream services can use without re-verifying.
This means downstream services can trust X-User-ID: 12345 because the gateway guarantees it only sets that header for authenticated requests. Services implement authorization (what this user can do) while the gateway handles authentication (who this user is).
The important caveat: services behind the gateway must be inaccessible from outside the network. If a client can reach order-service:8080 directly and bypass the gateway, you've built security theater.
Rate Limiting
Rate limiting protects your services from being overwhelmed, prevents abuse, and implements fair-use policies. At the gateway, you can implement rate limiting per API key, per user, per IP, or per endpoint — with limits configurable centrally rather than duplicated across services.
The implementation complexity is in the strategy: does a rate limit reset per minute, per hour, per day? Do all servers share the same rate limit state (requires a shared cache like Redis) or do they each have their own (simpler but allows burst behavior)? What do you return when the limit is hit — a 429 with Retry-After header, or do you queue the request?
Gateway products like Kong, AWS API Gateway, and Traefik have rate limiting built in. If you're building a custom gateway, distributed rate limiting with Redis is the standard pattern.
Request/Response Transformation
Gateways can modify requests and responses in flight. Common use cases:
- Converting from one API format to another (SOAP to REST, XML to JSON)
- Adding or removing headers
- Transforming response structures to match what clients expect
- Protocol translation (HTTP/1.1 to gRPC for backend services)
Use this carefully. Business logic does not belong in a gateway. Transformations at the gateway should be mechanical — format conversion, header manipulation — not semantic transformations that require understanding the domain.
The BFF Pattern (Backend for Frontend)
The Backend for Frontend pattern is one of the most valuable API gateway patterns and one of the most underused.
The problem: a single generic API must serve multiple client types with very different needs. A mobile client needs compact, battery-efficient responses with minimal data. A web dashboard needs rich, denormalized data for complex UI components. A third-party integration needs a stable, versioned API with predictable schemas. Trying to serve all three from a single API produces a bloated, compromised design that serves none of them well.
The BFF pattern creates a separate "backend" service (or gateway configuration) for each client type, each optimized for its consumer:
- Mobile BFF: Returns minimal payloads. Aggregates multiple service calls into single endpoints matching screen data requirements. Handles mobile-specific caching and offline concerns.
- Web BFF: Returns richer data for complex UI components. Handles pagination, filtering, and search patterns appropriate for web interfaces.
- Partner API: Provides a stable, versioned, well-documented API with conservative change management policies.
Each BFF owns the transformation and aggregation logic specific to its client, leaving the underlying services as clean domain-oriented APIs. Changes to the mobile client's data requirements modify the mobile BFF without affecting the web or partner APIs.
BFFs work best when they're owned by the same team as the client they serve. A mobile team owning the mobile BFF can evolve it as needed without coordinating with the team that owns the partner API.
Request Aggregation
Related to BFF but distinct: the gateway can aggregate multiple downstream requests into a single response.
A product detail page might need data from: the catalog service (product info), the inventory service (stock levels), the pricing service (current price and promotions), and the review service (ratings). Without aggregation, the client makes four requests serially or in parallel and assembles the data. With aggregation at the gateway (or BFF), the client makes one request and the backend handles the fan-out and assembly.
The trade-offs:
Benefits: Reduced client complexity, fewer network round trips for mobile clients, ability to parallelize backend calls server-side.
Costs: The gateway now needs domain knowledge to aggregate the responses. If the aggregation logic is complex, it belongs in a dedicated service (an API composition service or BFF), not in a generic gateway configuration.
The rule: simple aggregation (combine responses from three services into one object) is appropriate at the gateway. Complex aggregation (join data across services, apply business logic to the result) belongs in a dedicated service.
Caching
A gateway is a natural caching layer for responses that are expensive to compute and change infrequently. Product catalog data, public content, and configuration are good candidates. User-specific or frequently-updated data is not.
Gateway caching should respect Cache-Control headers from upstream services. Services declare their caching intentions; the gateway enforces them. Don't override a service's cache directives at the gateway — the service knows its data's freshness requirements better than the gateway does.
Cache invalidation at the gateway layer is particularly tricky. Design for this upfront rather than discovering the problem when you need to push an urgent update and your cache holds the old version.
The Configuration Problem
As API gateways grow, the configuration becomes a maintenance burden. Hundreds of route definitions, authentication rules, rate limit configurations, and transformation rules create a fragile configuration layer that's difficult to test and easy to break.
Strategies that help:
GitOps for gateway configuration. Store gateway configuration in source control and apply it through CI/CD. Changes are reviewed, versioned, and auditable.
Service-owned routing. In some gateway systems (Traefik, Kong with declarative config), services declare their own routing rules in configuration files deployed alongside the service. The gateway discovers and applies them. This distributes ownership of routing to the teams who own the services.
Testing gateway configuration. Integration tests that verify routing, authentication enforcement, and rate limiting behavior should run in CI, not just be verified manually after deployment.
Choosing a Gateway
The right gateway depends heavily on your context:
AWS API Gateway / Azure API Management / Google Cloud Endpoints: Appropriate for cloud-native deployments deeply integrated with the respective cloud's ecosystem. Good managed options if you don't want to operate gateway infrastructure.
Kong / Traefik / NGINX / Envoy: Self-hosted options with varying plugin ecosystems and configuration models. Kong and Traefik are particularly popular for microservices environments with plugin-based extensibility.
Custom BFF (Node.js/Go service): When a dedicated BFF pattern is the right answer and the aggregation logic is complex enough to warrant a real application.
The worst answer is "we'll figure it out later." Authentication enforcement, rate limiting, and routing strategy are foundational. Get them right early.
If you're designing an API gateway strategy or evaluating options for a microservices deployment, let's connect.