Problem
No endpoint declares a response type. Every handler returns a plain object or a TypeScript interface, which vanishes at runtime, so Swagger emits either no schema or { "type": "object" }. @wantere/api-client therefore returns { [key: string]: unknown } for every call (see listingsControllerFindOneV1200.ts, conversationsControllerStartV1201.ts). The web app follow-ups for #4 will have to hand-write types that already exist in the API, and any drift between the two will go unnoticed until runtime.
Proposal
Adopt one convention for the 24 existing endpoints and every new one:
- Turn each response interface (
ListingSummary, ListingDetail, ConversationView, MessageView, the favorites and notifications shapes, the public profile) into a class with @ApiProperty() decorators. Interfaces cannot be seen by Swagger; classes can.
- Add
@ApiOkResponse({ type: X }) or @ApiCreatedResponse({ type: X }) to every handler. @HttpCode(204) routes get @ApiNoContentResponse().
- Add a small helper for paginated lists, e.g.
ApiPaginatedResponse(ItemDto), that builds the Paginated<T> schema from PageMetaDto so items is typed too.
- Regenerate the client once with
pnpm api:generate and check that packages/api-client/src/generated/models no longer contains { [key: string]: unknown } types.
- Add a CONTRIBUTING note: a new endpoint is not done until its response is declared.
Acceptance criteria
- Every operation in
apps/api/openapi.json has a response schema with named properties.
- The generated client exposes a named type for each response; no
*V1200.ts / *V1201.ts files with unknown maps remain.
- Existing unit and end-to-end tests pass unchanged, since the wire format does not move.
pnpm lint, pnpm typecheck, pnpm build pass.
Out of scope
Changing any response shape. This is declaration only.
Context
Raised while implementing #4 (PR #5). Rough size: one afternoon.
https://claude.ai/code/session_01VGBQpJZopVVa1AWeVsNaWg
Problem
No endpoint declares a response type. Every handler returns a plain object or a TypeScript interface, which vanishes at runtime, so Swagger emits either no schema or
{ "type": "object" }.@wantere/api-clienttherefore returns{ [key: string]: unknown }for every call (seelistingsControllerFindOneV1200.ts,conversationsControllerStartV1201.ts). The web app follow-ups for #4 will have to hand-write types that already exist in the API, and any drift between the two will go unnoticed until runtime.Proposal
Adopt one convention for the 24 existing endpoints and every new one:
ListingSummary,ListingDetail,ConversationView,MessageView, the favorites and notifications shapes, the public profile) into a class with@ApiProperty()decorators. Interfaces cannot be seen by Swagger; classes can.@ApiOkResponse({ type: X })or@ApiCreatedResponse({ type: X })to every handler.@HttpCode(204)routes get@ApiNoContentResponse().ApiPaginatedResponse(ItemDto), that builds thePaginated<T>schema fromPageMetaDtosoitemsis typed too.pnpm api:generateand check thatpackages/api-client/src/generated/modelsno longer contains{ [key: string]: unknown }types.Acceptance criteria
apps/api/openapi.jsonhas a response schema with named properties.*V1200.ts/*V1201.tsfiles withunknownmaps remain.pnpm lint,pnpm typecheck,pnpm buildpass.Out of scope
Changing any response shape. This is declaration only.
Context
Raised while implementing #4 (PR #5). Rough size: one afternoon.
https://claude.ai/code/session_01VGBQpJZopVVa1AWeVsNaWg