By Allan Adan · January 8, 2026 · 4 min read

REST API Design: Principles That Age Well

#backend#APIs#engineering

API design fashions change, but a small set of principles has remained correct across more than two decades of web development. These principles endure because they derive from the architecture of HTTP itself rather than from any framework. This article examines the design decisions that age well: modeling resources rather than actions, using HTTP methods and status codes for their defined meanings, preserving statelessness, and treating the published contract as something to be evolved carefully rather than broken. The thesis is that an API built on the semantics HTTP already provides will outlive one built on conventions invented anew.

Model Resources, Not Procedures

REST, as a glossary term, describes an architectural style in which a system exposes resources, each identified by a URL, that clients manipulate through a uniform interface. The first principle is therefore to model the nouns of a domain rather than its verbs. A URL such as /orders/482 names a resource; a URL such as /getOrderById smuggles a procedure into a path and discards the uniformity that makes the rest of HTTP useful.

Resource modeling pays off because it composes. Once /orders is a collection and /orders/482 is a member, the relationships among resources can be expressed as nested or linked paths without inventing new conventions for each case. The discipline of asking “what is the resource?” before “what is the operation?” tends to produce APIs that remain navigable as they grow.

Use Methods for Their Defined Semantics

HTTP defines request methods with specific meanings, and a durable API respects them. GET retrieves a representation and must not cause side effects. POST submits data and typically creates a subordinate resource. PUT replaces a resource at a known URL. PATCH applies a partial modification. DELETE removes a resource.

Two properties documented for these methods matter in practice. Safe methods, such as GET and HEAD, do not alter server state, which allows intermediaries to cache and prefetch them. Idempotent methods, such as PUT and DELETE, produce the same result whether called once or several times, which allows clients to retry safely after a network failure. Honoring these properties means that caches, proxies, and client libraries built for HTTP behave correctly without special handling.

Communicate With Status Codes

The response status code is the primary channel through which an API reports the outcome of a request. The code ranges carry meaning: 2xx indicates success, 3xx indicates redirection, 4xx indicates a client error such as a malformed or unauthorized request, and 5xx indicates a server error. An API that returns 200 with an error embedded in the body forces every client to parse the body to learn whether the call succeeded, defeating the mechanisms that depend on the status line. Returning 201 on creation, 400 on invalid input, 404 on a missing resource, and 409 on a conflict gives clients and intermediaries information they can act on directly.

Remain Stateless

A defining constraint of the style is that each request carries everything the server needs to process it; the server does not rely on stored session context from prior requests. Statelessness has a cost in request size, since authentication and relevant context must accompany each call, but it yields scalability and resilience. Any server instance can handle any request, which makes horizontal scaling and recovery from instance failure straightforward. Designs that quietly depend on server-side session affinity tend to fail precisely when load grows.

Evolve the Contract, Do Not Break It

An API is a contract with its clients, and the durable practice is to extend that contract additively. Adding a new field or a new endpoint rarely breaks existing clients; removing a field, renaming one, or changing a status code’s meaning does. When a breaking change is unavoidable, versioning isolates existing clients from it. The principle that ages well is to treat every published response shape as a commitment and to reserve breaking changes for explicit version boundaries.

Conclusion

The principles that survive shifting trends are those grounded in HTTP itself: model resources rather than procedures, use methods according to their safe and idempotent semantics, report outcomes through status codes, keep requests self-contained, and evolve the contract additively. An API built this way inherits the caching, retry, and scaling behavior that the web’s infrastructure already provides, and it remains comprehensible to engineers who encounter it years later. Designing with the grain of HTTP is, in the end, what makes an API age well.

Working on something like this? Let's talk →

Sources & references (2)