Back to blog

API Gateway Complete Guide

api-gatewaybackendmicroservicesarchitecturedevopsinfrastructure
API Gateway Complete Guide

If you've built or worked with microservices, you've hit this problem: clients need to talk to multiple backend services. Without a single entry point, every client must know every service's address, handle authentication separately, and deal with different protocols.

An API gateway solves this. It's the front door for all your API traffic — one URL, one place for authentication, one place for rate limiting, and intelligent routing to all your backend services.

In the Reverse Proxy post, we covered how a reverse proxy handles SSL termination, caching, and load balancing. An API gateway does all of that plus API-specific concerns: authentication, request transformation, rate limiting per API key, and response aggregation.

Time commitment: 1-2 hours
Prerequisites: Understanding of REST APIs, HTTP, and reverse proxies

What You'll Learn

✅ What an API gateway is and why microservices need one
✅ How API gateways differ from reverse proxies
✅ Routing patterns — path-based, header-based, and versioned routing
✅ Authentication and authorization at the gateway
✅ Rate limiting — per client, per API key, per endpoint
✅ Request/response transformation and aggregation
✅ Circuit breaking and resilience patterns
✅ Practical setup with Kong, AWS API Gateway, and Spring Cloud Gateway


1. What is an API Gateway?

An API gateway is a server that sits between clients and your backend services. It receives all API requests, routes them to the right service, and returns the response.

Without an API gateway, every client needs to:

  • Know the address of every service
  • Handle authentication with each service separately
  • Deal with different protocols and data formats
  • Implement retry logic and circuit breaking
  • Handle API versioning per service

The gateway centralizes all of this.

What It Does

When a request arrives at the API gateway:

  1. Authenticates — validates API key, JWT token, or OAuth token
  2. Authorizes — checks if the client has permission for this endpoint
  3. Rate limits — checks if the client has exceeded their quota
  4. Routes — determines which backend service handles this request
  5. Transforms — modifies the request format if needed (headers, body)
  6. Forwards — sends the request to the backend service
  7. Aggregates — optionally combines responses from multiple services
  8. Returns — sends the response back to the client

2. API Gateway vs Reverse Proxy

A reverse proxy and an API gateway overlap significantly. The key difference is what level they operate at.

AspectReverse ProxyAPI Gateway
FocusInfrastructure (HTTP traffic)Application (API management)
RoutingPath/host-basedPath, header, method, query param, version
AuthenticationBasic (IP, client cert)JWT, OAuth2, API keys, OIDC
Rate limitingPer IP addressPer API key, per user, per endpoint
TransformationHeader manipulationRequest/response body transformation
AggregationNoCombine multiple service responses
API versioningNo (manual)Built-in version management
Developer portalNoAPI docs, key management, usage analytics
ExamplesNginx, HAProxyKong, AWS API Gateway, Apigee

Think of it this way:

  • Reverse proxy: "Route this HTTP request to the right server"
  • API gateway: "Authenticate this API consumer, check their rate limit, transform the request, route it, and log the usage"

In practice, many tools blur this line. Nginx with Lua plugins can act as an API gateway. Kong is built on Nginx but adds API management features. The distinction is about capability, not strict categories.


3. Core Features

3.1 Request Routing

The most fundamental feature — route incoming requests to the right backend service.

Path-based routing:

GET /api/users/123      → User Service
GET /api/orders/456     → Order Service
POST /api/payments      → Payment Service
GET /api/notifications  → Notification Service

Header-based routing:

X-API-Version: v1  → Legacy Service
X-API-Version: v2  → New Service

Method-based routing:

GET  /api/products  → Product Read Service (optimized for queries)
POST /api/products  → Product Write Service (optimized for writes)

Query parameter routing:

GET /api/search?type=products  → Product Search Service
GET /api/search?type=users     → User Search Service

3.2 Authentication and Authorization

The gateway is the perfect place to handle auth — validate once, forward the identity downstream.

Common auth patterns at the gateway:

PatternHow It WorksBest For
API KeyClient sends key in header (X-API-Key)Third-party integrations
JWTClient sends token in Authorization: Bearer headerSPAs, mobile apps
OAuth2Gateway handles full OAuth2 flowThird-party API access
mTLSClient presents certificateService-to-service
OIDCOpenID Connect for identity verificationEnterprise SSO

