# HTTP API и ошибки ## Источник контракта Backend генерирует OpenAPI из собственного публичного API. Frontend использует производное описание контракта и типизированный клиент. Изменения проходят [contract workflow](../development/runtime-openapi-verification.md). API имеет prefix `/api/v1`; Swagger публикуется для локальной разработки по environment policy, а не используется frontend в runtime. ## Validation и identity Backend преобразует и проверяет входные данные на общей HTTP-границе. Неизвестные свойства запроса удаляются; сам факт их передачи не обещает отказа. Проверка формата не заменяет бизнес-ограничения и проверку доступа к счёту. Аутентификация подтверждает личность пользователя; accountId из URL сам по себе не доказывает доступ к брокерским данным. ## Error contract Общая граница обработки HTTP-ошибок возвращает `application/problem+json` со `status` и публичным `code`. Неожиданный exception возвращает `500` / `INTERNAL_SERVER_ERROR`, без исходного message/stack. Типичный ответ: ```json { "status": 401, "code": "UNAUTHORIZED" } ``` Для input validation контракт требует `400`, `VALIDATION_ERROR` и `errors` как массив `{ pointer, detail }`, где pointer адресует поле запроса. Это требование не считается проверенным одним описанием OpenAPI: нужна проверка реального HTTP-ответа после всех стадий обработки запроса. **Известное расхождение:** согласованная [спецификация аутентификации](../../specs/openspec/specs/user-authentication/spec.md#requirement-стандартные-ответы-об-ошибках) требует `pointer` и `detail` для невалидных полей. В текущей конфигурации валидация формирует строковые сообщения, а фильтр ожидает структурированные ошибки полей; поэтому корректность деталей `errors` не подтверждена. Исправление требует отдельного изменения реализации и проверки полного HTTP-потока. OpenAPI сам по себе этого расхождения не устраняет. Ответ не включает автоматически все поля RFC (`type`, `title`, `instance`). Добавление обязательного поля является изменением публичного контракта. Клиент выбирает поведение по публичному коду, а не по внутреннему тексту ошибки. ## Domain errors и auth Специальный code определяется сценарием; общее преобразование ошибок и безопасная форма ответа принадлежат HTTP-границе. Auth endpoints используют свои status и cookie operations: [Authentication](../domains/authentication/overview.md). T-Bank token failure и временная недоступность имеют разные значения: [Connection API](../integrations/tbank.md#состояние-и-ошибки). Raw upstream/Prisma errors и secrets не передаются frontend. ## Граница доказательства Сравнение OpenAPI подтверждает согласованность схем, а не результат каждого запроса. Безопасная обработка неожиданной ошибки проверяется отдельно. Валидация, доступ, статусы и cookie требуют проверки полного HTTP-потока; атомарность хранения — проверки с изолированной реальной базой. Известное ограничение сквозных проверок описано в [проверке backend](../development/verification.md). ## Наблюдаемость Backend пишет структурированные JSON-события в stdout через Pino. Обработка HTTP-запроса получает серверный request ID, который возвращается заголовком `X-Request-ID`; допустимый входящий идентификатор сохраняется отдельно как client request ID. Это позволяет сопоставить публичную ошибку с обработкой запроса без передачи внутреннего exception в ответ API. Журнал завершения запроса содержит шаблон маршрута, метод, статус, длительность и при наличии публичный error code. События внешней границы добавляют операцию, результат и число попыток. Разрешённые поля ограничены; полные запросы и ответы, token, cookie и Authorization не являются данными журнала. Фильтрация полей и redaction не защищают секрет, вручную включённый в свободный текст сообщения или stack. Выбор logger и граница ответственности описаны в [ADR 008](../adr/008-pino-backend-logging.md); согласованное поведение — в workspace-спецификации [Structured logging](../../specs/openspec/specs/backend-structured-logging/spec.md). Сборщик, срок хранения журналов и alerting не определяются приложением.