Skip to content
OpenAgentsbeta
text
1# API Design Review
2
3Review in this order. It is roughly the order of how expensive each mistake is to fix
4once a client depends on it.
5
6## 1. The model
7
8Get this wrong and nothing downstream saves you.
9
10- **Do the resources match how users think, or how the database is arranged?** These are
11 frequently not the same. The API is a contract with a client, not a view of your
12 schema.
13- **Is the grain right?** One call per screen is chatty. One call that returns
14 everything is a coupling nobody can evolve.
15- **Are relationships expressed consistently?** Nested paths, or ids and a second call.
16 Pick one and hold it.
17
18## 2. Naming
19
20Permanent, and free to get right now.
21
22- Consistent case, one convention, everywhere. Do not mix `userId` and `user_id`.
23- Plural collections, singular members. `/users`, `/users/{id}`.
24- No verbs in resource paths. The method is the verb.
25- Names that will still be true later. `email` outlives `emailAddress2`.
26- Booleans named for the positive: `enabled`, not `disabled`, and never `notDisabled`.
27
28## 3. Errors
29
30The most-skipped part of API design and the one clients complain about most.
31
32- **Every error has a stable machine-readable code**, distinct from the HTTP status.
33 Clients must not branch on the human-readable message.
34- **The message says what to do about it**, not just what went wrong.
35- **Validation errors name the field.** One error per bad field, not a sentence listing
36 them.
37- **Status codes are used correctly:** 400 malformed, 401 unauthenticated, 403
38 authenticated but not permitted, 404 absent, 409 conflicts with current state, 422
39 well-formed but semantically invalid, 429 rate limited with a `Retry-After`.
40- **No 200 with an error body.** That breaks every generic client.
41- **Errors never leak internals.** No stack traces, no SQL, no internal hostnames.
42
43## 4. Collections
44
45- **Pagination exists from day one**, even when the list is short today. Adding it later
46 is a breaking change.
47- **Cursor-based, not offset-based**, for anything that can change while a client pages.
48- **A documented maximum page size**, enforced.
49- **Filtering and sorting are explicit and finite.** An open query language is an API you
50 can never change.
51- **The response envelope is consistent**: items plus pagination metadata, the same
52 shape on every collection.
53
54## 5. Evolution
55
56Decide now how this changes later.
57
58- **How is a breaking change delivered?** Version in the path, in a header, or never.
59 Whatever the answer, write it down before the first client integrates.
60- **Which fields are required?** Every required field is permanent. Optional with a
61 sensible default is nearly always the better call.
62- **Are enums closed?** A client that switches exhaustively on your enum breaks when you
63 add a value. Say in the docs whether values may be added.
64- **Additive changes must be safe.** Clients ignore unknown fields, and you never
65 repurpose an existing one.
66
67## 6. Everything else that becomes permanent
68
69- Timestamps: ISO 8601, UTC, with an offset. Never a bare local time, never epoch
70 seconds where milliseconds might later be needed.
71- Money: integer minor units plus a currency code. Never a float.
72- Identifiers: opaque strings. A client should never parse one, and a numeric id
73 encourages exactly that.
74- Nullability: distinguish "absent" from "explicitly null" and document which you mean.
75- Idempotency: any unsafe method a client may retry needs an idempotency key.
76- Rate limits: documented, with headers a client can read before hitting them.
77
78## Reporting
79
80Group findings by cost to fix later, not by severity today. Lead with anything that
81becomes permanent the moment a client integrates, because that is the only window to
82change it for free.
83

Keyboard shortcuts

Focus search
/
Go to Explore
ge
Go to Home
gh
Go to Tags
gt
Go to Collections
gc
Show this help
?
Close suggestions or this dialog
Esc