feat(rules): rest-api path-scoped rule distilled from agent-skills
Contract-first order, one error envelope + HTTP map, paginated lists, idempotency (key from intent, atomic claim, payload guard, duplicate policy, retention), naming, Hyrum's law. Versioning points to CLAUDE.md § Web APIs — always versioned; the upstream one-version rule is dropped.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
---
|
||||
paths: ["**/api/**", "**/routes/**", "**/controllers/**", "**/*.route.*", "**/*.controller.*", "**/openapi.*", "**/*.openapi.*"]
|
||||
---
|
||||
|
||||
# REST API — contract, errors, lists, idempotency
|
||||
|
||||
## Contract first
|
||||
Order: typed input/output → schemas (server-generated fields like id,
|
||||
createdAt apart from client input) → error codes → implementation.
|
||||
Validate at boundaries only (route handlers, external responses, env
|
||||
loading); trust internal code and your own database reads.
|
||||
|
||||
## Errors
|
||||
One envelope everywhere: `{ error: { code, message, details? } }`.
|
||||
HTTP map: 400 invalid · 401 auth · 403 forbidden · 404 missing ·
|
||||
409 conflict · 422 semantic · 500 server (never leak internals).
|
||||
Never mix throw / null / envelope styles across endpoints.
|
||||
|
||||
## Lists
|
||||
Every list endpoint paginated: `page`, `pageSize`, `totalItems`,
|
||||
`totalPages`. Filters as query params (`?status=x&createdAfter=…`),
|
||||
never in the body.
|
||||
|
||||
## Idempotency
|
||||
Key from intent, not attempt (`charge:v1:${orderId}`, never
|
||||
`randomUUID()` or a timestamp). Claim atomically via a unique
|
||||
constraint — check-then-insert is a race, not a guard. Same key,
|
||||
different payload: fail loudly, never replay the first response.
|
||||
Pick the in-flight-duplicate policy on purpose: 409 reject, bounded
|
||||
wait, or 202 + status URL. Retention outlives the longest retry
|
||||
path, dead-letter replay included.
|
||||
|
||||
## Naming
|
||||
Plural nouns for endpoints (`/api/tasks`), no verbs. camelCase query
|
||||
params and response fields. UPPER_SNAKE enum values. Boolean fields
|
||||
prefixed is/has/can.
|
||||
|
||||
## Hyrum's law
|
||||
Every observable behavior — undocumented quirks, error text, timing —
|
||||
becomes a de facto contract once someone depends on it.
|
||||
|
||||
## Versioning
|
||||
CLAUDE.md § Web APIs — always versioned. Not repeated here.
|
||||
Reference in New Issue
Block a user