Designing REST APIs
A good REST API is predictable: someone who has used one of your endpoints can guess how the rest behave. That predictability comes from a handful of conventions applied consistently — around resources, methods, status codes, validation, and change over time. This guide explains the reasoning behind each so you can make sound calls on the cases the conventions don't spell out. The checklist below is auto-generated from the enforceable rules; the reference checklist at the end covers the broader practices.
Model resources, not actions
REST is organized around nouns (resources), not verbs. The URL identifies what (/orders/42/items), and the HTTP method says what to do with it. Resist the urge to encode actions in the path (/getOrder, /createUser) — the method already carries that meaning:
- GET reads and must be safe (no side effects) and idempotent (calling it twice changes nothing).
- POST creates or triggers a non-idempotent action.
- PUT replaces a resource and is idempotent; PATCH partially updates it.
- DELETE removes a resource and is idempotent.
Idempotency matters in practice because networks retry. If a client never knows whether its request arrived, idempotent methods make retries safe, and you can offer an idempotency key on POST to extend the same guarantee to creates.
Say what happened with the right status code
The status code is the first thing every client — and every cache, proxy, and monitoring tool — reads. Use it honestly:
- 2xx success:
200 for a read, 201 for a create (with a Location header), 204 for a successful action with no body.
- 4xx the caller's fault:
400 malformed, 401 not authenticated, 403 authenticated but not allowed, 404 not found, 409 conflict, 422 well-formed but semantically invalid, 429 rate-limited.
- 5xx your fault:
500 for an unhandled error — and never leak a stack trace or internal detail in the body.
Returning 200 with an { "error": ... } body is a common anti-pattern: it hides failures from everything that reads the status line.
Treat every request as hostile until proven otherwise. Validate all request input — body, query, params, headers — against a schema at the edge of your handler, before any of it touches business logic or the database. This is both a correctness measure (reject the malformed early) and a security one (it's your first line against injection and abuse). Return 422/400 with a structured, field-level error so the caller can fix the request, without exposing internals.
Protect the API from load and abuse
A public endpoint with no limits is a liability. Implement rate limiting so a single client — buggy or malicious — can't exhaust your capacity, and return 429 with a Retry-After header so well-behaved clients can back off. Pair this with pagination on any collection endpoint: never return an unbounded list, because the one customer with 100,000 rows will eventually find that endpoint.
Plan for change from day one
APIs are contracts, and contracts outlive your current intentions. Version your API (a /v1/ path prefix is the simplest, most legible choice) so you can evolve without breaking existing clients. Add fields freely — that's backward-compatible — but treat removing or renaming a field, or changing a type, as a breaking change that belongs in a new version.
A practical checklist
The items currently enforced as rules appear in the auto-generated Checklist below (and link to each rule). The broader set worth reviewing on any endpoint:
- Resource-oriented URLs; methods match semantics; idempotency where it matters.
- Correct status codes; structured errors; no internals leaked.
- Input validated at the boundary; collections paginated.
- Rate limiting +
Retry-After; auth on every non-public route.
- Consistent naming, timestamps, and error shape across endpoints.
- Versioned from the start; additive changes only within a version.
Used together, these turn a set of endpoints into something a consumer can trust and reason about. Where an item is enforceable, it lives as a rule in this skill — and the checklist below is generated from exactly those.