AI Computer Institute
Expert-curated CS & AI curriculum aligned to CBSE standards. A bharath.ai initiative. About Us

API Gateway Pattern: Routing Requests Efficiently

📚 Architecture⏱️ 22 min read🎓 Grade 9
✍️ AI Computer Institute Editorial Team Updated: August 2026 CBSE-aligned · Peer-reviewed · 22 min read
Content curated by subject matter experts with IIT/NIT backgrounds. All chapters are fact-checked against official CBSE/NCERT syllabi.

Open the results app on your phone the day CBSE marks are released. In the same few seconds, that one app screen shows your attendance percentage, your latest test scores, whether your school fee installment has been received, and a notice from the library about an overdue book. It feels like one app talking to one server. It almost never is. Behind that single screen there are usually several separate programs running on separate machines — an Attendance system, a Results system, a Fees system, a Library system — each one built, tested, and updated independently, often by different teams. Your phone never contacts any of them directly. It sends every request to one address, and something on the other end reads each request and decides which of the four systems should actually handle it. That something is called an API gateway, and figuring out how it decides "who handles this" is what this chapter is about.

A quick refresher: what is an API request?

Before talking about gateways, fix one idea firmly: a server is a program running on a computer somewhere, waiting for messages. A client — your phone app, a browser, another program — sends it a message called a request. A request has, at minimum, a method (usually GET to fetch data or POST to send data) and a path, which is the part of the address that says what is being asked for, such as /api/fees/receipt/2026. The server reads the request and sends back a response. This request/response contract between programs — not between a human and a web page, but between two pieces of software — is what people mean by an API (Application Programming Interface). Everything in this chapter is about what happens to a request in the small gap between "the phone sent it" and "the correct server received it."

What goes wrong without a gateway

Suppose your school builds these four services separately and simply gives the phone app all four addresses directly: the Attendance service at 10.0.0.1:5001, Fees at 10.0.0.2:5002, Results at 10.0.0.3:5003, Library at 10.0.0.4:5004. The app calls whichever address it needs. This works for a demo, but it breaks down in ways that matter once real students depend on it:

  • The app must know every address. If the school's IT team moves the Fees service to a new machine, or a fifth service (say, a Transport tracker) is added next year, every phone that has ever installed the app needs an update just to keep working — because the addresses are hardcoded inside it.
  • Security is duplicated four times. Each of the four services independently has to check "is this really a logged-in student, and are they allowed to see this data?" That check gets written, and can go wrong, four separate times, by four separate teams. A bug in the Library service's login check does not just break the library feature — it can leak student data.
  • Nobody can see the whole picture. If someone starts hammering the Results service with thousands of requests right after boards are declared, there is no single place recording "who is calling what, how often" — each service only sees its own slice of traffic.
  • The internal structure of the school's servers is exposed to the internet. Four raw IP addresses and ports sitting inside a phone app is four separate things an attacker can probe, rather than one.

Every one of these problems has the same shape: work that should be done once, in one place is instead scattered across every backend service. The fix is to stop letting the client talk to the services directly at all.

The API gateway: one door, many rooms

An API gateway is a single server that sits between every client and every backend service. The client only ever knows one address — the gateway's. Every request goes there first. The gateway reads the request, decides which backend service is meant to handle it, forwards the request to that service, waits for the reply, and sends the reply back to the client. From the phone's point of view, there is exactly one system to talk to. From the school's point of view, there can be as many backend services as needed, added, removed, or moved around, without the phone app ever noticing.

This is a specific case of a more general networking idea called a reverse proxy — a server that receives requests on behalf of other servers and forwards them onward. What makes it a gateway specifically is that it does more than blind forwarding: it looks at what is being asked for and routes different requests to different destinations, and along the way it enforces rules that apply to all of them. The diagram below shows the shape of it for our four-service school system.

Student's Phone App sends one request GET /api/fees/... API Gateway /api/attendance -> 5001 /api/fees -> 5002 /api/results -> 5003 /api/library -> 5004 Auth + Rate Limit check (one entry point, one place to enforce rules) Attendance Service port 5001 Fees Service port 5002 Results Service port 5003 Library Service port 5004 The gateway reads only the path prefix to decide where a request goes - the phone app never needs to know these four addresses exist.

