R1 — The building blocks: services, APIs and how they talk

R0 named what a distributed system cannot promise. R1 names the parts you build it from. This page follows one payment request through all of them; the detail lives in five parts, R1.1 to R1.5, each one a page of its own. Everything later in the pack assumes this vocabulary.

The story: one payment request, there and back

A customer taps "Pay" on their phone. Follow the request.

It leaves the phone as an HTTPS call: POST /v1/payments, an Authorization header carrying a token, an Idempotency-Key header, and a JSON body naming the payer, the payee and the amount.

It does not reach a payment service directly. It reaches a gateway first. The gateway terminates TLS, checks the token, checks that this customer has not sent 500 requests in the last second, and decides which service owns /v1/payments. Only then does it forward the call.

Behind the gateway sit several identical copies of the payment-initiation service. Any one of them can take the request, because none of them remembers anything about this customer between calls. Whatever it needs — the session, the account, the idempotency record — it reads from somewhere shared.

The service validates the payment, records it, and answers. It does not answer "paid". The rail has not settled anything yet. It answers 202 Accepted with a payment ID.

Seconds or minutes later the rail reports the real outcome. That report arrives as a webhook — an HTTP call into your system. And the phone, which is still showing a spinner, learns the outcome over a push channel or by asking again.

Every building block appears in that one trip, and each has its own part:

Step in the story Building block The question it answers Part
The phone opens an HTTPS call Connections, threads and pools How does a request reach your code, and how many can run at once? R1.1
Any copy can serve the call Stateless service + external store Where does state live? R1.2
Token, rate limit, routing Gateway What runs before your code? R1.3
POST /v1/payments → 202 API design What does the contract look like? R1.4
Rail reports, phone learns Polling, SSE, WebSocket, webhooks How does the answer come back later? R1.4
The services, taken together Architecture style How are the pieces arranged? R1.5

Whether the call between services is synchronous or asynchronous, and whether a message is a command or an event, is R0. Spreading the request across the copies is load balancing, which is R14. The queue behind the service is R9, and the cache in front of the database is R12.

The parts of R1

Read them in order the first time; each builds on the one before. Later sections of the pack point to the specific part they depend on.

Part Covers Read it when
R1.1 — Connections and request handling Connections, sockets and ports; one request through the kernel and Tomcat; every pool a request touches; sizing threads and pools; overload; virtual threads You are sizing a service, or explaining why it fell over
R1.2 — Where state lives Stateful, stateless and hybrid services; sticky sessions; a shared session store; where real systems keep their state You need to say why any instance can serve any request
R1.3 — Gateways Reverse proxy, load balancer and API gateway; what a gateway does and costs; how production systems stack them You are drawing the front door
R1.4 — The API contract Requests, resources and methods, status codes, pagination, versioning, the error model; polling, SSE, WebSocket and webhooks You are designing the endpoints, or the answer arrives later
R1.5 — Architecture styles N-tier layers; monolith, modular monolith and microservices; broker versus ESB; event sourcing You are asked "monolith or microservices?", or how history is kept

What to say in the interview

"The payment API is stateless — any instance serves any request, and the state lives in the payments database, the idempotency table and a Redis session store with a TTL; I keep stateful components, like a matching engine, for genuine real-time cases and journal them so they can be rebuilt. POST /payments requires an idempotency key and returns 202 Accepted with a payment ID, because the rail has not settled anything yet, and lists use cursor pagination. Underneath, connections are reused — keep-alive towards clients, pools towards the database — and I size Tomcat's worker threads and the database pool together, because a slow query exhausts threads long before it exhausts CPU. An L4 load balancer gives the edge a stable address; behind it a replicated gateway does TLS, authentication, rate limiting and routing in a cheap-first filter chain, with the data plane independent of the control plane, and an internal load balancer or mesh picks the instance — the gateway decides which service, the balancer decides which copy. The rail reports back by signed webhook that I deduplicate on its reference and backstop with status queries and reconciliation, and the customer's screen gets the outcome over SSE. As for the shape of the system, I start with a modular monolith and carve out a service only when it needs independent deployment, scaling or failure isolation; I keep integration logic in services we own rather than in a shared bus; and I use event sourcing where the history is the business — the ledger — not everywhere."