Key principle: The gateway validates the token and extracts the identity. Backend services receive trusted headers (X-User-ID, X-Role) — they don't need to validate tokens themselves.

3.3 Rate Limiting

Control how many requests each client can make. This protects your backend from abuse and ensures fair usage.

Rate limiting strategies:

StrategyExampleUse Case
Per IP100 req/min per IPBasic DDoS protection
Per API key1000 req/hour per keyThird-party API access
Per user50 req/min per userAuthenticated endpoints
Per endpoint10 req/min on /loginBrute-force protection
Global10,000 req/min totalOverall system protection

Rate limit response:

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710000000
Retry-After: 30
 
{
  "error": "rate_limit_exceeded",
  "message": "You have exceeded 100 requests per minute",
  "retry_after": 30
}

Rate limiting algorithms:

  • Fixed window: Count requests in fixed time windows (e.g., per minute). Simple but can allow bursts at window boundaries.
  • Sliding window: Smoother distribution using a rolling time window. More accurate.
  • Token bucket: Tokens accumulate over time, each request consumes one. Allows controlled bursts.
  • Leaky bucket: Requests queue up and process at a fixed rate. Smoothest output.

3.4 Request/Response Transformation

Transform requests and responses as they pass through the gateway.

Request transformation:

Client sends:
POST /api/v2/users
Content-Type: application/json
{ "firstName": "John", "lastName": "Doe" }
 
Gateway transforms to:
POST /users
Content-Type: application/json
X-API-Version: 2
{ "first_name": "John", "last_name": "Doe" }

Response transformation:

Backend responds:
{ "user_id": 123, "first_name": "John", "created_at": "2026-03-11T..." }
 
Gateway transforms to:
{ "id": 123, "firstName": "John", "createdAt": "2026-03-11T..." }

Common transformations:

  • Header injection: Add API version, correlation ID, request timestamp
  • Body format: Convert between camelCase and snake_case
  • Field filtering: Remove internal fields from responses
  • Protocol translation: Accept REST, forward as gRPC
  • Response wrapping: Wrap responses in a standard envelope

3.5 Request Aggregation (API Composition)

One of the most powerful features — combine responses from multiple services into a single response for the client.

Without aggregation, the client would need to make 3 separate API calls. With aggregation, one call returns everything.

Example aggregated response:

{
  "user": {
    "id": 123,
    "name": "John Doe",
    "email": "john@example.com"
  },
  "recentOrders": [
    { "id": 456, "total": 99.99, "status": "delivered" },
    { "id": 457, "total": 49.99, "status": "processing" }
  ],
  "paymentMethods": [
    { "type": "credit_card", "last4": "4242" }
  ]
}

This is especially valuable for mobile clients where minimizing network requests matters.

3.6 Circuit Breaking

When a backend service is failing, the gateway can stop sending it requests — preventing cascading failures.

Circuit states:

StateBehavior
ClosedNormal operation — all requests forwarded
OpenBackend is failing — return fallback/error immediately, don't forward
Half-OpenAfter timeout, send one test request. If it succeeds, close circuit. If it fails, keep open.

Configuration example:

circuit_breaker:
  threshold: 5          # Open after 5 consecutive failures
  timeout: 30s          # Wait 30s before trying half-open
  half_open_requests: 3 # Allow 3 test requests in half-open
  failure_codes:        # Which HTTP codes count as failures
    - 500
    - 502
    - 503
    - 504

4. API Gateway Patterns

4.1 Single Gateway

The simplest pattern — one gateway for all clients and all services.

Pros: Simple, centralized configuration, easy to monitor.

Cons: Single point of failure, one team owns the gateway, can become a bottleneck.

4.2 Backend for Frontend (BFF)

Each client type gets its own gateway that's tailored to its needs.

Why BFF?

  • Mobile needs compact responses (bandwidth is limited) and different aggregation
  • Web needs richer responses and may access more services
  • Third-party needs stable, versioned APIs with strict rate limiting

Each BFF team can deploy independently without coordinating with other teams.

4.3 Gateway per Domain

In large organizations, each domain/team owns their gateway.

Pros: Teams own their gateway, independent deployments, domain isolation.

Cons: Duplicated cross-cutting concerns, harder to enforce global policies.