Routing: how the gateway decides "which service?"

The most common routing rule is beautifully simple: look at the path prefix of the request and match it against a table. Here is the routing table for our school system, exactly as drawn above:

/api/attendance  ->  http://10.0.0.1:5001
/api/fees        ->  http://10.0.0.2:5002
/api/results     ->  http://10.0.0.3:5003
/api/library     ->  http://10.0.0.4:5004

A request for /api/fees/receipt/2026 starts with the prefix /api/fees, so the gateway strips that prefix off and forwards the remaining part, /receipt/2026, to the Fees service. The Fees service never even sees the /api/fees part — as far as it is concerned, it just received a normal request for /receipt/2026. This stripping step matters: it means the Fees service's own code does not need to know or care what prefix the gateway used to find it.

Here is that matching logic written out as real, runnable JavaScript, close to how a lightweight gateway (built with something like Node.js) actually works:

const routingTable = [
  { prefix: "/api/attendance", target: "http://10.0.0.1:5001" },
  { prefix: "/api/fees", target: "http://10.0.0.2:5002" },
  { prefix: "/api/results", target: "http://10.0.0.3:5003" },
  { prefix: "/api/library", target: "http://10.0.0.4:5004" }
];

function findRoute(path) {
  let bestMatch = null;
  for (const route of routingTable) {
    if (path.startsWith(route.prefix)) {
      if (bestMatch === null || route.prefix.length > bestMatch.prefix.length) {
        bestMatch = route;
      }
    }
  }
  return bestMatch;
}

function routeRequest(path) {
  const route = findRoute(path);
  if (route === null) {
    return "404 Not Found: no service handles this path";
  }
  const remainingPath = path.slice(route.prefix.length);
  return `Forwarding to ${route.target}${remainingPath}`;
}

console.log(routeRequest("/api/fees/receipt/2026"));
console.log(routeRequest("/api/attendance/student/9A-17"));
console.log(routeRequest("/api/timetable/monday"));

Trace it exactly the way the machine would, one call at a time:

  1. routeRequest("/api/fees/receipt/2026")findRoute loops through all four rows. Only "/api/fees" is a prefix of the path (the string starts with those nine characters), so bestMatch becomes the Fees route. Back in routeRequest, remainingPath is the path with the first 9 characters removed, giving "/receipt/2026". Result: "Forwarding to http://10.0.0.2:5002/receipt/2026".
  2. routeRequest("/api/attendance/student/9A-17") — only "/api/attendance" (15 characters) matches. Stripping those 15 characters leaves "/student/9A-17". Result: "Forwarding to http://10.0.0.1:5001/student/9A-17".
  3. routeRequest("/api/timetable/monday") — none of the four prefixes match this path at all, so bestMatch stays null all the way through the loop, and routeRequest returns the 404 message. This is correct behaviour: a gateway should refuse a request cleanly rather than guess where to send it.

Notice the comparison route.prefix.length > bestMatch.prefix.length inside the loop. With this particular table it never actually changes the outcome, because no prefix here is contained inside another. But it is there for a reason worth understanding: if the table also had a general rule /api -> some default service alongside the specific rule /api/fees -> Fees service, then a request for /api/fees/receipt/2026 would match both rules. Picking the longest matching prefix means the more specific rule wins — exactly the same principle used in real computer networks, where a router chooses the most specific matching address range for an IP packet. Grade 9 algorithmic thinking and real infrastructure design turn out to be the same idea: when several rules could apply, let the most specific one win.

Authentication: checking identity once, not four times

Recall the second problem from earlier — every service having to independently verify "is this really a logged-in student?" A gateway fixes this by doing the check itself, before any forwarding happens. When your phone logs in, it typically receives a token — a signed piece of text proving who you are — and attaches it to every subsequent request in a header. The gateway's job, before it even looks at the routing table, is: read the token, verify it is valid and not expired, and only then proceed to route the request. If the token is missing or invalid, the gateway immediately replies with an error (commonly numbered 401 Unauthorized) and never bothers any backend service at all. The Attendance, Fees, Results, and Library services can then be written under one simple, load-bearing assumption: "if a request reaches me, the gateway has already confirmed who sent it." That assumption is what lets four independent teams skip writing four independent, error-prone copies of the same login check.

