REST API design: the decisions that make an API pleasant to use
An API is a product with developers as users. Most of what makes one good is consistency, not cleverness.
Version an API when you must make a breaking change — removing or renaming a field, changing a type, tightening validation, or altering default behaviour. URL versioning is the pragmatic default; date-based versioning suits APIs that evolve continuously. Whatever you choose, publish a deprecation policy with dates and enforce it, or you will maintain every version forever.
| Change | Breaking? |
|---|---|
| Adding an optional response field | No |
| Adding an optional request parameter | No |
| Removing or renaming a field | Yes |
| Changing a field's type or format | Yes |
| Making an optional parameter required | Yes |
| Tightening validation on existing input | Yes |
| Changing default sort order or pagination size | Yes, in practice |
| Adding a new enum value | Usually — clients often switch exhaustively |
| Scheme | Example | Pros | Cons |
|---|---|---|---|
| URL path | /v2/orders | Visible, cacheable, easy routing | Duplicated routes; version in every link |
| Header | Accept: application/vnd.api.v2+json | Clean URLs, content negotiation | Invisible in logs, harder to test |
| Query parameter | /orders?version=2 | Simple | Easy to forget; pollutes cache keys |
| Date-based | API-Version: 2026-01-15 | Fine-grained, per-account pinning | Complex to implement internally |
URL versioning wins on operability: you can see the version in access logs, route it at the load balancer, and test it in a browser. Date-based versioning, as used by several large payment and communication APIs, is excellent for continuously evolving products but requires disciplined internal transformation layers.
Design for extension: additive changes, tolerant readers, and explicit opt-in for new behaviour.
HTTP/1.1 200 OK
Deprecation: Sat, 15 Nov 2026 00:00:00 GMT
Sunset: Sun, 15 Feb 2027 00:00:00 GMT
Link: <https://docs.example.com/migrate/v2>; rel="deprecation"Do not fork your business logic. Keep one internal domain model and write thin transformation layers at the edge that convert requests and responses between the versioned shape and the internal one. Forked handlers diverge, and bugs get fixed in one version but not the other.
Test every supported version in CI with contract tests derived from the published specification. That is what makes 'we support v1 and v2' a statement rather than a hope.
Two — the current one and the previous one. Three or more multiplies testing and support cost, and usually means a deprecation deadline was allowed to slip.
If the client and server deploy together, no — use type-safe contracts and update both. If they deploy independently, treat the internal API like an external one.
Partly. Only the major version usually appears in the URL, since minor and patch changes should be backwards compatible by definition. Use semver in your SDKs where it fits naturally.
Security fixes sometimes force it. Communicate immediately with the reason and timeline, provide a migration path, and give the largest affected customers direct support. Transparency is what preserves trust.
Harshal Patel
Founder & Lead Engineer, ROVQIX
Harshal leads engineering at ROVQIX, where he has shipped production Next.js, Node.js and PostgreSQL systems for startups, SaaS teams and ecommerce brands. He writes about the trade-offs behind architecture decisions rather than the framework of the week.
ROVQIXdesigns and builds production web platforms — Next.js front ends, Node.js APIs and the infrastructure behind them. Tell us what you're building and we'll scope it with you.
An API is a product with developers as users. Most of what makes one good is consistency, not cleverness.
Webhooks are an API you deliver to someone else's unreliable server. Design for their failures, not just your success.
GraphQL solves a real problem for a specific shape of team. If you are not that team, it is a large bill for flexibility you will not use.
No spam. Just the occasional case study and craft breakdown.