4.4 Sidecar Gateway (Service Mesh)

Instead of a centralized gateway, each service gets its own proxy sidecar (like Envoy in Istio).

This is the service mesh approach (Istio, Linkerd). The sidecar handles mTLS, retry, circuit breaking, and observability for service-to-service communication. The ingress gateway handles external client traffic.


5. API Versioning at the Gateway

The gateway is the ideal place to manage API versions without changing backend services.

Versioning Strategies

URL path versioning:

GET /api/v1/users/123  → User Service v1
GET /api/v2/users/123  → User Service v2

Header versioning:

GET /api/users/123
Accept: application/vnd.api.v2+json  → User Service v2

Query parameter versioning:

GET /api/users/123?version=2  → User Service v2

Gateway-Level Version Routing

The gateway can route different versions to different backend deployments:

routes:
  - path: /api/v1/users
    service: user-service-v1
    strip_prefix: /api/v1
 
  - path: /api/v2/users
    service: user-service-v2
    strip_prefix: /api/v2
 
  # Default latest version
  - path: /api/users
    service: user-service-v2
    strip_prefix: /api

Or the gateway can transform requests to match the backend's expected format — allowing one backend to serve multiple API versions:

routes:
  - path: /api/v1/users
    service: user-service
    transform:
      request:
        rename_fields:
          firstName: first_name
          lastName: last_name
      response:
        rename_fields:
          first_name: firstName
          last_name: lastName

6. Practical Setup: Kong

Kong is the most popular open-source API gateway. Built on Nginx + Lua, it combines high performance with a plugin ecosystem.

Setup with Docker

# docker-compose.yml
version: "3.8"
 
services:
  kong-database:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: kong
      POSTGRES_DB: kong
      POSTGRES_PASSWORD: kongpass
    volumes:
      - kong-data:/var/lib/postgresql/data
 
  kong-migration:
    image: kong:3.6
    depends_on:
      - kong-database
    environment:
      KONG_DATABASE: postgres
      KONG_PG_HOST: kong-database
      KONG_PG_PASSWORD: kongpass
    command: kong migrations bootstrap
 
  kong:
    image: kong:3.6
    depends_on:
      - kong-database
      - kong-migration
    environment:
      KONG_DATABASE: postgres
      KONG_PG_HOST: kong-database
      KONG_PG_PASSWORD: kongpass
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_ADMIN_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG: /dev/stderr
      KONG_ADMIN_ERROR_LOG: /dev/stderr
      KONG_ADMIN_LISTEN: "0.0.0.0:8001"
    ports:
      - "8000:8000"    # Proxy port
      - "8443:8443"    # Proxy SSL port
      - "8001:8001"    # Admin API
 
volumes:
  kong-data:

Configuring Routes

# Create a service
curl -i -X POST http://localhost:8001/services/ \
  --data "name=user-service" \
  --data "url=http://user-service:3000"
 
# Create a route for the service
curl -i -X POST http://localhost:8001/services/user-service/routes \
  --data "name=user-routes" \
  --data "paths[]=/api/users" \
  --data "strip_path=true"
 
# Create another service
curl -i -X POST http://localhost:8001/services/ \
  --data "name=order-service" \
  --data "url=http://order-service:3001"
 
# Route for order service
curl -i -X POST http://localhost:8001/services/order-service/routes \
  --data "name=order-routes" \
  --data "paths[]=/api/orders" \
  --data "strip_path=true"

Adding Plugins

# Rate limiting — 100 requests per minute per consumer
curl -i -X POST http://localhost:8001/services/user-service/plugins \
  --data "name=rate-limiting" \
  --data "config.minute=100" \
  --data "config.policy=local"
 
# JWT authentication
curl -i -X POST http://localhost:8001/services/user-service/plugins \
  --data "name=jwt"
 
# Request logging
curl -i -X POST http://localhost:8001/services/user-service/plugins \
  --data "name=file-log" \
  --data "config.path=/tmp/api-logs.log"
 
# CORS
curl -i -X POST http://localhost:8001/services/user-service/plugins \
  --data "name=cors" \
  --data "config.origins[]=https://example.com" \
  --data "config.methods[]=GET" \
  --data "config.methods[]=POST" \
  --data "config.headers[]=Authorization" \
  --data "config.headers[]=Content-Type"
 
