Learning Material

API Design Principles That Age Well

Learning Material · Software Engineering

Cover: API Design Principles That Age Well

Consistency beats cleverness

An API that's boringly consistent — the same patterns for every resource, the same error shape everywhere — is easier to work with than one that's individually elegant in each endpoint but inconsistent between them. Consistency is what lets a developer guess correctly without reading the docs every time.

Resource naming

GET    /users          # list users
GET    /users/42       # get one user
POST   /users          # create a user
PATCH  /users/42       # update a user
DELETE /users/42       # delete a user

Plural nouns for collections, the HTTP verb carrying the action, not the URL (avoid /getUser or /deleteUser) — this convention is old, well understood, and worth following even when you could invent something "better."

Versioning from day one

GET /v1/users/42

Adding a version prefix before you have any consumers costs nothing. Adding it after you have consumers who depend on unversioned responses means every future breaking change is now a painful, coordinated migration instead of a simple /v2 rollout alongside the existing one.

A consistent error shape

{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Email is required",
    "field": "email"
  }
}

Every error response using the same structure means client code can handle errors generically, rather than writing custom parsing logic per endpoint. A machine-readable code alongside the human-readable message lets clients branch on logic without string-matching the message text, which can change wording without warning.

Pagination that doesn't break at scale

GET /users?cursor=eyJpZCI6NDJ9&limit=50

Offset-based pagination (?page=3) seems simpler but degrades badly on large, frequently-changing datasets — items shift between pages as data changes underneath the request. Cursor-based pagination stays correct regardless of concurrent writes, at the cost of not supporting "jump to page 10" directly.

Never break a published API silently. If a field's meaning or type must change, that's a new version, a new field name, or a deprecation period with advance notice — not a quiet change to an existing field that every current consumer is already depending on.

Document the contract, not just the endpoint list

Good API docs specify required vs. optional fields, exact types, what happens on invalid input, and rate limits — the things a consumer actually needs to build against confidently, not just a list of URLs with a one-line description each.

Comments