API Design First
Write and review the endpoint contract — resources, errors, pagination, versioning — before any handler code exists.
Use when: Use when adding or changing API endpoints, so the contract is designed and reviewed before implementation locks in accidental decisions.
The skill file
Claude Code · SKILL.mdSKILL.md3680 chars
# API Design First
Implementation details leak into contracts when the contract is written last. Design the interface as an artifact (OpenAPI spec, tRPC router signatures, or a markdown contract doc), get it reviewed, then implement against it.
## Step 1 — Write the contract document
For every endpoint, specify before writing handler code:
- Method + path, request shape, response shape with field types and nullability, status codes, auth requirement, and rate-limit class.
- At least one concrete example request/response pair per endpoint. Examples expose bad designs faster than schemas do.
- Walk a consumer scenario end to end ("client creates X, lists X, updates X") using only the contract. If the walkthrough needs information the API doesn't return, the design is incomplete.
## Naming and shape rules
- Resources are plural nouns: `/invoices`, `/invoices/{id}/line-items`. Verbs only for true actions that aren't CRUD: `/invoices/{id}/send`.
- Pick one casing for JSON fields (camelCase or snake_case) and never mix. Match the codebase's existing choice.
- No booleans that will grow a third state — use an enum (`status: "draft" | "sent" | "void"` instead of `isSent`).
- Timestamps are ISO 8601 UTC strings, money is integer minor units plus a currency code, IDs are opaque strings (never expose auto-increment integers in new APIs).
- Don't return different shapes from the same endpoint based on input. Variants belong in a discriminated union with an explicit `type` field.
## Errors
- Define the error envelope once and use it everywhere: `{ "error": { "code": "invoice_already_sent", "message": "...", "details": {...} } }`. Machine-readable `code` is the contract; `message` is for humans and may change.
- Map deliberately: 400 malformed input, 401 unauthenticated, 403 unauthorized, 404 missing (also for resources the caller can't know exist), 409 state conflict, 422 semantically invalid, 429 throttled. Reserve 500 for actual bugs — never return 500 for predictable conditions.
- Validation errors list *all* failures in `details`, not just the first. Clients hate fix-one-resubmit loops.
- Write the error cases into the contract with the same rigor as success cases. Every 4xx an endpoint can return is part of its signature.
## Pagination, filtering, ordering
- Every collection endpoint paginates from day one — retrofitting breaks clients. Default and max page sizes are stated in the contract.
- Prefer cursor pagination (`?cursor=...&limit=50`, response carries `nextCursor: string | null`) for anything that grows; offset pagination drifts under concurrent writes.
- Filters are explicit query params with documented semantics. Reject unknown params with a 400 rather than ignoring them — silent ignoring hides client typos forever.
## Versioning and evolution
- Additive changes (new optional field, new endpoint) need no version bump. Breaking changes (removing/renaming a field, changing a type, tightening validation) need a new version or a deprecation cycle — never a silent change.
- State the deprecation policy in the contract: how breakage is announced, the sunset window, and how callers detect it (e.g. a `Deprecation` header).
- Plan for unknown fields: clients must ignore fields they don't recognize; document this so future additions stay non-breaking.
## Before implementing
- [ ] Contract reviewed by at least one consumer of the API (or by walking their use case yourself).
- [ ] Every endpoint has examples, error cases, auth requirement, and pagination defined.
- [ ] Names checked against existing endpoints for consistency.
- [ ] Implementation tests assert against the contract's examples, so drift fails CI.
Install
drop into your repoSave this to your project or home directory so Claude Code can load it.
path~/.claude/skills/api-design-first/SKILL.md
Discussion
What people are saying
Forks
0 forks of this skillLoading forks…