API Design for Distributed Systems
An API isn't just a URL scheme — it's a contract other teams build against, and it has to survive retries, versions, and failures gracefully.
Intermediate
restaurants, orders, and drivers — and HTTP methods express the action, rather than inventing a new endpoint per action.
GET /orders/482 # read one order
POST /orders # create a new order
PATCH /orders/482 # partially update an order (e.g. cancel it)
DELETE /orders/482 # remove an order
GET /orders?userId=910 # list a user's orders
/cancelOrder?id=482, /getUserOrders?userId=910 — which works, but throws away the predictability of the resource-oriented convention: once a client knows the shape for one resource, it can usually guess the shape for every other one.200 OK with {"error": "payment declined"} in the body forces every caller to parse the body just to know whether the call succeeded — using the status code correctly lets clients (and load balancers, and monitoring dashboards) understand outcomes without parsing anything.| Status code range | Meaning | Example |
|---|---|---|
| 2xx | Success | 201 Created after placing an order |
| 4xx | Client error — the request itself was invalid | 404 Not Found for a nonexistent order, 400 Bad Request for a malformed payload |
| 5xx | Server error — the request was valid but the server failed | 503 Service Unavailable during an outage |
GET /v1/orders/482
GET /v2/orders/482 # new response shape, old clients keep hitting v1
v1 keeps serving old clients unmodified, buying time for every consumer to migrate before v1 is eventually deprecated.POST /orders and times out waiting for a response genuinely doesn't know if the order was created or not — and the safe instinct, retrying, risks placing the order twice if the first request actually succeeded server-side.
POST /orders
Idempotency-Key: 7f3a9e21-...
# retrying with the SAME key returns the original order, not a duplicate