# Response transformer — remove internal headers
curl -i -X POST http://localhost:8001/services/user-service/plugins \
  --data "name=response-transformer" \
  --data "config.remove.headers=X-Powered-By" \
  --data "config.remove.headers=Server"

Kong Declarative Configuration

For production, use declarative config (YAML) instead of the Admin API:

# kong.yml
_format_version: "3.0"
 
services:
  - name: user-service
    url: http://user-service:3000
    routes:
      - name: user-routes
        paths:
          - /api/users
        strip_path: true
    plugins:
      - name: rate-limiting
        config:
          minute: 100
          policy: redis
          redis_host: redis
      - name: jwt
      - name: cors
        config:
          origins:
            - "https://example.com"
          methods:
            - GET
            - POST
            - PUT
            - DELETE
 
  - name: order-service
    url: http://order-service:3001
    routes:
      - name: order-routes
        paths:
          - /api/orders
        strip_path: true
    plugins:
      - name: rate-limiting
        config:
          minute: 50
          policy: redis
          redis_host: redis
 
consumers:
  - username: mobile-app
    jwt_secrets:
      - key: mobile-app-key
        algorithm: HS256
        secret: your-secret-key
 
  - username: web-app
    jwt_secrets:
      - key: web-app-key
        algorithm: HS256
        secret: your-other-secret

7. Practical Setup: AWS API Gateway

AWS API Gateway is a fully managed service — no servers to manage.

REST API Configuration

# serverless.yml (Serverless Framework)
service: my-api
 
provider:
  name: aws
  runtime: nodejs20.x
  region: us-east-1
 
functions:
  getUsers:
    handler: handlers/users.getAll
    events:
      - http:
          path: /users
          method: get
          cors: true
          authorizer:
            type: COGNITO_USER_POOLS
            authorizerId:
              Ref: ApiGatewayAuthorizer
 
  getUser:
    handler: handlers/users.getById
    events:
      - http:
          path: /users/{id}
          method: get
          cors: true
 
  createOrder:
    handler: handlers/orders.create
    events:
      - http:
          path: /orders
          method: post
          cors: true
 
resources:
  Resources:
    # Usage plan with rate limiting
    ApiUsagePlan:
      Type: AWS::ApiGateway::UsagePlan
      Properties:
        UsagePlanName: BasicPlan
        Throttle:
          BurstLimit: 100
          RateLimit: 50
        Quota:
          Limit: 10000
          Period: MONTH
 
    # API Key
    ApiKey:
      Type: AWS::ApiGateway::ApiKey
      Properties:
        Name: mobile-app-key
        Enabled: true
 
    # Cognito authorizer
    ApiGatewayAuthorizer:
      Type: AWS::ApiGateway::Authorizer
      Properties:
        Name: CognitoAuthorizer
        Type: COGNITO_USER_POOLS
        ProviderARNs:
          - !GetAtt UserPool.Arn
        RestApiId:
          Ref: ApiGatewayRestApi
        IdentitySource: method.request.header.Authorization

HTTP API (Simpler, Cheaper)

# AWS SAM template
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
 
Resources:
  HttpApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      StageName: prod
      CorsConfiguration:
        AllowMethods:
          - GET
          - POST
          - PUT
          - DELETE
        AllowOrigins:
          - "https://example.com"
        AllowHeaders:
          - Authorization
          - Content-Type
 
  GetUsersFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: handlers/users.getAll
      Runtime: nodejs20.x
      Events:
        GetUsers:
          Type: HttpApi
          Properties:
            ApiId: !Ref HttpApi
            Path: /users
            Method: GET

AWS API Gateway Features

FeatureREST APIHTTP API
CostHigher~70% cheaper
LatencyHigherLower
CachingBuilt-inNo
API KeysYesNo
Usage plansYesNo
Request validationYesNo
WAF integrationYesYes
JWT authorizerVia LambdaBuilt-in
Best forFull API managementSimple, cost-effective APIs

8. Practical Setup: Spring Cloud Gateway

If you're in the Java/Spring ecosystem, Spring Cloud Gateway is the natural choice.

Setup

<!-- pom.xml -->
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
    </dependency>
</dependencies>

Configuration

