← Curriculum 04 · APIs & Web ⏱ 60 min

Module 04 · Web · All tracks

APIs & Web Fundamentals

APIs are the contracts that let systems collaborate. Interviewers probe whether you understand the protocol underneath — not just that you can call an endpoint.

60 min deep read 🎯 9 sections 📊 1 diagram

By the end you'll be able to explain, with conviction:

  • HTTP verbs, status codes, and what makes an API genuinely RESTful.
  • When to choose REST, GraphQL, or gRPC — and why.
  • Idempotency, rate limiting, gateways, and the CORS rule everyone fumbles.

1HTTP methods & status codes

HTTP is the shared grammar of the web. Speak it precisely and everything else follows.

The methods express intent: GET reads, POST creates, PUT replaces, PATCH partially updates, DELETE removes. They carry semantic promises — GET should never change state (it's safe), and several are idempotent (§3). Honouring those promises is what lets caches, proxies, and retries work correctly.

Status codes are grouped by their leading digit, and knowing the families matters more than memorising every code:

  • 2xx success — 200 OK, 201 Created, 204 No Content.
  • 3xx redirection — 301 moved permanently, 304 not modified (cache hit).
  • 4xx client error — 400 bad request, 401 unauthenticated, 403 forbidden, 404 not found, 429 too many requests.
  • 5xx server error — 500 internal error, 502 bad gateway, 503 unavailable.

Common trap

401 vs 403 trips people up: 401 means "I don't know who you are" (authenticate), 403 means "I know who you are and you're not allowed" (authorisation). Mixing them up signals shaky fundamentals.

2What REST actually means

REST is an architectural style, not a protocol — a set of constraints Roy Fielding described for using HTTP the way it was designed. The core ideas: resources identified by URLs (nouns, not verbs — /orders/42, not /getOrder?id=42), manipulated with the standard HTTP methods, exchanging representations (usually JSON).

Two constraints carry most of the weight. Statelessness: each request contains everything needed to process it; the server keeps no client session between calls. This is what lets you scale horizontally — any server can handle any request. And a uniform interface: predictable, resource-oriented URLs and verbs, so a new consumer can guess how the API works.

💬 Interview angle

"REST is a style: resources as URLs, standard HTTP verbs, and — the part people skip — statelessness. Because the server holds no session between requests, any instance can serve any request, which is what makes it scale horizontally."

3Idempotency & versioning

Idempotency means making the same request multiple times has the same effect as making it once. GET, PUT, and DELETE are idempotent; POST typically isn't (two POSTs create two orders). This matters enormously in the real world because networks retry — if a response is lost, the client resends, and a non-idempotent operation can double-charge a customer. The fix is an idempotency key the server uses to deduplicate retries.

Versioning protects existing consumers when an API must change incompatibly. Common approaches: URL path (/v2/orders), a header, or a query param. The principle matters more than the mechanism: never break existing clients — add a new version and migrate, rather than changing the old contract underneath people.

💬 Interview angle

"Idempotency means a repeated request has the same effect as one — critical because clients retry on network failures. For payments I'd use an idempotency key so a retried POST can't double-charge."

4The request/response lifecycle

Knowing the journey of a request lets you reason about latency and failure at every hop.

flowchart LR C[Client] --> DNS[DNS resolve] DNS --> LB[Load Balancer] LB --> GW[API Gateway
auth · rate limit] GW --> S[Service] S --> DB[(Database)] DB --> S --> GW --> LB --> C
Each hop is a place latency accrues and failures can be handled — DNS, balancing, the gateway's cross-cutting concerns, the service, the data.

The takeaway for interviews: a "slow API" is rarely one thing. It could be DNS, TLS handshakes, a cold load balancer, gateway auth, the service logic, or a slow query (Module 03). Naming the stages shows you can diagnose systematically instead of guessing.

5REST vs GraphQL vs gRPC

Three ways to shape an API, each solving a different pain.

RESTGraphQLgRPC
ShapeResources + verbsSingle endpoint, query languageRPC over HTTP/2 + Protobuf
SolvesSimplicity, cachingOver/under-fetchingSpeed, typed contracts
CostMany round-tripsComplexity, caching is hardNot browser-native, binary
Sweet spotPublic, cacheable APIsRich frontends, varied clientsInternal microservices

GraphQL lets the client ask for exactly the fields it needs in one request — killing the REST problems of over-fetching (too much data) and under-fetching (N calls to assemble a screen). gRPC uses binary Protobuf over HTTP/2 for low-latency, strongly-typed service-to-service calls. The honest summary: REST for public/cacheable APIs, GraphQL for complex frontends with diverse data needs, gRPC for fast internal microservice communication.

💬 Interview angle

"REST is simple and cacheable; GraphQL fixes over- and under-fetching for rich clients but makes caching harder; gRPC is fast, typed, and binary — great between internal services but not browser-native. I choose by client and performance needs."

6Real-time: WebSockets & SSE

Plain HTTP is request-response: the client asks, the server answers, done. Real-time features need the server to push. Two main tools:

  • WebSockets — a persistent, full-duplex connection: both sides send messages any time. Ideal for chat, multiplayer, collaborative editing — anything bidirectional.
  • Server-Sent Events (SSE) — a one-way stream from server to client over plain HTTP. Simpler than WebSockets and great for notifications, live feeds, or streaming LLM tokens, where the client only needs to listen.

Before either, the old hack was polling (ask repeatedly) or long-polling. Mentioning that you'd reach for SSE over WebSockets when traffic is one-directional shows you pick the simplest tool that fits — a senior instinct.

Go deeper

Streaming LLM responses token-by-token is a textbook SSE use case — one-way, incremental, over standard HTTP. If the role is GenAI-flavoured, that's a sharp, relevant example to drop.

7Pagination, filtering, rate limiting

These three keep an API usable at scale. Pagination stops a list endpoint returning a million rows: offset-based (?page=3) is simple but drifts when data changes mid-scroll; cursor-based (a pointer to the last item seen) is stable and performs better on large datasets — the senior choice for infinite scroll.

Filtering, sorting, and field selection via query params let clients fetch just what they need. Rate limiting protects the service from abuse and runaway clients — a common scheme is a token bucket per API key, returning 429 Too Many Requests with a Retry-After header when exceeded. It's both a stability and a fairness mechanism.

💬 Interview angle

"For large lists I prefer cursor-based pagination over offset — it's stable when rows are inserted mid-scroll and faster at depth. And I'd rate-limit per key with a token bucket, returning 429 with Retry-After so clients can back off gracefully."

8API gateways

In a microservices world, an API gateway is the single front door. Instead of clients talking to dozens of services directly, they hit the gateway, which routes each request to the right service and handles the cross-cutting concerns in one place: authentication, rate limiting, TLS termination, request logging, caching, and sometimes response aggregation.

The value is DRY infrastructure — you implement auth and rate limiting once at the edge rather than in every service, and clients get one stable endpoint while the services behind it can change freely. It's the network-level expression of the same "centralise the cross-cutting concern" instinct you saw with middleware and encapsulation.

9CORS — the one everyone gets wrong

CORS (Cross-Origin Resource Sharing) is misunderstood constantly, so nail it. The browser enforces a same-origin policy: by default, JavaScript on site-a.com can't read responses from api-b.com. CORS is the mechanism by which a server opts in to allowing specific other origins, via response headers like Access-Control-Allow-Origin.

The two things people miss: CORS is enforced by the browser, not the server (a server-to-server call or curl ignores it entirely), and it's a relaxation of security, not a restriction — the server decides who's allowed. For non-simple requests the browser first sends a preflight OPTIONS request to ask permission before the real one.

Common trap

"I got a CORS error so the API is down" — no. A CORS error means the browser blocked the response because the server didn't grant your origin permission. The fix is server-side headers, and it only ever affects browser-based callers.

💬 Interview angle

"CORS is a browser-enforced policy where the server opts in to which origins may read its responses. It's not a server-side block and it doesn't apply to server-to-server calls — and non-simple requests get a preflight OPTIONS first."

Recap — what you can now teach

  • HTTP verbs carry semantic promises; status-code families matter more than memorising codes (401 ≠ 403).
  • REST = resources, verbs, and statelessness — which is what enables horizontal scale.
  • Idempotency + idempotency keys make retries safe; version to never break existing clients.
  • REST for cacheable APIs, GraphQL for over/under-fetching, gRPC for fast internal services.
  • WebSockets for bidirectional, SSE for one-way streams; cursor pagination + rate limiting at scale.
  • Gateways centralise cross-cutting concerns; CORS is a browser-enforced server opt-in.

Self-check

Say each answer out loud before revealing it.

What's the difference between 401 and 403?

Why does statelessness let REST scale horizontally?

When would you pick GraphQL over REST?

Who enforces CORS, and what does it actually do?

How do you make a payment POST safe to retry?