API Gateway Patterns#

An API gateway sits between clients and your backend services. It handles cross-cutting concerns – authentication, rate limiting, request transformation, routing – so your services do not have to. Choosing the right gateway and configuring it correctly is one of the first decisions in any microservices architecture.

Gateway Responsibilities#

Before selecting a gateway, clarify which responsibilities it should own:

  • Routing – directing requests to the correct backend service based on path, headers, or method.
  • Authentication and authorization – validating tokens, API keys, or certificates before requests reach backends.
  • Rate limiting – protecting backends from traffic spikes and enforcing usage quotas.
  • Request/response transformation – modifying headers, rewriting paths, converting between formats.
  • Load balancing – distributing traffic across service instances.
  • Observability – emitting metrics, logs, and traces for every request that passes through.
  • TLS termination – handling HTTPS so backends can speak plain HTTP internally.

No gateway does everything equally well. The right choice depends on which of these responsibilities matter most in your environment.

Gateway Options#

Kong#

Kong is the most feature-rich open-source API gateway. It runs on top of NGINX/OpenResty and extends it with a plugin system. Kong stores its configuration in PostgreSQL or runs in declarative (DB-less) mode.

Strengths: Extensive plugin ecosystem (authentication, rate limiting, logging, transformations), enterprise support, hybrid deployment mode (control plane + data planes), strong community.

Weaknesses: Heavier resource footprint than alternatives, PostgreSQL dependency in traditional mode, plugin configuration can become complex at scale.

Best for: Teams that need a full-featured gateway with enterprise support, complex authentication flows, or extensive plugin requirements.

# Kong Ingress Controller on Kubernetes
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: rate-limit-api
plugin: rate-limiting
config:
  minute: 100
  hour: 5000
  policy: redis
  redis_host: redis.infrastructure.svc
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-routes
  annotations:
    konghq.com/plugins: rate-limit-api
    konghq.com/strip-path: "true"
spec:
  ingressClassName: kong
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /orders
            pathType: Prefix
            backend:
              service:
                name: order-service
                port:
                  number: 8080

Emissary-Ingress (formerly Ambassador)#

Emissary-Ingress is built on Envoy Proxy and designed specifically for Kubernetes. It uses Custom Resource Definitions (CRDs) for configuration, which integrates naturally with GitOps workflows.

Strengths: Native Kubernetes integration, Envoy-based (high performance, protocol-aware), CRD-driven configuration, built-in support for canary releases and traffic shifting.

Weaknesses: Kubernetes-only (no standalone mode), smaller plugin ecosystem than Kong, Envoy’s complexity surfaces in advanced configurations.

Best for: Kubernetes-native teams that want Envoy’s performance and protocol awareness with a simpler configuration model.

apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
  name: order-service
spec:
  hostname: api.example.com
  prefix: /orders/
  service: order-service.production:8080
  timeout_ms: 5000
  retry_policy:
    retry_on: "5xx"
    num_retries: 3
---
apiVersion: getambassador.io/v3alpha1
kind: RateLimit
metadata:
  name: api-rate-limit
spec:
  domain: api.example.com
  limits:
    - pattern:
        - generic_key: "default"
      rate: 100
      unit: minute

NGINX Ingress Controller#

The community NGINX Ingress Controller (kubernetes/ingress-nginx) is the most widely deployed ingress controller. It is not a full API gateway out of the box, but annotations and snippets extend it significantly.

Strengths: Battle-tested, lightweight, extensive documentation, low resource consumption, familiar NGINX configuration model.

Weaknesses: Configuration via annotations is limited and awkward for complex scenarios, no native plugin system, custom logic requires NGINX snippets (which are error-prone and hard to test).

Best for: Teams with simple routing needs, existing NGINX expertise, or environments where resource efficiency matters most.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-routes
  annotations:
    nginx.ingress.kubernetes.io/rate-limit: "100"
    nginx.ingress.kubernetes.io/rate-limit-window: "1m"
    nginx.ingress.kubernetes.io/auth-url: "https://auth.internal/validate"
    nginx.ingress.kubernetes.io/auth-response-headers: "X-User-ID,X-User-Role"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header X-Request-Start "t=${msec}";
spec:
  ingressClassName: nginx
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /api/v1
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080

Traefik#

Traefik auto-discovers services and routes traffic to them. It integrates with Docker, Kubernetes, Consul, and other orchestrators natively. It is the default ingress controller in k3s.

Strengths: Automatic service discovery, automatic TLS via Let’s Encrypt, middleware chain model, dashboard UI, TCP/UDP routing support.

Weaknesses: Middleware configuration is less intuitive than Kong’s plugin model, fewer enterprise authentication integrations, debugging complex routing requires understanding Traefik’s priority system.

Best for: Teams running k3s or lightweight clusters, environments with dynamic service discovery needs, or setups where automatic TLS is a priority.

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: rate-limit
spec:
  rateLimit:
    average: 100
    burst: 50
    period: 1m
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: auth-forward
spec:
  forwardAuth:
    address: http://auth-service.infrastructure.svc:8080/validate
    authResponseHeaders:
      - X-User-ID
      - X-User-Role
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: api-routes
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`api.example.com`) && PathPrefix(`/orders`)
      kind: Rule
      services:
        - name: order-service
          port: 8080
      middlewares:
        - name: rate-limit
        - name: auth-forward

AWS API Gateway#

AWS API Gateway is a managed service with two variants: REST API (feature-rich, more expensive) and HTTP API (simpler, cheaper, faster). It integrates tightly with Lambda, IAM, Cognito, and other AWS services.

Strengths: Fully managed (no infrastructure to operate), native AWS integration, built-in authorization via Cognito and IAM, usage plans and API keys, WebSocket support.

