API Gateway Patterns: Routing, Security & the BFF Approach
An API gateway is the front door of your microservice architecture. It handles cross-cutting concerns so that individual services do not have to. But gateway design decisions have long-lasting consequences on performance, coupling, and team autonomy.
Gateway Responsibilities Taxonomy
API Gateway Responsibilities
├── Traffic Management
│ ├── Request routing
│ ├── Load balancing
│ ├── Rate limiting / throttling
│ ├── Circuit breaking
│ └── Canary / blue-green routing
├── Security
│ ├── Authentication (JWT validation, OAuth2)
│ ├── Authorization (scope/role checking)
│ ├── TLS termination
│ ├── CORS management
│ └── IP whitelisting / WAF integration
├── Transformation
│ ├── Request/response mapping
│ ├── Protocol translation (REST↔gRPC)
│ ├── Header injection
│ └── Response aggregation
├── Observability
│ ├── Access logging
│ ├── Distributed tracing (trace ID injection)
│ ├── Metrics collection
│ └── Health check endpoints
└── Developer Experience
├── API documentation (OpenAPI serving)
├── Developer portal
├── API key management
└── Usage analytics
Tool Comparison
| Feature | Kong | Envoy | AWS API Gateway | Apigee (Google) | Traefik |
|---|---|---|---|---|---|
| Type | Full gateway | Proxy / data plane | Managed service | Managed platform | Edge router |
| Deployment | Self-hosted or cloud | Sidecar or edge | AWS-managed | GCP-managed | Self-hosted or cloud |
| Protocol support | HTTP, gRPC, WebSocket | HTTP/2, gRPC, TCP | HTTP, WebSocket, REST | HTTP, gRPC | HTTP, TCP, gRPC |
| Plugin ecosystem | Extensive (Lua, Go) | Filters (C++, Wasm) | Lambda authorizers | Policies (extensive) | Middlewares (Go) |
| Service mesh role | Via Kuma | Istio data plane | N/A | N/A | Via Traefik Mesh |
| Best for | API management at scale | High-performance proxy | AWS-native workloads | Enterprise API program | Kubernetes ingress |
| Pricing model | Open source + enterprise | Open source | Per request + data | Per API call | Open source + enterprise |
| Learning curve | Medium | High | Low | Medium-High | Low-Medium |
Backend-for-Frontend (BFF) Pattern
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Mobile │ │ Web │ │ Partner │
│ App │ │ SPA │ │ API │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
┌────▼─────┐ ┌────▼─────┐ ┌────▼─────┐
│ Mobile │ │ Web │ │ Partner │
│ BFF │ │ BFF │ │ BFF │
│ │ │ │ │ │
│ - Compact│ │ - Rich │ │ - Stable │
│ payload│ │ payload│ │ versioned│
│ - Offline│ │ - SSR │ │ contract│
│ support│ │ support│ │ - Rate │
│ - Push │ │ - WebSock│ │ limited │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└─────────────┼─────────────┘
│
┌────────▼────────┐
│ Internal API │
│ Gateway / Mesh │
└────────┬────────┘
│
┌─────────┬───┴───┬─────────┐
│ │ │ │
┌──▼──┐ ┌──▼──┐ ┌──▼──┐ ┌──▼──┐
│Svc A│ │Svc B│ │Svc C│ │Svc D│
└─────┘ └─────┘ └─────┘ └─────┘
API Gateway vs Service Mesh
| Dimension | API Gateway | Service Mesh |
|---|---|---|
| Position | Edge (north-south traffic) | Internal (east-west traffic) |
| Primary role | External API management | Service-to-service communication |
| Authentication | External identity (JWT, API key) | mTLS between services |
| Rate limiting | Per external client | Per service / per route |
| Observability | API-level metrics, access logs | Distributed traces, L7 metrics |
| Protocol | HTTP/REST focus | Any protocol (L4/L7) |
| Deployment | Centralized (1-few instances) | Distributed (sidecar per pod) |
| Managed by | Platform / API team | Platform team |
| Tools | Kong, AWS APIGW, Apigee | Istio, Linkerd, Consul Connect |
| Overlap | Yes -- both can do routing, TLS, observability |
Key insight: They are complementary, not competing. Use a gateway for external traffic and a mesh for internal traffic. Avoid duplicating policies across both layers.
Anti-Patterns
The God Gateway -- Putting business logic in the gateway (field transformations, complex orchestration). The gateway should route and enforce policies, not contain domain logic.
Shared gateway across teams -- When one team's gateway change breaks another team's API. Give teams ownership of their own gateway configuration or use a self-service model.
No gateway at all -- Exposing microservices directly means every service reimplements auth, rate limiting, and CORS. Cross-cutting concerns belong in infrastructure.