Statelessness, Versioning & Query Design
Statelessness
Every request carries all context needed to process it — no server-side session state between requests. This is why auth is typically a Bearer token in the Authorization header on every request, rather than a persisted server-side session.
Versioning
/v1/users # URL path version
Accept: application/vnd.myapi.v2+json # content negotiation versionAdding a new optional field is safe (clients ignore what they don't recognize); removing/renaming a field or changing its type is a breaking change. Knowing this distinction determines what ships to an existing version vs. what needs a new one.
Filtering, Sorting & Pagination
GET /users?status=active&sort=-createdAt&search=ada&page=2&limit=20
GET /users?after=<cursor>&limit=20 # cursor-based, more stable under concurrent writesPATCH Ambiguity: Omitted vs. Null
A naive merge-based PATCH can't tell "clear this field" (explicit null) from "don't touch this field" (omitted). Document the convention clearly, or use a formal patch-operation format (JSON Patch, RFC 6902) when the ambiguity matters.
Rate Limiting & Decoupling from Internals
Rate limits protect the backend from excess traffic — commonly communicated via X-RateLimit-Remaining/Retry-After headers. Avoid exposing raw database internals (auto-increment IDs, internal column names) directly — a stable API-specific shape (UUIDs, a deliberate response structure) decouples the public contract from implementation, letting the database evolve without breaking clients.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free