Rate limiting: protecting services from overload

The third job worth tracing carefully is rate limiting — capping how many requests one client can send in a given time window, so that one misbehaving app (or a bug that loops and re-sends requests) cannot overwhelm a backend service. A simple version, called a fixed-window counter, works like this: pick a limit (say, 5 requests) and a window length (say, 60 seconds). Keep a counter for each student. Every time a request arrives, check whether the current 60-second window has ended; if it has, reset the counter to zero and start a new window. Then increase the counter by one and check whether it has gone over the limit.

const LIMIT = 5;
const WINDOW = 60; // seconds

let windowStart = 0;
let count = 0;

function checkRequest(t) {
  if (t >= windowStart + WINDOW) {
    windowStart = Math.floor(t / WINDOW) * WINDOW;
    count = 0;
  }
  count = count + 1;
  if (count > LIMIT) {
    return `t=${t}s -> BLOCKED (429 Too Many Requests), count=${count}`;
  }
  return `t=${t}s -> ALLOWED, count=${count}`;
}

Trace it for roll number 9A-17 sending requests at t = 2, 10, 25, 40, 50, 55, and 63 seconds:

  • t=2, 10, 25, 40, 50 — each falls inside the window [0, 60), so the counter climbs 1, 2, 3, 4, 5. All five are ALLOWED, the fifth exactly at the limit.
  • t=55 — still inside [0, 60), the counter becomes 6, which is over the limit of 5, so this one is BLOCKED.
  • t=63 — this is past 60 seconds, so t >= windowStart + WINDOW is true. windowStart resets to 60 and count resets to 0 before incrementing, giving count=1. A fresh window means this request is ALLOWED again.

Because the gateway is the single place every request passes through, it is the only place that can actually count requests per student across all four services combined. If each service tried to rate-limit on its own, a determined script could still overload the school's servers by spreading its requests across all four — one gateway-level counter closes that gap.

Aggregation: answering one screen with several backend calls

Sometimes the client does not want one service's data — it wants a combined view. The results-day dashboard mentioned at the start needs attendance percentage, latest marks, and fee status all at once. Without a gateway, the phone app itself would have to make three separate calls, one after another, and stitch the answers together on a possibly weak mobile connection. A gateway can instead offer one combined endpoint, say /api/dashboard, that internally calls all three backend services itself and merges their replies into a single response before sending it to the phone.

The saving is not just convenience — it is measurable. Suppose, purely for this calculation, that each backend call takes about 150 milliseconds to complete over a typical mobile connection. If the phone makes the three calls itself, one after another, that is roughly 150 + 150 + 150 = 450 milliseconds of waiting before the screen can be drawn. If the gateway instead fires all three calls out to the backend services at the same time and waits for whichever finishes last, the total time is close to just 150 milliseconds — because the three calls overlap instead of stacking up. The phone app only ever made one request and received one reply, so it does not need to manage three separate network calls, three separate failure cases, or three separate loading spinners.

A common mix-up: is a gateway just a load balancer?

It is worth naming this misconception directly, because the two ideas get confused constantly and they solve genuinely different problems. A load balancer sits in front of several identical copies of the same service — say, three identical copies of the Results service running on three machines because results-day traffic is heavy — and spreads incoming requests roughly evenly across those copies so no single machine gets overwhelmed. It does not care what the request is about; every copy behind it can handle any request the same way, so it mostly just needs a rule like "send this one to whichever machine is least busy."

An API gateway solves a different problem: it sits in front of several different services and decides, based on the content of the request (the path, in our examples), which different service should receive it. It also carries responsibilities a load balancer typically does not — authentication, rate limiting, combining responses — because it is the one place that sees every request regardless of which service it is destined for. In a large real system the two are often layered together: the gateway first decides "this is a Results request," and only then does a load balancer sitting behind the gateway decide "and specifically, which of the three Results machines should handle it." Confusing the two leads to design mistakes — like putting authentication logic inside a load balancer, where it cannot see enough of the request to make a sound decision, or expecting a single-service load balancer to somehow understand five unrelated services.

