Home › High-Level Design › API Gateway
A

API Gateway

If your design has more than three services, an interviewer expects you to know why a gateway sits in front of them. I have watched good candidates draw ten microservices and then quietly wire each one straight to the browser. That is the moment I start asking questions, because it tells me they have never shipped a real system. The rest of this page is what a gateway actually buys you, what it costs, and the numbers that make the trade-offs stop being abstract.

High-Level DesignIntermediate11 min read

If you remember five things

The whole concept in one glance. Everything below defends these five calls.

  1. One front door. The gateway owns everything true for every request (auth, rate limiting, TLS, logging, routing), so no service reinvents it and the stack cannot drift.
  2. Not a load balancer. A load balancer picks a healthy box and forwards bytes. A gateway reads the request, understands users and routes, and can reshape the payload. It sits in front of the load balancer, not instead of it.
  3. Verify auth locally. Check the JWT signature at the gateway with a cached public key instead of a per-request network hop. That one call turns 1 to 2 ms of auth tax into 0.1 ms.
  4. Shared state goes external. Per-instance rate-limit counters let a client do N times its budget. Push counters to Redis with atomic increments, cache the decision, and fail open on a Redis outage.
  5. Keep it dumb about your domain. Routing, auth, limits, shaping. No business logic. The moment product rules leak in, a feature change needs a gateway deploy.

1The core idea#

A gateway is a single front door for a set of backend services. Clients talk to one endpoint, say api.yourcompany.com, and the gateway decides where each request goes.

The mental model: it is the front desk of a large office building.

  • Visitors do not wander the hallways hunting for the right room. They check in at one desk, show ID, and get sent to floor 7.
  • The desk logs who came in and turns away people who should not be there.
  • The gateway plays that exact role for your API traffic.

It owns the cross-cutting concerns, the things true for every request.

  • Authentication, rate limiting, TLS termination, request logging, routing.
  • Without a gateway you copy that logic into every service, and six months later three of them handle auth slightly differently and you have a hole.
  • I have debugged exactly that: two services accepted an expired token because each team wrote its own 15-line JWT check and one forgot the exp claim.
The distinction interviewers want to hear

A gateway is not a load balancer. A load balancer picks a healthy instance of one service and forwards bytes, mostly blind to what is inside. A gateway reads the request, understands routes and users, and can transform the payload. Gateways usually sit in front of load balancers, not in place of them. Saying this out loud early earns trust, because a surprising number of candidates blur the two.

2How it works#

A request hits the gateway and runs a chain of steps before it reaches any service. The order is deliberate: reject bad traffic as cheaply as possible, so auth and rate limiting come before the expensive routing and transformation.

Why the order matters.

  • Rejecting at step 2 costs you a signature check.
  • Rejecting at step 5 means you already paid for routing and a downstream connection.

A typical path through the gateway:

  1. TLS termination. Decrypt HTTPS once. Internal hops run plain HTTP or lighter mutual TLS, so each service skips the handshake cost.
  2. Authentication and authorization. Validate the token or API key. A common pattern: verify a JWT signature, then pass the decoded user ID downstream in a header so services trust the gateway instead of re-checking.
  3. Rate limiting and quotas. Drop the request if this client has blown past its budget. Usually a 429 with a Retry-After.
  4. Routing. Match path or host to a backend. GET products goes to catalog, POST orders goes to the order service.
  5. Request and response transformation. Rewrite headers, strip internal fields, maybe collapse several backend calls into one response.
  6. Forward to the backend (through a load balancer), then shape the response on the way out.
flowchart LR A[Client] --> B[API Gateway] B --> C[Auth check] B --> D[Rate limit] B --> E[Load Balancer] E --> F[Catalog Service] E --> G[Order Service] F --> H[(Product DB)] F --> I[(Cache)] G --> J[(Order DB)]
Notice the gateway is the only box clients touch. Auth and rate limiting hang off it as cheap early gates, and the load balancer lives behind the gateway, fanning validated traffic out to services that are never exposed directly.

The full lifecycle of one request is the version I sketch when someone says "show me the flow":

sequenceDiagram participant C as Client participant G as Gateway participant A as Auth Service participant S as Order Service C->>G: POST order with token G->>A: Validate token A-->>G: User id and scopes G->>G: Check rate limit G->>S: Forward with user header S-->>G: 201 Created G-->>C: 201 Created
The auth check here talks to a separate service, one network hop per request. Watch that hop: in high-traffic systems you cache the result, or verify the JWT locally with a cached public key so there is no call at all. That single choice dominates your p99.
From the interviewer's chair

I am listening for whether you treat the gateway as a real service with its own latency budget. Draw the six steps in any order and I notice. Put auth and rate limiting before routing on purpose, and explain that you reject junk before paying for the expensive work, and I know you have stared at a gateway's CPU graph.

3A worked example: sizing the gateway tier#

Make it concrete. Say we front a shopping API.

