An API gateway is the single front door to a microservices system. Rather than letting web and mobile clients call a dozen services directly, you put one component in front of them all. Every request arrives at the gateway, which figures out where it should go and forwards it.
That one address hides a lot of messy reality. Behind it, services get added, split, renamed, and scaled, and the clients never notice. This indirection is the main reason gateways exist: they decouple the outside world from the shape of your internal architecture.
The problem the gateway solves
Picture an app with services for accounts, catalog, orders, and payments. Without a gateway, the mobile app needs the address of each one, has to implement authentication against each, and breaks the moment you split the orders service into two. Every client re-implements the same login, retry, and header logic.
A gateway pulls all of that into one place. Clients call https://api.example.com/... and
the gateway routes by path: /accounts/** goes to the account service, /orders/** to the
order service. Cross-cutting concerns — who are you, how many requests per minute, is your
token valid — get handled once, at the door.
What a gateway typically handles
A well-scoped gateway takes on a specific, bounded set of jobs:
- Routing — map an incoming path or host to a backend service.
- Authentication — validate the JWT or API key before the request reaches any service.
- Rate limiting — reject abusive callers so one client cannot exhaust your capacity.
- TLS termination — decrypt HTTPS once instead of in every service.
- Aggregation — occasionally combine calls to several services into one response.
- Observability — attach a correlation ID so a request can be traced across services.
Pro tip: Keep the gateway thin. It should route and enforce policy, not contain business logic. The moment order-calculation rules creep into the gateway, you have built a new monolith that every team must edit and redeploy together.
A concrete routing example
Spring Cloud Gateway is the common choice in the Java ecosystem. Routing is just
configuration. Here a request to /orders/** is forwarded to the order service and stripped
of its prefix:
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service # resolved via service discovery
predicates:
- Path=/orders/**
filters:
- StripPrefix=1 # /orders/42 -> /42 at the service
- id: catalog-service
uri: lb://catalog-service
predicates:
- Path=/catalog/**
filters:
- StripPrefix=1
- name: RequestRateLimiter # throttle abusive callers
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
The lb:// prefix means "look this service up in the registry and load-balance across its
instances", which is where service discovery quietly does its job. You add a new service by
adding a route, not by touching any client.
Adding a cross-cutting filter
Because every request passes through the gateway, it is the perfect place to enforce authentication once. Here is a minimal global filter that rejects requests without a token before they ever reach a service:
@Component
public class AuthFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String auth = exchange.getRequest()
.getHeaders()
.getFirst(HttpHeaders.AUTHORIZATION);
if (auth == null || !auth.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// Token present — validation happens here, then continue downstream
return chain.filter(exchange);
}
}
Now no individual service has to check for the presence of a token. That said, do not treat the gateway as your only defense — services should still validate trust, a point covered in microservices security best practices. A gateway that is your single security layer becomes a single point of compromise.
The backend-for-frontend variation
A pattern worth knowing is the backend-for-frontend, or BFF. Instead of one gateway for everyone, you run a tailored gateway per client type — one for the web app, one for mobile, one for partner APIs. A mobile client on a slow connection wants a compact, aggregated response; a web dashboard wants richer data. A BFF lets each gateway shape responses for its client without polluting the services with client-specific logic.
You do not need a BFF on day one, and running several gateways multiplies operational cost. But when a single gateway is bending over backwards to serve two very different clients, a BFF per client is often cleaner than one gateway trying to please everyone. As with every choice here, add it when the pain is real, not in anticipation.
Aggregation: one call instead of five
Sometimes a screen needs data from several services at once. A product page might want details from Catalog, price from Pricing, and stock from Inventory. Without a gateway, the client makes three round trips over a possibly slow mobile network.
An aggregation endpoint on the gateway can fan out to the three services, combine the results, and return one response. This cuts round trips and hides the internal decomposition from the client. Use it sparingly, though — heavy aggregation logic in the gateway drifts toward the fat gateway problem, and complex orchestration usually belongs in a dedicated service, not the edge.
Gateway, discovery, and load balancer — how they differ
These three get confused constantly, so pin them down:
- A load balancer spreads traffic across identical copies of one service. It works at the connection level and does not know your API.
- Service discovery is the live registry of where each service instance currently runs, since instances start and stop all the time.
- The API gateway uses discovery to find services and a load balancer to pick an instance, then adds routing, auth, and rate limiting on top. It is the application-aware layer.
You need all three in a mature system, but they solve different problems. A request to buy something typically flows through all of them: it hits the gateway, which validates your token and consults discovery to find a healthy order-service instance, then a load balancer picks one of the three replicas, and the request finally reaches your code. Each layer has one job.
When you do not need a gateway
Here is the honest guidance. If you have two internal services that only talk to each other, a gateway is machinery you have not earned yet. Direct calls, or a plain load balancer, will serve you fine, and you avoid running and scaling another component.
A gateway earns its place when you have multiple external clients, several services, and a real need to centralize authentication and rate limiting. Introduce it then, not on day one. This is the same "match the tool to the actual pressure" judgment that runs through the whole monolith-versus-microservices decision.
Common mistake: Making the gateway a single point of failure by running exactly one instance. Always run several gateway replicas behind a load balancer, and keep the gateway stateless so any instance can serve any request. A gateway outage takes down every client at once.
Keep the gateway stateless
One practical rule underpins everything above: the gateway must hold no per-request state of its own. Any instance should be able to serve any request. If instance A remembers something about your session that instance B does not, load balancing across gateway replicas breaks the moment your second request lands on B.
That means session data lives in a shared store like Redis, or better, in a stateless token such as a JWT that the client sends on every call. A stateless gateway scales horizontally without drama — add replicas under load, remove them when it passes — and a crashed instance costs you nothing because no state died with it. The instant you push session memory or business state into the gateway, you lose that property and inherit a fragile, hard-to-scale bottleneck.
Interview relevance
A frequent question is "what does an API gateway do, and how is it different from a load balancer?" The answer that impresses names the concrete responsibilities — routing, auth, rate limiting — and draws the distinction that a load balancer is connection-level while a gateway is API-aware. Bonus points for warning that a fat gateway becomes a bottleneck and a single point of failure, and that it is not a substitute for per-service security.
Related concepts
The gateway sits at the edge, so it pairs naturally with resilience and security. Study the circuit breaker pattern to see how the gateway and services protect themselves from slow downstream calls, and revisit what are microservices to keep the big picture in view.
Frequently Asked Questions
What does an API gateway do?
What is the difference between an API gateway and a load balancer?
Do I always need an API gateway for microservices?
Can the API gateway become a single point of failure?
What is the difference between an API gateway and service discovery?
Want to Build Your Career in Java Full Stack with AI?
Join CodeBegun and train with working industry engineers — Explore the Program

