Skip to content

0036. El spec OpenAPI cubre también los responses (DTOs de respuesta en el backend)

Estado

Aceptada — supersede a ADR-0035.

Contexto

ADR-0035 dejó el spec cubriendo solo bodies de request porque los controllers retornaban objetos literales { data, message } (sin DTOs de respuesta), y registró como derivada agregar esos DTOs. Esta tarea (dtos-respuesta-backend) ejecutó esa derivada con un barrido único sobre los 69 endpoints.

Decisión

  • Cada endpoint tipa su data con un DTO de respuesta (@ApiOkResponse/@ApiCreatedResponse ({ type: XDto })), con @ApiProperty igual que los DTOs de request. Los DTOs viven en src/modules/<mod>/dto/<mod>-response.dto.ts; el { deleted: true } de los DELETE usa un DeletedResponseDto compartido en src/common/dto/.
  • El envelope { data, message, statusCode } (ver ADR-0006) no se declara en cada controller: wrapResponsesInEnvelope en camaroneras_backend/src/common/swagger/build-document.ts envuelve cada respuesta 2xx al exportar el spec, moviendo el schema del DTO a properties.data sin mutar el componente compartido en components.schemas (un mismo DTO referenciado por varios endpoints queda intacto). Es idempotente y solo toca respuestas 2xx.
  • Los *-flow.md dejan de documentar a mano las respuestas 2xx (ahora en la API Reference, como los bodies). Conservan las respuestas de error (4xx/5xx con su mensaje de negocio), que el spec no cubre, más las reglas de negocio y el flujo de cliente.

Consecuencias

  • La API Reference (/api/) es fiel para requests y para el shape de las respuestas 2xx, incluido el envelope. injectEnvelopeStatusCode fue reemplazado por wrapResponsesInEnvelope (con tests unitarios en build-document.spec.ts: envelope, no-mutación de componentes compartidos, arrays, idempotencia, ignora 4xx).
  • Casos no estándar detectados y tipados fielmente al comportamiento real (no al ideal): varios POST/PATCH (alimentación, muestreos, raleos, ciclos) devuelven la lista/detalle recalculado del recurso padre, no la fila creada/editada; POST /auth/signin es polimórfico (oneOf sesión activa | pendiente); POST /auth/accept-invitation responde 200 (no 201) por @HttpCode.
  • Derivada de seguridad registrada (no parte de esta tarea): onboarding/accept-invitation/ refresh devuelven refreshToken en el body además de la cookie httpOnly — revisar si es intencional.
  • La convención de camaroneras_docs cambia: "responses a mano" pasa a "solo responses de error a mano" (actualizado en camaroneras_docs/CLAUDE.md y en la nota puntero de cada *-flow.md).