# Backend HTTP API ## Выбор boundary Сначала определи, меняется wire contract или только реализация существующего use case. Для route/request/response/status/error shape используй [локальный публичный контракт](#источник-контракта) и configured HTTP tests. | Проверка | Где выполнять | | --- | --- | | Тип/формат/диапазон входа | Runtime DTO class с class-validator/class-transformer | | Согласованность полей, бизнес-ограничение | Feature service/domain helper | | Session и identity | Existing guard/strategy | | Доступ user к конкретному account | Existing access service | | HTTP envelope/безопасная ошибка | Общий HttpExceptionFilter | Controller объявляет contract и делегирует; не обращается напрямую к Prisma/gRPC и не выполняет финансовые расчёты или сложную оркестрацию. Controller вызывает application use case/service. Identity берётся из verified `request.user`, не из body/userId, предоставленного клиентом. Access rules активируют Security. ## DTO и errors DTO — runtime class: TS interface не предоставляет validation metadata. `*.controller.ts` и `*.dto.ts` остаются около HTTP boundary, в root компактного module или presentation. DTO можно передать application boundary при совпадении формы; отдельный Input с теми же полями не нужен. Domain не импортирует DTO: например, чистые денежные расчёты используют `Money`, а Swagger — `MoneyDto`. Нормализованная форма input нужна только при смысловом отличии от wire contract; выбор suffix принадлежит [Architecture](../architecture.md). ValidationPipe уже настроен в `configureApp` (`transform`, `whitelist`). Не обещай rejection неизвестных fields: `forbidNonWhitelisted` не включён. Для query numbers/arrays выбирай явное преобразование и валидаторы, как в [operations DTO](../../src/modules/investments/operations/presentation/brokerage-operation.dto.ts). Swagger metadata описывает те же required/optional/nullable/enum/range значения. Используй типизированные response DTO, `ApiOkResponse`/другой фактический status и существующий `ApiProblemResponses`. Prisma model не является public contract: response выбирает поля явно. Stable codes, RFC 9457 профиль и mapping принадлежат [Errors](error-handling.md). **Безопасный путь:** используй exception и общий filter, а не локальный `res.status(...).json(...)`. Исключение — транспортная операция вроде cookie; следуй существующему auth controller с `passthrough` и явно заданным status. ## Пример и проверка Prefix `/api/v1` задаёт `configureApp`. Route/status/request/response/OpenAPI change — изменение публичного backend contract; несовместимое изменение требует согласованного перехода consumers, а не незаметной правки DTO. Новый API version не вводи для внутреннего refactor. Pagination сохраняет contract endpoint: operations использует opaque cursor, limit и DTO bounds. Не заменяй cursor offset/page и не добавляй global pagination helper ради первого endpoint. Новая pagination явно определяет порядок, границу страницы и end-of-list; reused cursor не должен менять filters/owner. [Operations controller](../../src/modules/investments/operations/presentation/brokerage-operations.controller.ts) показывает guard, user.sub, DTO query и service delegation. Для нового field обновляй Nest DTO/metadata и публикуемый OpenAPI artifact. Потребители получают публичный контракт независимо от внутреннего устройства API. Проверь happy path и применимые invalid input/access/not-found/domain/upstream errors на boundary, где они возникают. Unit вызов controller не запускает pipes, guards или serialization. `npm run test:openapi-contract` проверяет schema parity, но не поведение invalid request; выбирай соответствующий test по [Testing](testing.md). Финальный gate не заменяет semantic review ошибок. ## Источник контракта Nest DTO/controllers/Swagger metadata определяют публичный HTTP API. `npm run openapi:generate` собирает backend и записывает корневой `openapi.json`. Nest preview читает metadata без запуска HTTP-порта, провайдеров, БД и T-Bank; команда не требует deployment environment. Artifact исключён из Git. При изменении API обнови DTO/metadata и выполни генерацию. Потребители получают artifact отдельно; backend не читает их репозитории. `test:openapi-contract` сравнивает вывод генератора с runtime schema configured app во временном каталоге. Проверка подтверждает правильность генерации, но без versioned baseline не выявляет breaking change относительно предыдущего выпуска. Для такого изменения согласуй переход consumers и проверь relevant HTTP behavior. HTTP prefix — `/api/v1`; Swagger доступен согласно `src/config/swagger.config.ts`. Общий error response — `application/problem+json` со `status` и публичным `code`. Validation требует `400 / VALIDATION_ERROR` и `errors: [{ pointer, detail }]`. ValidationPipe сохраняет структурированные field errors без `target/value`, а filter формирует JSON pointers, включая вложенные поля. Schema parity не доказывает правильность `errors`; изменения проверяются через реальный HTTP pipeline.