API Gateway Patterns and Best Practices for Modern Applications

Implement API gateway patterns including rate limiting, authentication, request routing, circuit breakers, and API versioning for scalable web architectures.

E
ECOSIRE Research and Development Team
|March 16, 20267 min read1.5k Words|

API Gateway Patterns and Best Practices for Modern Applications

API gateways handle an average of 83% of all enterprise traffic, serving as the single entry point for client applications. A well-designed API gateway simplifies client-server communication, enforces security policies, and provides observability across all services. A poorly designed one becomes a bottleneck and single point of failure.

This guide covers API gateway architecture patterns, technology selection, and implementation best practices for web applications, ERP systems, and eCommerce platforms.

Key Takeaways

  • API gateways centralize cross-cutting concerns (auth, rate limiting, logging) to eliminate duplication across services
  • Rate limiting at the gateway level protects backend services from traffic spikes and abuse
  • Circuit breaker patterns prevent cascading failures when downstream services are unhealthy
  • API versioning through the gateway enables backward-compatible evolution of your API surface

Core Gateway Patterns

Pattern 1: Request Routing

The gateway routes requests to the appropriate backend service based on the URL path, headers, or other request attributes.

# Nginx as API gateway
upstream api_service {
    server api-1:3001;
    server api-2:3001;
}

upstream auth_service {
    server auth:9000;
}

upstream web_service {
    server web:3000;
}

server {
    listen 443 ssl;
    server_name api.example.com;

    location /api/v1/ {
        proxy_pass http://api_service;
    }

    location /auth/ {
        proxy_pass http://auth_service;
    }

    location / {
        proxy_pass http://web_service;
    }
}

Pattern 2: Authentication and Authorization

Centralize authentication at the gateway to avoid implementing it in every service.

// NestJS middleware for JWT validation at the gateway level
@Injectable()
export class GatewayAuthMiddleware implements NestMiddleware {
  constructor(private readonly jwtService: JwtService) {}

  async use(req: Request, res: Response, next: NextFunction) {
    // Skip public endpoints
    if (this.isPublicEndpoint(req.path)) {
      return next();
    }

    const token = this.extractToken(req);
    if (!token) {
      throw new UnauthorizedException('Missing authentication token');
    }

    try {
      const payload = await this.jwtService.verifyAsync(token);
      req['user'] = payload;
      next();
    } catch {
      throw new UnauthorizedException('Invalid token');
    }
  }

  private extractToken(req: Request): string | undefined {
    // Check cookie first, then Authorization header
    return req.cookies?.ecosire_auth
      || req.headers.authorization?.replace('Bearer ', '');
  }

  private isPublicEndpoint(path: string): boolean {
    const publicPaths = ['/health', '/api/v1/products', '/api/v1/blog'];
    return publicPaths.some(p => path.startsWith(p));
  }
}

Pattern 3: Rate Limiting

// Rate limiting configuration per endpoint type
const rateLimits = {
  public: { windowMs: 60000, max: 100 },     // 100 req/min for public APIs
  authenticated: { windowMs: 60000, max: 500 }, // 500 req/min for authenticated users
  admin: { windowMs: 60000, max: 1000 },       // 1000 req/min for admin
  webhooks: { windowMs: 60000, max: 50 },       // 50 req/min for webhooks
};

Pattern 4: Circuit Breaker

When a downstream service fails, the circuit breaker prevents cascading failures:

[Closed] --> (failures exceed threshold) --> [Open] --> (timeout expires) --> [Half-Open]
    ^                                                                            |
    |                                        (success)                           |
    +--------------------------------------------------------------------<-------+
    |                                        (failure)                           |
    |                                           +-------->  [Open]

States:

  • Closed: Requests pass through normally. Track failure count.
  • Open: All requests fail immediately without calling the service. Return cached/fallback response.
  • Half-Open: Allow one request through. If it succeeds, close the circuit. If it fails, reopen.

Pattern 5: Response Caching

# Cache GET responses for public endpoints
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m;

location /api/v1/products {
    proxy_pass http://api_service;
    proxy_cache api_cache;
    proxy_cache_valid 200 5m;
    proxy_cache_valid 404 1m;
    proxy_cache_key "$scheme$request_method$host$request_uri";
    add_header X-Cache-Status $upstream_cache_status;
}

API Versioning Strategies

StrategyURL ExampleProsCons
URL path/api/v2/productsClear, easy to routeURL pollution
Query param/api/products?version=2No URL changeEasy to miss
HeaderAccept: application/vnd.api.v2+jsonClean URLsLess discoverable
Content negotiationAccept: application/json; version=2Standards-basedComplex

Recommendation: URL path versioning. It is the most explicit, most debuggable, and easiest to route at the gateway level.

Breaking vs Non-Breaking Changes

Change TypeBreaking?Action
Add new field to responseNoAdd to current version
Add new optional query parameterNoAdd to current version
Remove field from responseYesNew version required
Change field typeYesNew version required
Change URL pathYesNew version required
Add required parameterYesNew version required

