API Gateway Patterns: Securing REST APIs Centrally Instead of Per Service
AI generated
{ }
GET
API Gateway · Microservices
API Gateway Patterns
Securing REST APIs centrally instead of rebuilding auth and rate limiting in every service

Once several microservices each offer their own REST API, the same cross-cutting logic repeats everywhere: checking authentication, enforcing rate limits, logging requests. An API gateway pulls that logic into one central place, with clear benefits but also new questions about resilience and latency.

15 min read API Gateway · BFF Rate Limiting · Routing

1. The problem an API gateway solves

In a microservice architecture with several independent REST APIs, the same pattern quickly appears multiple times: every service independently checks an auth token, enforces its own rate limits, logs requests in its own format. Implementing that logic separately in every service leads not only to code duplication but to inconsistencies whenever one team implements a detail differently from another.

An API gateway sits as a central layer in front of all backend services and takes over these cross-cutting tasks in one place. Clients only ever talk to the gateway, which validates, enriches, and forwards requests to the responsible backend service. The benefit lies in consistency and in the ability to change security or observability requirements in a single place instead of adjusting every service individually.

2. Routing pattern: one entry point for many services

The most basic gateway pattern is pure routing: the client only knows one public domain, and the gateway forwards based on the URL path to the responsible backend service. /api/orders/* goes to the order service, /api/customers/* to the customer service, without the client needing to know how many services actually sit behind it or how they are reachable internally.

This pattern decouples the external API structure from the internal service split: a team can split a service internally into two smaller services without anything changing for API consumers, as long as the routing rules in the gateway are adjusted accordingly. That makes internal refactorings noticeably less risky for external integrators.


# traefik-gateway.yaml — routing rules by path prefix
http:
  routers:
    orders-router:
      rule: "PathPrefix(`/api/orders`)"
      service: order-service
      middlewares:
        - rate-limit
        - jwt-auth

    customers-router:
      rule: "PathPrefix(`/api/customers`)"
      service: customer-service
      middlewares:
        - rate-limit
        - jwt-auth

  services:
    order-service:
      loadBalancer:
        servers:
          - url: "http://order-service:8080"
    customer-service:
      loadBalancer:
        servers:
          - url: "http://customer-service:8080"

3. Authentication in one place instead of in every service

Instead of every backend service validating a JWT itself, the gateway takes over this task centrally: it checks the token's signature, expiry, and scopes, and only forwards the request to the backend on successful validation, often with enriched headers like X-User-Id for the backend service. The backend service itself no longer needs to implement its own auth handling, and trusts that only already-verified requests reach it.

This trust assumes that backend services are not directly reachable from outside, but only through the gateway, typically secured through network segmentation or an internal service mesh. Without that safeguard, the centralized auth check in the gateway would be worthless, since an attacker could address the backend service directly, bypassing the gateway check entirely.

4. Rate limiting centrally instead of configured per service

Rate limiting in the gateway makes it possible to enforce limits consistently across all services, for example per API key or per authenticated user, regardless of which backend service a request ultimately reaches. That prevents a client from cleverly distributing requests across multiple services to bypass a single service's rate limits.

Common gateway implementations like Kong, Traefik, or Envoy offer built-in rate limiting modules with different algorithms (token bucket, sliding window) that can be activated through configuration rather than code. For a team, that means being able to change rate limiting rules without redeploying a single backend service.

5. Backend for Frontend: one gateway per client type

An evolution of the simple gateway pattern is Backend for Frontend (BFF): instead of a single gateway for all client types, a dedicated, specialized gateway is run for each client type (web, iOS, Android) that tailors the backend services exactly to that client's needs, for example with aggregated responses or client-specific field trimming.

The benefit is that a mobile client, needing minimal payloads for bandwidth reasons, can get a different response format than a web app, without the underlying backend services themselves having to offer multiple response variants. The downside is additional operational and maintenance overhead for running multiple gateway instances instead of a single one.

6. Request aggregation: bundling multiple backend calls into one response

Another common gateway pattern is aggregating several backend calls into a single client response. Instead of a client sending three separate requests to product, pricing, and inventory services for a product detail page, the gateway calls all three internally and combines the results into one response, reducing the number of client-server round trips.

This aggregation must be carefully combined with error handling: if one of three aggregated backend calls fails, the gateway has to decide whether to return the entire response as an error or deliver a partial response with a flagged missing field. That decision should be explicitly documented, so client developers are not surprised by unexpected behavior.


<?php
// Symfony: aggregation endpoint in the BFF gateway
#[Route('/bff/product/{sku}', methods: ['GET'])]
public function productDetail(string $sku): JsonResponse
{
    $product = $this->productClient->get($sku);
    $price = $this->pricingClient->getPrice($sku);
    $stock = $this->inventoryClient->getStock($sku);

    // A partial failure is explicitly flagged instead of failing the whole request
    return $this->json([
        'product' => $product,
        'price' => $price ?? ['available' => false],
        'inStock' => $stock->quantity > 0,
        'degraded' => $price === null,
    ]);
}

7. The single point of failure: gateway resilience

A central gateway inevitably becomes a critical part of the entire infrastructure: if it goes down, the whole API becomes unreachable, even if every backend service is running fine. That requires running the gateway itself with high availability, usually with several redundant instances behind a load balancer.

Equally important is that the gateway itself does not contain complex business logic, and stays limited to pure cross-cutting tasks (routing, auth, rate limiting). A gateway that additionally takes on domain logic becomes a monolith itself, with the same scaling and deployment problems the microservice architecture was supposed to avoid in the first place.

8. The extra network hop and its latency cost

With a gateway, every request passes through an extra network hop compared to talking directly to the backend service. In most cases this extra latency (typically a few milliseconds with a performant gateway) is negligible compared to the latency of the actual backend processing, especially with database access.

For latency-critical internal calls between services (not client-to-gateway, but service-to-service), the gateway is usually deliberately bypassed, and services talk directly to each other or through a lightweight service mesh. The gateway pattern applies primarily to the external entry point into the system, not necessarily to every internal communication.

9. Common gateway implementations compared

The choice of concrete gateway software depends on team experience, existing infrastructure, and required features. The table below compares common options.

Gateway Configuration style Distinguishing feature Typical use
Kong Declarative + plugins Large plugin ecosystem Feature-rich enterprise gateway
Traefik Labels/YAML, Docker-native Automatic service discovery Docker/Kubernetes-native setups
Envoy YAML, very granular High performance, service mesh foundation Large, complex infrastructures
Symfony/Nginx as gateway Code + Nginx config Full control, more custom build Smaller setups without a dedicated tool

Mironsoft

OpenAPI design, Symfony APIs, and API security

APIs that external teams can integrate without back-and-forth questions?

We review existing REST APIs for inconsistent error formats, missing OpenAPI documentation, and security gaps, then build an API that is clearly documented, versioned, and hardened against abuse.

API Review

Checking the OpenAPI spec, error formats, and status codes for consistency.

Symfony Implementation

Using DTOs, Serializer, and Validator for clean, type-safe request/response models.

Security Audit

Hardening rate limiting, auth schemes, and input validation against real attack surfaces.

10. Summary

API Gateway Patterns: The Essentials at a Glance

Core idea

Implement auth, rate limiting, and routing centrally in the gateway instead of duplicated across every backend service.

BFF pattern

For strongly different client types (web, mobile), a specialized gateway per client is worth it instead of one universal gateway.

Risk

The gateway becomes a single point of failure and must itself stay highly available and free of business logic.

Latency

The extra hop is usually negligible, for latency-critical internal calls the gateway is often deliberately bypassed.

11. FAQ: API Gateway Patterns: The Essentials at a Glance

1Does every microservice system need an API gateway?
No, with few services and manageable complexity, direct client-to-service communication can be enough. Past a certain number of services and cross-cutting requirements, a gateway becomes noticeably more maintainable though.
2What is the difference between an API gateway and a load balancer?
A load balancer only distributes requests across multiple instances of the same service. An API gateway additionally routes between different services and takes on auth, rate limiting, and other cross-cutting tasks.
3How do I ensure backend services are not reachable bypassing the gateway?
Through network segmentation (backend services only reachable on the internal network) or a service mesh with mTLS that only allows authorized internal connections.
4What happens if the gateway goes down?
Without redundant gateway instances, the entire API becomes unreachable. That is why the gateway itself must run with high availability, usually with multiple instances behind a load balancer.
5Is a backend-for-frontend pattern worth it for every project?
Only if client types genuinely have different data needs. With a single web app, an additional BFF gateway is usually unnecessary overhead.
6Should business logic live in the gateway?
No, the gateway should stay limited to cross-cutting tasks like routing, auth, and rate limiting. Domain logic in the gateway turns it into a hard-to-maintain monolith itself.
7How much extra latency does a gateway cause?
With a performant gateway, typically a few milliseconds, usually negligible compared to backend processing time, especially with database access.
8Can a gateway also be used for internal service-to-service communication?
Technically yes, but for latency-critical internal calls it is usually deliberately bypassed in favor of direct communication or a lightweight service mesh.
9Which gateway software fits a Docker/Kubernetes setup?
Traefik offers automatic service discovery and is especially popular in Docker/Kubernetes-native environments because it can derive routing rules directly from container labels.
10How do I test rate limiting rules in the gateway without affecting production traffic?
In a separate staging environment with synthetic load generation, or by gradually rolling out the rules to only a small percentage of production traffic.