RESTful Design & Versioning

Resource modeling, URI design, HTTP method semantics, and versioning strategies (URL, header, content negotiation) without breaking clients.

3/5Overview: 35m

Resource modeling

Think in nouns (resources), not verbs (actions):

RPC smellRESTful
POST /createOrderPOST /orders
GET /getUser?id=1GET /users/1
POST /orders/123/cancelDELETE /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 /searches with 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)

MethodSafeIdempotentBodyTypical use
GETYesYesNoRead
HEADYesYesNoMetadata only
PUTNoYesYesReplace resource
PATCHNoNo*YesPartial update
POSTNoNoYesCreate, actions
DELETENoYesOptionalRemove

*PATCH idempotency depends on patch semantics (JSON Merge Patch vs JSON Patch).

Status codes — use precisely

  • 200 OK, 201 Created (+ Location header), 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

StrategyExampleProsCons
URL path/v2/usersObvious, easy routingURL pollution
HeaderAccept: application/vnd.api+json; version=2Clean URLsHarder to test in browser
Query param?api-version=2024-01SimpleEasy to forget
Content-Typevendor media typesREST-puristComplex

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 Sunset header 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:

  1. Client GETs resource, receives ETag: "v3"
  2. Client PUTs with If-Match: "v3"
  3. 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 API

    Design URIs and methods for: create subscription, list user's subscriptions, cancel, upgrade plan, list invoices. Avoid RPC-style paths; justify each verb.

    20m