Weaknesses: Vendor lock-in, cold start latency for Lambda integrations, 29-second timeout limit on REST APIs, request/response size limits (10MB), complex pricing model.

Best for: AWS-native architectures, serverless backends, teams that want zero gateway infrastructure management.

# AWS SAM template
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  ApiGateway:
    Type: AWS::Serverless::HttpApi
    Properties:
      StageName: prod
      CorsConfiguration:
        AllowOrigins:
          - "https://app.example.com"
        AllowMethods:
          - GET
          - POST
      Auth:
        DefaultAuthorizer: CognitoAuthorizer
        Authorizers:
          CognitoAuthorizer:
            AuthorizationScopes:
              - api/read
            IdentitySource: $request.header.Authorization
            JwtConfiguration:
              issuer: !Sub "https://cognito-idp.${AWS::Region}.amazonaws.com/${UserPool}"
              audience:
                - !Ref UserPoolClient

Cloudflare API Shield#

Cloudflare API Shield operates at the edge, providing schema validation, mTLS, rate limiting, and bot detection before traffic reaches your origin.

Strengths: Edge-level protection (stops bad traffic before it hits your infrastructure), schema validation against OpenAPI specs, anomaly detection, global presence (low latency worldwide).

Weaknesses: Not a traditional routing gateway (your origin still needs a routing layer), less flexible request transformation, requires Cloudflare as your DNS/proxy layer.

Best for: Public-facing APIs that need DDoS protection, schema enforcement, and global edge caching alongside gateway functionality.

Rate Limiting Patterns#

Rate limiting protects your backends and enforces usage quotas. The implementation depends on your requirements.

Fixed window#

Count requests in fixed time windows (e.g., 100 requests per minute). Simple to implement but allows burst traffic at window boundaries – a client can send 100 requests at 11:59:59 and another 100 at 12:00:00.

Sliding window#

Track requests over a rolling time period. More accurate than fixed window but requires more state. Most production gateways use sliding window or a hybrid approach.

Token bucket#

Clients accumulate tokens at a fixed rate and spend one token per request. This allows controlled bursting while maintaining a long-term average rate. Kong and Traefik both support this model.

# Kong token bucket rate limiting
plugin: rate-limiting
config:
  minute: 100     # refill rate
  policy: redis   # shared state across gateway instances
  redis_host: redis.infrastructure.svc
  redis_port: 6379
  fault_tolerant: true   # allow traffic if Redis is down
  hide_client_headers: false  # expose X-RateLimit-* headers

Always return rate limit headers so clients can self-throttle:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1708646400

Per-entity rate limits#

Rate limit by API key, user ID, IP address, or a combination. Per-IP is the default but insufficient for APIs behind CDNs (all requests appear from CDN IPs). Use a client identifier header or API key instead.

Authentication Offloading#

The gateway validates authentication so backend services receive pre-validated requests with identity information in headers.

JWT validation at the gateway#

Client -> [JWT in Authorization header] -> Gateway (validates JWT)
  -> [X-User-ID, X-User-Role headers] -> Backend Service

The gateway validates the JWT signature, checks expiration, and extracts claims. Backend services trust the headers from the gateway and skip token validation entirely. This requires that backends are not directly accessible – only the gateway can reach them.

External auth service#

For complex authorization logic, the gateway delegates to an external auth service:

# NGINX external auth
nginx.ingress.kubernetes.io/auth-url: "http://auth-service.infrastructure.svc/validate"
nginx.ingress.kubernetes.io/auth-response-headers: "X-User-ID,X-User-Role,X-Tenant-ID"
nginx.ingress.kubernetes.io/auth-cache-key: "$http_authorization"
nginx.ingress.kubernetes.io/auth-cache-duration: "200 5m, 401 1m"

The auth service receives the original request headers, validates the token, checks permissions, and returns 200 (allowed) or 401/403 (denied). The gateway forwards or rejects the request accordingly.

Request Transformation Patterns#

Path rewriting#

Strip prefixes so backends do not need to know their gateway path:

# Client sends:      GET /api/v1/orders/123
# Gateway forwards:  GET /orders/123  (to order-service)

Header injection#

Add service mesh context, request IDs, or tenant information:

# Emissary header injection
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
  name: order-service
spec:
  prefix: /orders/
  service: order-service:8080
  add_request_headers:
    X-Request-ID:
      append: false
      value: "%REQ(X-REQUEST-ID)%"
    X-Gateway-Timestamp:
      value: "%START_TIME(%s)%"

Response transformation#

Remove internal headers, add CORS headers, or wrap responses in a standard envelope. Most gateways handle CORS at the gateway level so backends do not need CORS middleware.

Selection Decision Matrix#

Requirement Kong Emissary NGINX Traefik AWS APIGW CF Shield
Kubernetes native Good Best Good Good N/A N/A
Plugin ecosystem Best Good Limited Good AWS-only Limited
Performance Good Best Best Good Variable Best
Operational overhead Medium Medium Low Low None None
Enterprise auth Best Good Basic Good AWS native Basic
Edge protection N/A N/A N/A N/A CloudFront Best
Multi-protocol Good Best Limited Good REST/WS HTTP only

Choose Kong when you need the richest plugin ecosystem and enterprise authentication flows. Choose Emissary when you are Kubernetes-native and want Envoy’s performance. Choose NGINX when you need simplicity and low overhead. Choose Traefik when you want auto-discovery and automatic TLS. Choose AWS API Gateway when you are all-in on AWS and want zero infrastructure management. Choose Cloudflare API Shield when edge protection and global performance are primary concerns.

Start with the simplest option that meets your requirements. You can always add complexity later, but removing it is much harder.