# application.yml
spring:
  cloud:
    gateway:
      routes:
        # User service
        - id: user-service
          uri: http://user-service:3000
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1
            - name: CircuitBreaker
              args:
                name: userServiceCB
                fallbackUri: forward:/fallback/users
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                key-resolver: "#{@apiKeyResolver}"
            - AddRequestHeader=X-Gateway, spring-cloud
 
        # Order service
        - id: order-service
          uri: http://order-service:3001
          predicates:
            - Path=/api/orders/**
            - Method=GET,POST,PUT
          filters:
            - StripPrefix=1
            - name: Retry
              args:
                retries: 3
                statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
                methods: GET
                backoff:
                  firstBackoff: 100ms
                  maxBackoff: 500ms
                  factor: 2
 
        # Version-based routing
        - id: user-service-v2
          uri: http://user-service-v2:3000
          predicates:
            - Path=/api/users/**
            - Header=X-API-Version, v2
          filters:
            - StripPrefix=1
 
      # Default filters applied to all routes
      default-filters:
        - name: RequestSize
          args:
            maxSize: 5MB
        - DedupeResponseHeader=Access-Control-Allow-Origin
 
      # Global CORS
      globalcors:
        corsConfigurations:
          "[/**]":
            allowedOrigins: "https://example.com"
            allowedMethods: "*"
            allowedHeaders: "*"

Custom Filters

@Component
public class JwtAuthFilter implements GatewayFilterFactory<JwtAuthFilter.Config> {
 
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            String token = exchange.getRequest().getHeaders()
                .getFirst(HttpHeaders.AUTHORIZATION);
 
            if (token == null || !token.startsWith("Bearer ")) {
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
 
            try {
                Claims claims = validateToken(token.substring(7));
 
                // Add user info as headers for downstream services
                ServerHttpRequest modifiedRequest = exchange.getRequest()
                    .mutate()
                    .header("X-User-ID", claims.getSubject())
                    .header("X-User-Role", claims.get("role", String.class))
                    .build();
 
                return chain.filter(
                    exchange.mutate().request(modifiedRequest).build()
                );
            } catch (Exception e) {
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
        };
    }
 
    public static class Config {
        // Configuration properties
    }
}

Rate Limiter with Redis

@Configuration
public class RateLimiterConfig {
 
    @Bean
    public KeyResolver apiKeyResolver() {
        return exchange -> {
            String apiKey = exchange.getRequest().getHeaders()
                .getFirst("X-API-Key");
            return Mono.just(apiKey != null ? apiKey : exchange.getRequest()
                .getRemoteAddress().getAddress().getHostAddress());
        };
    }
 
    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> {
            String userId = exchange.getRequest().getHeaders()
                .getFirst("X-User-ID");
            return Mono.just(userId != null ? userId : "anonymous");
        };
    }
}

9. Observability

An API gateway is the perfect place to collect metrics, traces, and logs — it sees every request.

Key Metrics

MetricWhat It Tells You
Request rateHow much traffic you're handling
Error ratePercentage of 4xx and 5xx responses
Latency (p50, p95, p99)How fast responses are
Rate limit hitsHow often clients hit their limits
Circuit breaker tripsWhich services are failing
Request sizeBandwidth consumption patterns
Active connectionsCurrent load on the gateway

Logging Best Practices

Every request through the gateway should log:

{
  "timestamp": "2026-03-11T10:30:00Z",
  "request_id": "req-abc-123",
  "method": "GET",
  "path": "/api/users/123",
  "status": 200,
  "latency_ms": 45,
  "client_ip": "203.0.113.50",
  "api_key": "mobile-app",
  "user_id": "user-456",
  "upstream_service": "user-service",
  "upstream_latency_ms": 38,
  "cache_status": "MISS",
  "rate_limit_remaining": 95
}

This data enables:

  • Debugging: Trace a request through the entire system
  • Analytics: Understand API usage patterns
  • Alerting: Detect anomalies in error rates or latency
  • Billing: Charge API consumers based on usage

10. Security Best Practices

Defense in Depth

Layer 1 — WAF (Web Application Firewall): Block SQL injection, XSS, known attack patterns before they reach the gateway.

Layer 2 — API Gateway: Authenticate, authorize, rate limit, validate request schemas.

Layer 3 — Service Mesh: mTLS between services, network policies, service-level auth.

Layer 4 — Backend Service: Input validation, business logic authorization.

Security Checklist

Always use HTTPS — terminate TLS at the gateway or load balancer
Validate all tokens — don't trust client-provided identity without verification
Rate limit everything — especially auth endpoints
Validate request schemas — reject malformed requests at the gateway
Strip sensitive headers — remove X-Powered-By, Server, internal headers
Log all requests — with correlation IDs for tracing
Use API keys for third-parties — track and control external access
Implement CORS properly — don't use * for allowed origins in production
Set request size limits — prevent oversized payloads
Rotate credentials regularly — API keys, JWT secrets, certificates


11. When to Use (and Not Use) an API Gateway

Use an API Gateway When

  • You have multiple backend services that clients need to access
  • You need centralized authentication across services
  • You need rate limiting per API key (not just per IP)
  • You need request aggregation to reduce client round-trips
  • You have multiple client types (mobile, web, third-party) with different needs
  • You need API versioning without changing backend services
  • You need a developer portal with API documentation and key management

Don't Use an API Gateway When

  • You have a monolithic application — a reverse proxy is sufficient
  • You have only 1-2 services — the overhead isn't worth it
  • Your services are internal only (no external API consumers)
  • You're at an early stage — start simple, add a gateway when you need it
  • You'd be creating a single point of failure without proper HA setup

Choosing the Right Solution

ScenarioRecommendation
Simple reverse proxy needsNginx, Caddy
Docker/Kubernetes microservicesKong, Traefik
AWS serverlessAWS API Gateway
Spring Boot ecosystemSpring Cloud Gateway
Enterprise with complex policiesApigee, MuleSoft
Service mesh + gatewayIstio + Envoy
Budget-consciousKong OSS, Traefik

12. Comparison of API Gateway Solutions

FeatureKongAWS API GatewaySpring Cloud GWTraefikApigee
TypeOpen sourceManagedOpen sourceOpen sourceManaged
LanguageLua/NginxN/AJavaGoN/A
DeploymentSelf-hosted/CloudAWS onlySelf-hostedSelf-hostedGoogle Cloud
AuthPluginsBuilt-inFiltersMiddlewareBuilt-in
Rate limitingPluginBuilt-inFilter + RedisMiddlewareBuilt-in
Plugins100+LimitedCustom filtersMiddlewarePolicies
PerformanceExcellentGoodGoodExcellentGood
KubernetesIngress controllerN/APod deploymentIngress controllerAdapter
Best forGeneral purposeAWS appsSpring appsContainer routingEnterprise

Summary

TopicWhat We Covered
ConceptAPI gateway is the single entry point for all API traffic in a microservices architecture
vs Reverse ProxyAPI gateway adds auth, rate limiting per key, aggregation, and API management on top of reverse proxy
RoutingPath-based, header-based, method-based, and versioned routing
AuthenticationJWT, API keys, OAuth2, mTLS — validate once at the gateway
Rate LimitingPer IP, per key, per user, per endpoint with various algorithms
AggregationCombine responses from multiple services in a single call
Circuit BreakingStop sending requests to failing services, use fallbacks
PatternsSingle gateway, BFF, gateway per domain, service mesh
SolutionsKong (general), AWS API Gateway (serverless), Spring Cloud Gateway (Java)
SecurityDefense in depth — WAF → Gateway → Service Mesh → Backend

Key takeaways:

✅ An API gateway centralizes cross-cutting concerns — auth, rate limiting, logging, routing
✅ Start with a reverse proxy; add an API gateway when you have multiple services and external consumers
✅ The BFF pattern gives each client type its own optimized gateway
✅ Circuit breaking prevents cascading failures across services
✅ Rate limit by API key, not just by IP — this enables fair usage for API consumers
✅ The gateway is the best place for observability — it sees every request
✅ Choose your gateway based on your ecosystem: Kong for general use, AWS for serverless, Spring Cloud for Java


An API gateway isn't just a router — it's where you define how the outside world interacts with your system. Get it right, and your microservices architecture becomes clean, secure, and observable. Get it wrong, and it becomes a bottleneck that every team complains about.

📬 Subscribe to Newsletter

Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.

We respect your privacy. Unsubscribe at any time.

💬 Comments

Sign in to leave a comment

We'll never post without your permission.