Skip to content

API Gateway Pattern — Architecture, Benefits & Implementation Guide

DodaTech Updated 2026-06-24 4 min read

In this tutorial, you'll learn about API Gateway Patternway" >}} Pattern. We cover key concepts, practical examples, and best practices.

The API gateway pattern provides a single entry point for client requests that routes to appropriate microservices, handles cross-cutting concerns like authentication and rate limiting, and aggregates responses — essential for managing distributed system complexity.

Why API Gateway Pattern Matters

Without an API gateway, every client must know the location of every microservice, handle authentication individually, and implement its own retry logic. As the number of services grows — Netflix runs hundreds — this becomes unmanageable. An API gateway centralizes these concerns. Cloudflare processes over 55 million HTTP requests per second through their gateway layer. Doda Browser's sync infrastructure uses an API gateway to route requests to its bookmark, history, and tab-sync microservices, handling authentication at a single point.

Plain-Language Explanation

Think of an API gateway like a hotel concierge. You don't need to know which floor housekeeping is on, where the kitchen is, or how to call maintenance. You tell the concierge what you need, and they route your request to the right department. If a department is busy, the concierge handles retries. If you're not a guest, the concierge turns you away at the door — that's authentication.

graph TD
    Client[Mobile / Web Client] --> GW[API Gateway]
    GW --> Auth[Auth Service]
    GW --> Users[User Service]
    GW --> Orders[Order Service]
    GW --> Inventory[Inventory Service]
    GW --> Payments[Payment Service]
    Auth --> GW
    GW --> RateLimiter[Rate Limiter]
    GW --> Aggregator[Response Aggregator]
    style GW fill:#e67e22,color:#fff
    style Auth fill:#e74c3c,color:#fff
    style RateLimiter fill:#f39c12,color:#fff

Kong Gateway Configuration

Kong is a popular open-source API gateway. Here is a declarative configuration:

_format_version: "3.0"
services:
  - name: user-service
    url: http://user-service:8001
    routes:
      - name: user-route
        paths:
          - /api/v1/users
        methods: [GET, POST, PUT, DELETE]
    plugins:
      - name: rate-limiting
        config:
          minute: 100
          hour: 1000
      - name: key-auth
  - name: order-service
    url: http://order-service:8002
    routes:
      - name: order-route
        paths:
          - /api/v1/orders
    plugins:
      - name: rate-limiting
        config:
          minute: 50
          hour: 500

FastAPI Gateway Implementation

A lightweight gateway using Python:

from fastapi import FastAPI, Request, HTTPException
import httpx

app = FastAPI()
SERVICES = {
    "users": "http://user-service:8001",
    "orders": "http://order-service:8002",
    "payments": "http://payment-service:8003",
}

@app.api_route("/api/v1/{service}/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def gateway(service: str, path: str, request: Request):
    if service not in SERVICES:
        raise HTTPException(404, "Service not found")
    async with httpx.AsyncClient() as client:
        resp = await client.request(
            method=request.method,
            url=f"{SERVICES[service]}/{path}",
            headers=dict(request.headers),
            params=dict(request.query_params),
            content=await request.body(),
        )
        return resp.json(), resp.status_code

Response Aggregation

A gateway often combines results from multiple services:

@app.get("/api/v1/dashboard/{user_id}")
async def dashboard(user_id: str):
    async with httpx.AsyncClient() as client:
        user = await client.get(f"{SERVICES['users']}/{user_id}")
        orders = await client.get(f"{SERVICES['orders']}?user_id={user_id}")
        return {
            "user": user.json(),
            "orders": orders.json(),
            "order_count": len(orders.json()),
        }

Common Mistakes

  1. Gateway as a monolith: Putting business logic in the gateway recreates the monolith. The gateway should route and transform, not implement domain logic.

  2. Single point of failure: A gateway without high availability takes down the entire system. Deploy multiple instances behind a load balancer.

  3. Chatty aggregation: Aggregating dozens of service calls per request increases latency. Use async parallel calls and cache responses.

  4. Ignoring gateway latency: Each request passes through an extra hop. Keep gateway processing under 2ms with efficient routing.

  5. Tight coupling: Clients depending on gateway-specific response formats break when the gateway changes. Keep response formats standard and versioned.

Practice Questions

  1. What problems does the API gateway pattern solve? Centralized authentication, rate limiting, routing, response aggregation, and protocol translation. Clients talk to one endpoint instead of many services.

  2. How does an API gateway differ from a load balancer? A load balancer distributes traffic across instances of the same service. A gateway routes to different services and handles cross-cutting concerns.

  3. When should you avoid an API gateway? For small systems with 2-3 services, the added latency and operational complexity of a gateway outweigh the benefits. Use direct service-to-service calls instead.

  4. What is BFF (Backend for Frontend)? A variant where each client type (mobile, web, IoT) has its own gateway optimized for its specific needs, avoiding over-fetching or under-fetching data.

  5. How do you handle gateway failures? Deploy multiple gateway instances, use health checks, implement circuit breakers for downstream services, and cache popular responses.

Mini Project

Build a simple API gateway that routes to two mock services:

from fastapi import FastAPI
import httpx, asyncio

app = FastAPI()
services = {
    "weather": "https://api.weather.gov",
    "news": "https://newsapi.org/v2",
}

@app.api_route("/gateway/{service}/{path:path}")
async def proxy(service: str, path: str):
    base = services.get(service)
    if not base:
        return {"error": "unknown service"}, 404
    async with httpx.AsyncClient() as c:
        r = await c.get(f"{base}/{path}")
        return r.json()

@app.get("/gateway/aggregate")
async def aggregate():
    async with httpx.AsyncClient() as c:
        w, n = await asyncio.gather(
            c.get(f"{services['weather']}/points/39.7456,-97.0892"),
            c.get(f"{services['news']}/top-headlines?country=us"),
            return_exceptions=True,
        )
    return {
        "weather": w.json() if not isinstance(w, Exception) else "unavailable",
        "news": n.json() if not isinstance(n, Exception) else "unavailable",
    }

Cross-References

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro