Resource modeling
Think in nouns (resources), not verbs (actions):
| RPC smell | RESTful |
|---|---|
POST /createOrder | POST /orders |
GET /getUser?id=1 | GET /users/1 |
POST /orders/123/cancel | DELETE /orders/123 or POST /orders/123/cancellations |
Not LLD: In a low-level design round you sketch ParkingLot.park(car) on a class. Here you design POST /parking-spots/{id}/reservations on a network contract consumed by unknown clients. LLD owns cohesion of in-process APIs; this topic owns HTTP resources, status codes, and versioning across deploy boundaries.
Sub-resources express relationships: GET /users/42/orders, GET /orders/99/line-items.
Actions that don't map to CRUD — use sub-resource or RPC-style POST on a resource:
POST /orders/123/capture(payment capture)POST /searcheswith body (complex query as resource creation)
Google API design uses collections, resources, and standard methods (List, Get, Create, Update, Delete) plus custom methods (:cancel) when needed.
HTTP method semantics (application layer)
| Method | Safe | Idempotent | Body | Typical use |
|---|---|---|---|---|
| GET | Yes | Yes | No | Read |
| HEAD | Yes | Yes | No | Metadata only |
| PUT | No | Yes | Yes | Replace resource |
| PATCH | No | No* | Yes | Partial update |
| POST | No | No | Yes | Create, actions |
| DELETE | No | Yes | Optional | Remove |
*PATCH idempotency depends on patch semantics (JSON Merge Patch vs JSON Patch).
Status codes — use precisely
- 200 OK, 201 Created (+
Locationheader), 204 No Content - 400 Bad Request (client bug), 422 Unprocessable (validation — debatable vs 400)
- 401 Unauthenticated, 403 Forbidden (authenticated but denied)
- 404 Not found (or intentionally hidden), 409 Conflict, 412 Precondition failed
- 429 Too Many Requests (+
Retry-After) - 500 Server error — never for validation; 503 unavailable (retryable)
Senior signal: distinguish retryable (502, 503, 429) vs non-retryable (400, 404, 409) for client SDK design.
Versioning strategies
| Strategy | Example | Pros | Cons |
|---|---|---|---|
| URL path | /v2/users | Obvious, easy routing | URL pollution |
| Header | Accept: application/vnd.api+json; version=2 | Clean URLs | Harder to test in browser |
| Query param | ?api-version=2024-01 | Simple | Easy to forget |
| Content-Type | vendor media types | REST-purist | Complex |
Compatibility rules staff teams enforce:
- Additive changes only in minor versions (new fields, new endpoints)
- Never remove or rename fields without major version
- Deprecation window with
Sunsetheader and metrics on old version usage - Consumer-driven contract tests (Pact) before breaking changes
HATEOAS — know it, rarely ship it
Hypermedia links in responses (_links: { "next": { "href": "..." } }) enable discoverability. Valuable for public platform APIs and long-lived integrations. Most internal microservices skip it in favor of OpenAPI + codegen.
Conditional requests
ETag + If-Match for optimistic concurrency — prevent lost updates:
- Client GETs resource, receives
ETag: "v3" - Client PUTs with
If-Match: "v3" - Server returns 412 if someone else updated first
Pairs with Networking's caching material — here the focus is write conflict detection, not CDN cache. Databases → Transactions & MVCC explains isolation behind optimistic locking; here you expose it as ETag/If-Match on the HTTP API.
Further Reading
Hands-On Tasks (Optional)
API design drills and whiteboard exercises — protocol selection, contract design, and bulk-transfer architecture. Assumes Networking and sibling tracks on the hub page (Distributed Systems, Databases, Concurrency, LLD).
- Model resources for a subscription API20m
Design URIs and methods for: create subscription, list user's subscriptions, cancel, upgrade plan, list invoices. Avoid RPC-style paths; justify each verb.