awesome-everything RU
↑ Back to the climb

APIs

REST modeling: design an order API that survives change

Crux Hands-on project — model and build a small order-management REST API that survives schema change, handles non-CRUD transitions safely, and stays retry-safe under failure.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 220 min

Reading about resource modeling is not the same as defending a contract through a real schema change. Design and build a small order API, then prove it survives the three things that break naive APIs in production: a column rename, an unguarded state transition, and a retried create.

Goal

Turn the unit’s mental model into a working API: model nouns instead of verbs, express non-CRUD actions as guarded transitions, decouple the representation from the schema with a mapping layer, and make creates retry-safe — proving each property, not asserting it.

Project
0 of 6
Objective

Design and build a small order-management REST API (Orders, Items, Refunds) whose contract survives a database column rename, refuses an illegal state transition, and returns the original result on a retried create — demonstrating each property with a request/response transcript.

Requirements
Acceptance criteria
  • A transcript proving schema decoupling: rename a DB column (e.g. full_name to display_name) with NO change to the wire representation, shown by identical request/response before and after the migration.
  • A transcript proving the guarded transition: POST /orders/{id}/cancel succeeds on a cancellable order and is rejected with a 4xx on an already-shipped one, while a direct attempt to write status via PATCH is refused.
  • A transcript proving retry safety: the same POST sent twice with one Idempotency-Key creates exactly one resource and returns the same id/result both times.
  • A one-page URL map and a short write-up naming, for each non-CRUD action, whether you chose an action sub-resource or a transition resource and why.
Senior stretch
  • Add cursor-based pagination, filtering, and sorting on the collection (GET /orders?status=open&sort=-created_at&cursor=...) and document why these are query params, not new endpoints.
  • Add HATEOAS links (_links with the legal next actions per order state) and write one client that follows the cancel link instead of hardcoding the URL — then note what it cost versus level-2 REST.
  • Add API versioning and demonstrate evolving a representation without breaking v1 clients, absorbing the change in the mapping layer.
  • Add an OpenAPI spec generated from the implementation and a contract test that fails the build if a response leaks a field not in the documented representation.
Recap

This is the design loop you run on every real API: model nouns and let the method carry the verb; express non-CRUD transitions as guarded actions or transition resources so the server owns the state machine; keep nesting shallow and expand instead of walking; serialize through a mapping layer so the representation is a contract you own and the database stays refactorable; and make creates retry-safe with idempotency keys. Doing it once on a small order API turns these from rules you can recite into shapes you reach for by reflex.

Continue the climb ↑Status codes that actually matter in production
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.