API contract hardening — zod everywhere, error envelope, pagination, versioning #179

Closed
opened 2026-06-20 15:43:52 +00:00 by james · 0 comments
Owner

Bring every API route under the OpenAPI/zod contract: convert remaining hand-rolled DTO parsers to zod, agree on a single error envelope, codify pagination and filtering conventions, and decide the versioning strategy.

This is the API side of "strong API contracts are paramount." The spec is only as good as the schemas it generates from.

Scope

  • Convert lib/dto/user.ts and lib/dto/settings.ts (the hand-rolled parsers called out in CLAUDE.md) to zod schemas.
  • Adopt a single error envelope — recommend RFC 7807 Problem Details (type, title, status, detail, instance) — and route every existing API error through it.
  • Pagination: settle on cursor or page/limit (recommend cursor for stability under writes); apply across list endpoints.
  • Sort/filter: agree on a query-string grammar (?sort=-created_at, ?filter[status]=open); document it in ADR-0027 §API conventions.
  • Versioning: decide URL-prefix (/api/v1/...) vs. header (Accept: application/vnd.carol.v1+json) and ship the chosen form.
  • Document all of the above in docs/api-conventions.md; link from CLAUDE.md.

Acceptance criteria

  • Every authenticated route's request and response is a zod schema.
  • Every error response is a Problem Details document.
  • List endpoints return paginated responses using the agreed shape; tests cover both DB engines.
  • Versioning is enforced (route prefix or header), with the convention documented.
  • docs/api-conventions.md exists and is linked from CLAUDE.md.

Out of scope

  • Generating the OpenAPI spec (its own ticket).
  • Client-side migration (its own ticket).

Composes with

OpenAPI spec generation, Generated typed API client, Token-based auth, ADR-0027.

Part of

#176

Bring every API route under the OpenAPI/zod contract: convert remaining hand-rolled DTO parsers to zod, agree on a single error envelope, codify pagination and filtering conventions, and decide the versioning strategy. This is the API side of "strong API contracts are paramount." The spec is only as good as the schemas it generates from. ## Scope - Convert `lib/dto/user.ts` and `lib/dto/settings.ts` (the hand-rolled parsers called out in CLAUDE.md) to zod schemas. - Adopt a single error envelope — recommend **RFC 7807 Problem Details** (`type`, `title`, `status`, `detail`, `instance`) — and route every existing API error through it. - Pagination: settle on cursor or page/limit (recommend cursor for stability under writes); apply across list endpoints. - Sort/filter: agree on a query-string grammar (`?sort=-created_at`, `?filter[status]=open`); document it in ADR-0027 §API conventions. - Versioning: decide URL-prefix (`/api/v1/...`) vs. header (`Accept: application/vnd.carol.v1+json`) and ship the chosen form. - Document all of the above in `docs/api-conventions.md`; link from CLAUDE.md. ## Acceptance criteria - [ ] Every authenticated route's request and response is a zod schema. - [ ] Every error response is a Problem Details document. - [ ] List endpoints return paginated responses using the agreed shape; tests cover both DB engines. - [ ] Versioning is enforced (route prefix or header), with the convention documented. - [ ] `docs/api-conventions.md` exists and is linked from CLAUDE.md. ## Out of scope - Generating the OpenAPI spec (its own ticket). - Client-side migration (its own ticket). ## Composes with OpenAPI spec generation, Generated typed API client, Token-based auth, ADR-0027. ## Part of #176
james closed this issue 2026-06-20 17:35:50 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
james/carol#179
No description provided.