Gateway Technology Comparison

TechnologyTypeBest ForLatency Overhead
NginxReverse proxySimple routing, SSL, caching<1ms
KongFull gatewayPlugin ecosystem, rate limiting1-3ms
AWS API GatewayManagedAWS-native, serverless5-10ms
EnvoyService meshKubernetes, gRPC<1ms
TraefikDynamic proxyDocker, auto-discovery1-2ms

For most SMBs: Nginx is sufficient. It handles routing, SSL termination, rate limiting, and caching with sub-millisecond overhead. Upgrade to Kong when you need advanced plugin capabilities (OAuth2, request transformation, analytics).


Observability at the Gateway

Request Logging

log_format gateway '$remote_addr - $remote_user [$time_local] '
                   '"$request" $status $body_bytes_sent '
                   '"$http_referer" "$http_user_agent" '
                   '$request_time $upstream_response_time '
                   '$http_x_request_id';

access_log /var/log/nginx/gateway.log gateway;

Metrics Collection

Track these metrics at the gateway level:

  • Request rate by endpoint, method, and status code
  • Latency distribution (P50, P95, P99) by endpoint
  • Error rate by endpoint and error type
  • Rate limit hits by client
  • Cache hit ratio by endpoint
  • Upstream response time vs total response time

Error Handling at the Gateway

Consistent Error Responses

The gateway should normalize error responses from different backend services:

{
  "error": {
    "code": "SERVICE_UNAVAILABLE",
    "message": "The requested service is temporarily unavailable",
    "requestId": "req_abc123",
    "timestamp": "2026-03-16T14:32:01Z"
  }
}

Retry and Timeout Configuration

location /api/ {
    proxy_pass http://api_service;

    # Timeout configuration
    proxy_connect_timeout 5s;
    proxy_send_timeout 30s;
    proxy_read_timeout 30s;

    # Retry on connection errors only (not on 5xx)
    proxy_next_upstream error timeout;
    proxy_next_upstream_tries 2;

    # Custom error pages
    error_page 502 503 504 /api-error.json;
}

Graceful Degradation

When a non-critical backend service is down, the gateway can serve cached responses or fallback data instead of returning errors:

Service StateGateway Behavior
HealthyProxy to backend normally
Slow (latency >2s)Return cached response if available, proxy otherwise
Down (5xx errors)Return cached response with X-Cache-Stale header
Down + no cacheReturn fallback response with 503 status

Gateway Security Patterns

Request Validation

Validate request structure before forwarding to backend services:

  • Reject requests with unknown content types
  • Enforce maximum request body size per endpoint
  • Validate required headers (API version, content type)
  • Strip suspicious headers (hop-by-hop headers, server-internal headers)

IP Allowlisting for Admin Endpoints

location /api/admin/ {
    allow 203.0.113.0/24;  # Office IP range
    allow 10.0.0.0/8;      # Internal network
    deny all;

    proxy_pass http://api_service;
}

Request Transformation

The gateway can add, modify, or remove headers before forwarding:

location /api/ {
    proxy_pass http://api_service;

    # Add security headers
    proxy_set_header X-Request-ID $request_id;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;

    # Remove internal headers from responses
    proxy_hide_header X-Powered-By;
    proxy_hide_header Server;
}

Frequently Asked Questions

Do we need an API gateway for a monolithic application?

Yes, but a simpler one. Even for a monolith, Nginx as a reverse proxy provides SSL termination, rate limiting, static file serving, and security headers. You do not need Kong or AWS API Gateway for a monolith, but you do need something between the internet and your application server.

How do we handle API gateway failover?

Run multiple gateway instances behind a cloud load balancer (AWS ALB, Cloudflare). If one gateway instance fails, the load balancer routes traffic to healthy instances. For Nginx, use active health checks and automatic removal of unhealthy upstreams.

Should the API gateway handle authentication or should each service?

The gateway should handle authentication (verifying the token is valid). Individual services should handle authorization (checking whether the authenticated user has permission for the specific action). This separation keeps the gateway lightweight and allows services to make fine-grained access control decisions.

How do we handle CORS at the API gateway?

Configure CORS at the gateway level to avoid duplicating CORS headers across services. Set Access-Control-Allow-Origin to your specific frontend domains (never use * in production with credentials). Handle preflight OPTIONS requests at the gateway to reduce load on backend services.


What Comes Next

An API gateway is the front door to your infrastructure. Pair it with monitoring for visibility, security hardening for protection, and load testing for capacity planning.

Contact ECOSIRE for API architecture consulting, or explore our DevOps guide for the complete infrastructure roadmap.


Published by ECOSIRE -- helping businesses build scalable API infrastructure.

E

Written by

ECOSIRE Research and Development Team

Building enterprise-grade digital products at ECOSIRE. Sharing insights on Odoo integrations, e-commerce automation, and AI-powered business solutions.

Chat on WhatsApp