Where this fits in what you already know

You have likely already met the client-server model as a basic idea in networking — one machine asks, another answers. The API gateway pattern is what that idea grows into once a real system stops being "one server" and becomes many small, independently-run services, which is how almost every serious web and mobile backend is actually built today. The core skill this chapter asked you to practice — tracing a routing table match, a longest-prefix comparison, and a fixed-window counter by hand, one step at a time — is the same skill examiners reward in board-exam algorithm-tracing questions and the same skill you will use again the moment you meet routing tables in networking, or matching/priority rules in any later data-structures topic.

Summary

  • An API gateway is a single server that every client talks to; it forwards each request to the correct backend service instead of letting clients contact services directly.
  • Routing commonly works by matching the request's path against a table of prefixes, choosing the longest matching prefix when more than one rule could apply, then stripping that prefix before forwarding.
  • Authentication done once at the gateway means backend services can trust that any request reaching them has already been verified, instead of each service re-checking identity independently.
  • Rate limiting, such as a fixed-window counter, caps how many requests a client can send per time window and can only fully protect a system when it is enforced centrally, at the gateway, across all services.
  • Aggregation lets the gateway call several backend services in parallel and combine their answers into one response, cutting the client's total waiting time compared to making the calls one after another.
  • A gateway is not the same as a load balancer: a load balancer spreads traffic across identical copies of one service; a gateway routes different requests to different services and enforces shared rules across all of them. Real systems commonly use both together.

Check your understanding

  1. A school adds a fifth service, Transport tracking, reachable by forwarding to it any request whose path starts with /api/transport. Using the routing code from this chapter, what would routeRequest("/api/transport/bus/12") return once this new row is added to routingTable?
  2. Suppose the routing table has both /api (a default/fallback service) and /api/results (the Results service) as valid prefixes. A request arrives for /api/results/9A-17. Which service should handle it, and which line of the findRoute function makes sure that happens?
  3. Using the fixed-window rate limiter with LIMIT = 5 and WINDOW = 60, if requests from one student arrive at t = 5, 20, 35, 50, 65, and 80 seconds, which ones are ALLOWED and which are BLOCKED? Work through the window resets carefully.
  4. Explain, in your own words, why moving the authentication check from "inside each of the four services" to "inside the gateway, once" reduces the number of places a security bug could exist — and why it does not eliminate security bugs completely.

Answers. (1) The new row's prefix /api/transport matches, so it returns "Forwarding to http://<transport-service-address>/bus/12" — the general routing code works for a fifth service with zero changes to findRoute or routeRequest. (2) The Results service should handle it, because /api/results is the longer, more specific matching prefix; the comparison route.prefix.length > bestMatch.prefix.length is exactly what makes the loop prefer it over the shorter /api match. (3) t=5,20,35,50 are ALLOWED (counts 1-4, still window [0,60)); t=65 falls in the next window [60,120) since 65 >= 0+60, so it resets and is ALLOWED as count=1; t=80 is still inside [60,120), so it becomes count=2, ALLOWED. All six are allowed here because the second window absorbs the later requests — a useful check on whether you tracked the window reset correctly, not just the counting. (4) Centralising the check means there is exactly one implementation to review, test, and patch instead of four, so a mistake found once gets fixed everywhere at once; but it does not remove security bugs entirely, because the gateway itself becomes a single high-value target, and a flaw in its one auth check now affects every service behind it rather than just one.

Think About It

Think about this: How would you explain api gateway pattern: routing requests efficiently to a friend who has never seen a computer? What real-world analogy would you use? Imagine you had to build a system using these concepts — what would be your first step? Try this: before moving on, write down three things you learned and one question you still have.

← Resolving Git Merge ConflictsMicroservices Architecture: Building Scalable Apps →

Found this useful? Share it!

📱 WhatsApp 🐦 Twitter 💼 LinkedIn