Fundamentalsprinciplesconsistencyleast surprisedefaults

Design Principles Without Commandments

Consistency, predictability, explicitness, least surprise, good defaults, bounded operations. Principles earn their place as tie-breakers and review questions — not as absolutes that override a requirement.

Follow the failure

Frame the contract

API design starts with a consumer, a design question and a guarantee — never with a URL.

Design question
When two designs both satisfy the requirement, which one will consumers predict correctly without reading the docs?
Consumers
Every developer who integrates the API after the first — the audience for whom consistency is a feature, because their real question is "does this work like the last endpoint I used?"
The promise
An API whose parts follow shared conventions lets a consumer learn one endpoint and correctly guess the next ten — pagination, errors, naming and defaults included.
RequirementConsumersResource ModelStyleContractValidationAuthorizationErrorsIdempotencyPaginationVersioningObservabilityEvolutionTrade-offs

The principles, and what each one buys

Principles are compressed experience, and they compress well because most API mistakes are repeated ones. But a principle applied against a requirement is just dogma with better branding — the skill is knowing what each principle protects, so you can tell when it applies.

The test for every principle below is the same: it should win *ties*. When the requirement genuinely does not care, follow the convention. When the requirement does care, the requirement wins, and the deviation gets documented as deliberate (see What an API Contract Actually Is).

  • Consistency — same concepts, same names, same shapes everywhere. Buys transfer learning: one endpoint teaches the next. Violated by user_id here and userId there (see One Vocabulary: Naming and Consistency).
  • Predictability — similar operations behave similarly, including in failure. Buys correct consumer guesses under pressure.
  • Explicitness — guarantees, defaults and limits are stated, not implied. Buys survivable evolution (silent behavior becomes load-bearing).
  • Least surprise — the obvious reading of the contract is the true one. A GET that mutates is the canonical violation (see GET: The Promise of Safety).
  • Good defaults — the zero-config call does something safe and bounded. Buys a gentle learning curve without hiding sharp edges.
  • Bounded operations — every list paginates, every payload has a limit, every call has a deadline. Buys survival at sizes you have not seen yet (see Unbounded Collections: The Anti-Pattern With a Fuse).
  • Clear ownership — every surface has an accountable owner (see API Ownership and the Catalog).

Consistency is the compound-interest principle

If you keep only one principle, keep consistency, because it multiplies the value of every other decision. A mediocre pagination convention applied uniformly beats an excellent one applied to a third of endpoints: consumers write one pagination helper, one error handler, one retry wrapper, and reuse them everywhere. The API's learnability *is* the consistency of its conventions.

Consistency is also the principle most under attack, because it dies by a thousand locally-reasonable decisions — this endpoint's data "naturally" fits a different envelope; that team prefers a different timestamp format. The defense is written conventions plus review: a short style sheet (naming, envelopes, errors, pagination, timestamps, ids) and a linter or checklist that makes deviation a decision instead of an accident (this is what the review lab's linter checks).

The limit case matters too: consistency with a bad convention is still a cost. When a convention proves harmful, change it deliberately, version the change, and migrate — do not let the API fork into "old style" and "new style" endpoints with no map of which is which.

Locally reasonable, globally incoherent
1GET /users?page=2&per_page=50
2→ { "data": [...], "meta": { "total": 913 } }
3
4GET /orders?offset=100&limit=50
5→ { "orders": [...], "count": 913 }
6
7GET /invoices?cursor=abc
8→ { "items": [...], "next": "def" }
9# three list endpoints, three pagination dialects,
10# three client helpers to write and maintain
One convention, learned once
1GET /users?cursor=abc&limit=50
2GET /orders?cursor=abc&limit=50
3GET /invoices?cursor=abc&limit=50
4→ {
5 "data": [ ... ],
6 "next_cursor": "def" | null
7}
8# one helper paginates every collection in the API

Neither dialect on the left is wrong in isolation. The cost is the aggregate: every consumer pays the learning and maintenance tax for every dialect, forever.

When principles collide, requirements referee

Real designs put principles in tension. Explicitness says "make the client state the page size"; good defaults say "work without it". Least surprise says "DELETE deletes"; a compliance requirement says deletion is a 30-day reversible process. Consistency says "every list paginates the same way"; one collection is capped at ten items by domain rule and pagination there is noise.

These are not paradoxes; they are unfinished requirement questions. The compliance case is not "violating least surprise" — the surprise was in pretending deletion is instant when the requirement says otherwise; the honest contract models the process (see DELETE: What Does Gone Mean? and Resources Have State Machines). Principles frame the debate; the requirement, made explicit, resolves it. What is *not* acceptable is resolving the tension silently and differently on every endpoint.

Key points

  • Principles win ties between designs that both satisfy the requirement; they never override the requirement itself.
  • Consistency compounds: one convention learned is every endpoint half-learned. Guard it with a written style sheet and review.
  • Explicitness and bounded operations are the principles that pay at scale — silence and unboundedness both become load-bearing.
  • Principle collisions are unfinished requirement questions; make the requirement explicit and it referees.
  • Deviations are allowed — as documented decisions, not accidents.

Follow the failure

How the contract fails or gets misused, hop by hop — and what it costs when it completes.

  1. 1
    Team → endpoints: each engineer ships locally reasonable choices; no shared conventions exist.
  2. 2
    API → consumers: every endpoint has its own naming, envelope and pagination dialect.
  3. 3
    Consumers → SDKs: clients accrete special cases per endpoint; the API is "documented" by its quirks.
  4. 4
    New team member → API: extends the wrong pattern (there are four to choose from); the fork deepens.
  5. 5
    Team → cleanup: a "consistency pass" is proposed and rejected — by now it would break every consumer at once.
What breaks
  • Learnability: every endpoint must be studied individually; integration time scales with surface size instead of flattening.
  • Client code quality: consumers write N variants of pagination/error/retry handling, each with its own bugs.
  • The provider's own tooling: SDK generation, linting and contract testing all assume conventions that do not hold.

Design, observe, evolve

A contract decision is incomplete until you know how you would notice it failing and how it changes later.

Design the contract
  • • Write the style sheet before the second endpoint: naming, response envelope, error shape, pagination, timestamps, id format.
  • • Enforce mechanically where possible (spec linter in CI) and by review where not; deviation requires a written reason.
  • • Prefer boring convention over local optimality — accept the 90%-good uniform answer.
  • • When a convention must change, change it as a versioned, mapped migration — never by letting new endpoints quietly diverge.
Observe in production
  • • Lint the API spec continuously; convention-drift count per release is a trackable metric.
  • • Watch integration-time and time-to-first-successful-call for new consumers — the practical measure of learnability.
  • • Support tickets asking "how does pagination work *on this endpoint*" indicate dialect drift.
Evolve without breaking
  • • Conventions make additive growth safe: a new endpoint that follows the sheet inherits consumer trust and tooling on day one.
  • • Convention changes are themselves versioned and migrated, with the map ("endpoints on new envelope") kept in the catalog.
What it costs
  • • Conventions reject some locally better designs; the uniform answer is rarely the optimal answer for any single endpoint.
  • • Style sheets and linters are maintenance; unenforced ones are worse than none because they document a fiction.

Misconceptions

Claim
“Principles like "least surprise" are subjective taste.”
Reality
Each principle names a measurable failure: surprise = wrong consumer guesses; inconsistency = per-endpoint learning cost; unboundedness = the incident at 10× data size. Taste is only in the tie-breaks.
Claim
“A good style guide means we do not need design review.”
Reality
Style guides catch shape drift; review catches requirement drift — an endpoint can be perfectly conventional and still answer the wrong question.