The numbers to anchor on:

  • 50,000 requests per second at peak, Black Friday style.
  • Request plus response averages about 4 KB, so roughly 200 MB/s through the gateway.
  • Each gateway box is 4 vCPU and comfortably handles 8,000 req/s with TLS termination and routing before CPU crosses 70 percent.

Sizing for load, then for failure:

  • Raw math: 50,000 / 8,000 = 6.25, round up to 7 instances to carry the load.
  • But 7 is the number where losing one box pushes the rest over the line.
  • Spread across 3 availability zones to survive one going dark: lose a zone with 3 per zone (9 total) and the surviving 6 cover 48,000 req/s, uncomfortably close.
  • I would rather run 4 per zone, 12 total, and sleep. The extra boxes cost maybe 150 dollars a month each. Cheap insurance against a 2am page.
0.1 ms
The number that moves latencyLocal JWT verify is pure CPU at ~0.1 ms. A per-request auth hop is 1 to 2 ms at p50 and spikes past 20 ms at p99 when the auth service is busy. Across a page that makes 8 calls, that is 8 ms of auth tax versus 160 ms. This is the trade-off worth saying out loud.

The auth decision is the one that actually moves latency. Two options:

  • Call the auth service per request. An extra network hop. Even at 1 ms in-zone, at 50,000 req/s the auth service must also do 50,000 validations per second, and its p99 now rides on top of yours. One slow GC pause there and every request in the system stalls.
  • Verify the JWT locally at the gateway using the auth service's public key, cached and refreshed every few minutes. Signature verification is pure CPU, roughly 0.1 ms, no network call. At 50,000 req/s that is maybe 5 percent of a core per instance, and it removes an entire failure dependency from the hot path.
Pause before you read on: each of your 12 gateway instances keeps its own rate-limit counter in local memory. A client is allowed 1,000 req/s. How much can it actually send?
Reveal the answer
Up to 12,000 req/s. Each instance only sees the slice of traffic the load balancer sent it, so each independently lets 1,000 through. The limit is effectively multiplied by your instance count. Fix: shared counters in Redis with atomic INCR plus EXPIRE. Reaching for this unprompted signals you have actually run a gateway tier, not just drawn one.

Rate limiting has the matching gotcha, and the fix has a cost.

  • Shared counters go in Redis with atomic INCR plus EXPIRE. At 50,000 req/s that load is well within one node's reach.
  • But Redis is now a dependency on the hot path. Cache the decision for a short window and fail open on a Redis outage rather than blocking all traffic.

What a strong answer sounds like. Not "add a gateway," but "9 to 12 instances across 3 zones, local JWT verify at 0.1 ms, Redis-backed limits with fail-open." Numbers signal you have run one.

4Trade-offs#

The honest pitch and the honest cost.

  • Pitch: the gateway centralizes the annoying stuff and gives you one place to enforce policy.
  • Cost: you just added a hop that every single request passes through. If it is slow, everything is slow. If it is down, everything is down.
  • So treat it like critical infrastructure: several instances behind a load balancer, stateless so any instance serves any request, and disciplined about what logic lives there.
Red flag that fails you here

Putting business logic in the gateway. The moment someone adds "if the order total is over 500 dollars, route to fraud check," you have leaked domain knowledge into shared infrastructure, and now a product change needs a gateway deploy. I have watched a gateway turn into a distributed monolith exactly this way. The gateway does routing, auth, rate limiting, and shaping. Keep it dumb about your business on purpose.

A few decisions you will actually face:

Decision Option A Option B What you give up When I pick which
Build vs buy Managed (AWS API Gateway, Kong, Apigee) Self-hosted or custom (Envoy, nginx) Managed is fast to start but costs per request and limits control Managed under maybe 10k req/s or small team. At 50k req/s the per-request bill and cold tuning push me to self-hosted Envoy
One gateway vs many Single shared gateway Backend for Frontend, one per client type A shared gateway is simpler but becomes a bottleneck team Shared until mobile and web needs clearly diverge, then split into BFFs
Auth location Validate at the gateway Validate inside each service Gateway auth is DRY but services then blindly trust a header Gateway with local JWT verify, plus network policy so services are not directly reachable
Aggregation Gateway composes multiple calls Client makes multiple calls Aggregation cuts round trips for mobile but makes the gateway stateful-ish and harder to reason about Aggregate only when the round-trip win is real, like a mobile home screen

On that last row, aggregation, the math is real but so is the cost.

  • A mobile app on a 150 ms round trip does not want 8 calls to render one screen. Serially that is 1.2 seconds of pure network time.
  • A gateway or BFF fans out to 8 services in parallel inside the data center and returns one payload in roughly 150 ms plus the slowest downstream. Genuine win.
  • But now the gateway handles partial failures, per-downstream timeouts, and merging. More code in a place where bugs hurt everyone. Reach for it when the latency win is real, not by default.

5Where it is used#

