# API Gateway Patterns for Microservices: A Practical Architecture Guide

> An advanced guide to API gateway patterns in microservices architectures — BFF, edge gateway, sidecar, and how to choose the right topology for your backend.

- **Published:** 2025-12-15
- **Author:** Clixo
- **Reading time:** 6 min read
- **Tags:** api-gateway, microservices, backend-architecture, advanced
- **Canonical URL:** https://clixo.sh/blog/api-gateway-patterns-microservices-architecture

When a system moves from a monolith to microservices, the question of how clients talk to internal services becomes structural. Direct service-to-client communication creates coupling, multiplies the number of network addresses clients must know, and forces cross-cutting concerns — authentication, rate limiting, logging — into every individual service.

An API gateway addresses this. But "API gateway" covers several distinct architectural patterns, each with a different trade-off profile. Choosing the wrong one introduces the problems it was supposed to solve.

## API Gateway Patterns in Microservices

### The Edge Gateway Pattern

The simplest and most common pattern. A single gateway sits between all external clients and all internal services. It handles:

- TLS termination
- Authentication and authorization
- Rate limiting and quotas
- Request routing to upstream services
- Request/response transformation
- Logging and observability

**When it works well:** when external traffic is the primary concern, when your internal services do not need different access control policies, and when the number of services is manageable.

**Where it breaks down:** a single edge gateway becomes a bottleneck and a deployment coupling point as the service count grows. Every new service requires a gateway configuration change. Every new client type requires gateway logic to accommodate it. Teams that own individual services cannot deploy independently of the gateway team.

### The Backend for Frontend (BFF) Pattern

Instead of one gateway for all clients, each major client type gets its own gateway instance:

- `web-bff` for the browser application
- `mobile-bff` for iOS and Android clients
- `partner-bff` for third-party API consumers

Each BFF is owned by the team that owns the client. It handles request aggregation, response shaping, and client-specific business logic without coordinating with other teams.

**Why this matters:** mobile clients often need different data projections than web clients. A single API that serves both over-fetches for one or under-fetches for the other. The BFF layer handles the translation without polluting the underlying services with client-specific logic.

**The cost:** more gateway instances to operate. Each BFF is a service that needs to be deployed, monitored, and maintained. For small teams, this overhead is often not worth the separation.

```mermaid
flowchart LR
  WC[Web Client] --> WB["Web BFF"]
  MC[Mobile Client] --> MB["Mobile BFF"]
  PC[Partner Client] --> PB["Partner BFF"]
  WB --> US[Users Service]
  WB --> OS[Orders Service]
  MB --> US
  MB --> NS[Notifications Service]
  PB --> OS
  PB --> IS[Inventory Service]
```

### The Aggregation Gateway

A gateway that combines multiple upstream service calls into a single client response. A client requests a user profile page; the gateway calls the users service, the orders service, and the preferences service in parallel, then assembles the response.

This keeps downstream services simple (single-responsibility resources) while giving clients a convenient composite view without multiple round trips.

**Implementation consideration:** parallel fan-out is straightforward. What requires care is partial failure — if the orders service is slow or unavailable, does the entire response fail, or do you return partial data with a degraded state indicator? Define this contract explicitly and implement circuit-breaking on upstream calls.

### Service Mesh vs API Gateway

A common source of confusion: a service mesh (Istio, Linkerd) is not an API gateway. A service mesh manages service-to-service communication inside the cluster — mutual TLS, retries, observability, traffic shaping between internal services. An API gateway manages inbound external traffic.

They are complementary, not alternatives. A well-architected microservices system typically uses both: an API gateway at the edge for external consumers, and a service mesh for internal service communication.

Trying to use one for the job of the other produces either an overloaded gateway configuration or a service mesh that is managing external traffic it was not designed to handle efficiently.

### The Sidecar Proxy Pattern

In this pattern, each service instance runs with a proxy sidecar container (typically Envoy) that handles inbound and outbound traffic on behalf of the service. Cross-cutting concerns — retries, circuit breaking, mTLS, distributed tracing — live in the sidecar, not in application code.

**The advantage:** service code is simpler. Language-specific networking libraries are replaced by a single, consistently-configured proxy layer. Operational behavior (retry budgets, timeout policies) is declared in configuration, not scattered across multiple language implementations.

**The overhead:** sidecar containers add memory and CPU cost per instance. The configuration layer (a control plane like Istio) adds operational complexity. This pattern makes sense when you have many services and the cost of implementing networking logic in each one exceeds the cost of running the mesh infrastructure.

## Routing Strategies Worth Knowing

**Path-based routing:** route by URL prefix. `/v1/users` goes to the users service, `/v1/orders` goes to the orders service. Simple and transparent.

**Header-based routing:** route by request header. Useful for A/B testing, canary deployments, and multi-tenant routing where different tenants hit different service versions.

**Weighted routing:** split traffic between two versions of a service by percentage. The standard mechanism for canary releases — start at 5% new version, monitor error rates, increment to 100%.

## What Belongs in the Gateway vs the Service

A useful heuristic: the gateway should handle concerns that apply to all requests regardless of which service handles them. Services should handle concerns that are specific to their domain.

**In the gateway:**
- Authentication (verify the token is valid)
- Rate limiting (enforce per-client quotas)
- TLS termination
- Access logging

**In the service:**
- Authorization (is this authenticated user allowed to do this specific operation?)
- Business logic
- Domain-specific validation

Authorization is the one that most often ends up in the wrong layer. Checking whether a user can read another user's private data requires knowing the domain model — it belongs in the service, not in the gateway.

## Choosing a Gateway Implementation

For standard API gateway requirements, managed services (AWS API Gateway, Kong, Traefik, Nginx) cover most teams' needs without custom code. The decision between managed and self-hosted is primarily operational: managed services reduce infrastructure burden at the cost of flexibility and per-request pricing.

For teams with complex routing requirements, high traffic volume where per-request gateway pricing becomes significant, or specialized protocol needs, self-hosted gateways with Envoy or Nginx offer more control.

If you are designing a microservices backend and need the gateway topology matched to your actual service structure and team topology, [Clixo designs and builds production backend systems](https://clixo.sh/#contact).

---

Clixo · 1141 W Bryn Mawr Ave, Itasca, IL 60143, US · [hello@clixo.sh](mailto:hello@clixo.sh)
[Start a build](https://clixo.sh/#contact) · [All services](https://clixo.sh/services) · [Agent guide (llms.txt)](https://clixo.sh/llms.txt)
