Community content. Review instructions before giving them to an AI agent — treat modules like open-source code.
REST API Design Rules
Design consistent, predictable REST APIs: resource-oriented URL paths, correct status codes, a uniform error envelope, pagination/filtering/sorting conventions, versioning, and idempotency.
Mby @markdownersPublished August 21, 2026 · ~3 min read
0 downloads · Used by 0 stacks
A REST API is a contract other people's code depends on — every inconsistency (a verb in one path, a noun in another; 200 here, 204 there) is a support burden multiplied across every consumer forever. Optimize for predictability over cleverness.
Resource paths
- Name paths after nouns, never verbs:
POST /orders, notPOST /createOrder— the HTTP method already carries the verb; a verb in the path duplicates it and produces inconsistent naming the moment two people design different endpoints. - Use plural nouns for collections (
/users,/orders/{id}/items) consistently — never mix singular and plural across the same API. - Nest resources only one level deep for ownership (
/orders/{id}/items), not the full hierarchy (/customers/{id}/orders/{id}/items/{id}) — deep nesting couples clients to a specific ownership chain that will eventually change; prefer flat resources with filter query params instead once nesting would exceed one level. - Use path parameters for resource identity (
/orders/{id}) and query parameters for everything else (filtering, sorting, pagination) — never encode optional behavior into the path itself.
Status codes
- Return
200for a successful read/update,201(with aLocationheader) for a successful creation,204for a successful action with no response body,400for malformed requests,401for missing/invalid auth,403for authenticated-but-not-allowed,404for a resource that doesn't exist (or that the caller isn't allowed to know exists),409for a state conflict,422for semantically invalid input that parsed fine, and429for rate limiting — pick the specific code, never default everything to200with an error flag in the body. - Never return
200for an error — a client that checks only the status code (the common case) will treat the response as success and corrupt its own state.
Error envelope
- Return one consistent error shape across every endpoint (e.g.
{ error: { code, message, details? } }) — a client should be able to write one error-parsing function for the whole API, not one per endpoint. - Use a stable machine-readable
code("validation_error","not_found") in addition to a humanmessage— messages can change wording without breaking clients that switch oncode. - Never leak internal detail (stack traces, SQL, internal ids) in error responses — log the detail server-side, return a sanitized message to the caller.
Pagination, filtering, sorting
- Paginate every collection endpoint from day one, even when the initial dataset is small — retrofitting pagination onto a live client base is a breaking change; a small dataset today does not mean the endpoint stays small.
- Prefer cursor-based pagination (
?after=<cursor>) over offset-based (?page=2) for anything that can grow or mutate during iteration — offset pagination skips or duplicates rows when the underlying data changes between requests. - Use consistent, documented query param names for filtering (
?status=active) and sorting (?sort=-created_atfor descending) across every collection endpoint, not endpoint-specific conventions.
Versioning
- Version the API explicitly from the first public release (
/v1/ordersor anAcceptheader version), even if only one version will ever exist — adding versioning later means every existing client is implicitly "v1" with no way to signal that. - Make breaking changes only in a new version; add optional fields or new endpoints within the current version freely — additive changes are not breaking, so they don't need a version bump.
Idempotency and partial updates
- Make
PUTandDELETEidempotent by construction (retrying the same request produces the same end state) — this is what lets clients safely retry on network failure without double-applying an action. - Support idempotency keys (a client-supplied
Idempotency-Keyheader) onPOSTendpoints that create resources with side effects (charges, orders) — without one, a retriedPOSTafter a timeout creates a duplicate. - Use
PATCHwith a partial body for partial updates, notPUTwith a full resource representation —PUTsemantically means "replace the whole resource," and treating it as partial-update silently drops fields the client didn't include. - Document exactly which fields a
PATCHaccepts and whether omitted fields are left unchanged or reset to default — this is the single most common point of confusion between client and server implementations.
Badge
Link back to this module from your own README.
[](https://markdowners.com/m/markdowners/rest-api-design-rules)Discussions about this module
No discussions about this module yet.
Start a discussion
Comments (0)
Sign in to comment. Sign in
No comments yet. Be the first to add one.