Pretty much every large API-driven company runs a gateway, even if they do not call it that.

  • Netflix popularized the BFF pattern. TV, phone, and browser have different needs, so they front them with device-specific edge layers instead of one gateway serving everyone.
  • Public API products like Stripe or Twilio put a gateway in front to enforce API keys, per-key rate limits, and usage metering for billing. The gateway is literally how they count what to charge you, so every request through it is also a billing event.
  • Kubernetes shops often run Envoy or an Ingress controller as the gateway. Service mesh setups (Istio, Linkerd) push some concerns down to sidecars, but you still want an edge gateway for north-south traffic coming in from outside the cluster.

When I reach for one in a design:

  • The moment external clients need to reach multiple services and I want consistent auth, rate limiting, and a stable public contract.
  • A client hits api.site.com/v2/orders and never learns there are four services behind it, so I can refactor freely. That decoupling is worth a lot.

When I skip it:

  • A single monolith with one public endpoint does not need one yet.
  • Do not add infrastructure to solve a problem you do not have.

6Common pitfalls and gotchas#

Making it a single point of failure.

  • One instance, no redundancy. Run at least two, behind a load balancer, across zones.
  • As the worked example showed, I would rather run 12 than the bare minimum 7. Table stakes.

Stuffing business logic in.

  • Covered above, and it is the most common failure I see. The gateway is plumbing.
  • Keep decisions about what your product does inside your services.

Auth that trusts a header with no backstop.

  • If the gateway strips and re-sets an X-User-Id header, make sure clients cannot spoof it and services cannot be reached directly from outside.
  • Network policy should force all external traffic through the gateway.
  • Otherwise someone curls your order service directly with a forged X-User-Id: 1 and acts as any user.

Timeout and retry storms.

  • The gateway retries a slow service, which is already overloaded, which makes it slower, which triggers more retries.
  • Use timeouts, circuit breakers, and capped retries with backoff. A gateway without a breaker turns a slow service into a dead one.
  • Concretely: a 200 ms timeout, at most one retry, and a breaker that trips after say 50 percent errors in a 10-second window.

Per-instance rate limit counters.

  • If limits live in local memory, a client allowed 1,000 req/s can do 1,000 times your instance count.
  • Push counters to Redis, as the example walked through.

No per-route limits.

  • One expensive endpoint (a big search query) gets the same treatment as a cheap health check.
  • Set limits and timeouts per route, not globally. Search might get a 2-second timeout and 100 req/s, health checks get 50 ms and no real limit.

Versioning pain.

  • Because the gateway is your public contract, a breaking change here breaks every client at once.
  • Plan for /v1 and /v2 coexisting and a real deprecation path.

7How it shows up in interviews#

Interviewers probe the gateway to check whether you understand operational reality, not just boxes and arrows.

Follow-ups the interviewer will ask (and your answers)
"Why not let clients call services directly?"
Name the concrete things you would otherwise duplicate: auth, rate limiting, TLS, logging. Plus, exposing internal services leaks your topology and blocks refactoring. The strongest answer adds the war story: two services drifting on JWT validation until one accepted expired tokens. "It is cleaner" is the weak answer.
"Your gateway is a single point of failure. Fix it."
Keep it stateless, run N instances behind a load balancer across zones, health-check them, and make sure no per-instance state like rate-limit counters lives only in local memory (push those to Redis). Put a number on N: at 50k req/s and 8k per box that is 7 to carry load, so 12 across 3 zones to survive a zone loss.
"Where do you do auth?"
At the gateway for the common case, with local JWT verification to skip a per-request network hop, and services still not directly reachable from outside so the trust boundary holds. Quantify it: local verify is about 0.1 ms, a per-request auth hop is 1 to 2 ms at p50 and spikes under load.
"How do you handle a slow downstream service?"
This separates juniors from people who have been paged at 3am. "Retry it" is the exact move that causes a retry storm. Strong: per-route timeouts, circuit breakers, bounded retries (one retry, backoff), and returning a degraded response rather than hanging, for example a cached or empty recommendations block so the page still renders.
"Is a gateway just a load balancer with extra steps?"
No. A load balancer picks a healthy instance of one service and forwards bytes, blind to the payload. A gateway reads the request, understands routes and users, and can transform it. It sits in front of load balancers, not instead of them. Clearing this up early earns trust because many candidates blur the two.

Treat the gateway as a real service with its own scaling and failure modes, not a magic box labeled "gateway."

What you can now explain in the room

  • Why a gateway owns cross-cutting concerns, and why duplicating them across services causes drift and holes.
  • How a gateway differs from a load balancer, and why one sits in front of the other.
  • How to size the tier: 7 instances to carry 50k req/s, 12 across 3 zones to survive a zone loss.
  • Why local JWT verify at 0.1 ms beats a per-request auth hop, and what it removes from the hot path.
  • Why per-instance rate limits multiply by instance count, and how Redis with fail-open fixes it.
  • How to survive a slow downstream with timeouts, circuit breakers, and bounded retries instead of a retry storm.

Next, try the System Design Question walkthrough on designing a URL shortener, where the gateway, rate limiting, and caching decisions all show up together in one problem.

Get a prep plan built around your API Gateway interview

Tell us the role and your interview date. We will send back a dated, day by day plan. Free.

Thanks. Check your inbox, your API Gateway prep plan is on the way.