Ошибки API: что контракт обещает кроме happy path
Практический чеклист для интеграций: как заранее описать ошибки API, диагностику, повторы, пользовательские сообщения и действия поддержки.
Зачем отдельно описывать ошибки
Happy path показывает, что интеграция может пройти успешно. Но рабочая интеграция начинается там, где команда понимает отказ: почему он случился, можно ли повторить запрос, что увидит пользователь, что увидит поддержка и какой статус останется в системе.
Если ошибки не описаны в контракте, каждый сбой превращается в разбор по месту. Разработчик видит код ответа, аналитик ищет смысл, продукт пытается понять влияние на пользователя, а поддержка получает слишком общий текст.
Что должно быть в контракте ошибки
Минимальный контракт ошибки должен отвечать на вопросы:
- ошибка техническая или предметная;
- является ли она финальным результатом или временным состоянием;
- можно ли безопасно повторить запрос;
- что должно попасть в лог, аудит и мониторинг;
- какой код или причина будут доступны поддержке;
- какое сообщение можно показать пользователю;
- какой следующий шаг у системы, оператора или команды.
Формат можно описывать в OpenAPI, Swagger, AsyncAPI или внутренней технической заметке. Важнее не инструмент, а проверяемая договоренность: одинаковая ошибка должна одинаково трактоваться всеми участниками.
1. Классификация ошибок
До разработки полезно разделить ошибки на группы:
- транспорт: внешний контур недоступен, соединение оборвалось, истек таймаут;
- авторизация и доверие: неверный токен, сертификат, подпись, scope или субъект доступа;
- формат: сообщение не проходит схему, обязательное поле отсутствует, тип данных не совпадает;
- данные: источник истины не содержит нужных сведений или данные противоречат правилу;
- бизнес-отказ: внешний контур принял запрос, но отказал по предметной причине;
- ограничение: превышена квота, лимит, окно доступности или правило обработки;
- внутренняя ошибка: запрос не может быть обработан из-за сбоя на своей стороне.
Такая классификация помогает не прятать разные причины под одним ответом “ошибка интеграции”.
2. Поля, которые помогают диагностировать
Для внешней интеграции полезно заранее договориться о наборе полей в ошибке:
- стабильный код ошибки;
- человекочитаемое описание для команды или поддержки;
- correlation id или request id;
- внешний идентификатор операции, если он уже появился;
- признак retryable / non-retryable;
- источник ошибки: наша система, внешний контур, транспорт, данные, авторизация;
- технические детали, которые можно хранить без раскрытия чувствительных данных.
Не все поля должны уходить пользователю. Контракт ошибки может иметь разные уровни: технический ответ API, внутреннюю запись события, сообщение для оператора и короткое пользовательское объяснение.
3. Повторы и финальность
Для каждой группы ошибок нужно решить, что делает система:
- повторяет автоматически;
- ставит запрос в ожидание;
- переводит в ручной разбор;
- завершает процесс предметным отказом;
- останавливает сценарий до исправления данных;
- сигнализирует команде о проблеме контура.
Самая опасная зона - таймаут. Он не доказывает, что внешняя сторона не обработала запрос. Поэтому таймаут нельзя считать обычной ошибкой без отдельного правила: как проверить статус, как повторить безопасно и как защититься от дубля.
sequenceDiagram
participant API as API
participant Classifier as Классификация
participant Process as Процесс
participant Support as Поддержка
API->>Classifier: ошибка интеграции
Classifier->>Classifier: тип и финальность
alt можно повторить
Classifier->>Process: retry_scheduled
Process-->>API: повтор после правила
else предметный отказ
Classifier->>Process: business_rejected
Process-->>Support: причина и id
else нужен разбор
Classifier->>Process: manual_review
Process-->>Support: контекст и действие
end
4. Сообщения для пользователя и поддержки
Технический текст ошибки редко подходит пользователю. Но слишком общий текст не помогает поддержке.
До разработки стоит разделить:
- пользовательское сообщение: коротко объясняет, что делать дальше;
- операторское сообщение: показывает состояние процесса и допустимое действие;
- техническое сообщение: помогает разработчику или поддержке найти причину;
- аудиторское событие: фиксирует факт, контур, идентификаторы и решение системы.
Если в ошибке есть персональные, финансовые или другие чувствительные данные, их нельзя переносить в публичные примеры, незащищенные логи и скриншоты для обсуждения.
5. Приемка ошибок
Ошибки нужно проверять так же явно, как успешный сценарий. Минимальный набор приемки:
- внешний контур недоступен;
- запрос ушел, но ответ не пришел;
- пришел предметный отказ;
- пришел некорректный формат;
- истекла авторизация или сертификат;
- повторный запрос не создает дубль;
- поддержка видит понятный статус и идентификатор;
- пользователь не получает технические детали.
Если команда не может воспроизвести ошибку в тестовом контуре, ее все равно стоит описать как ожидаемое поведение и проверить через заглушку, контрактный тест или ручную имитацию.
Короткий шаблон
Для каждой важной ошибки заполните пять строк:
| Вопрос | Ответ |
|---|---|
| Что произошло? | Техническая причина или предметный отказ |
| Можно ли повторить? | Да, нет, только после проверки статуса, только вручную |
| Какой статус ставим? | Внутренний статус процесса |
| Кто действует дальше? | Система, оператор, поддержка, команда, внешняя сторона |
| Что показываем наружу? | Пользовательское или операторское сообщение без лишних деталей |
Если хотя бы одна строка остается пустой, ошибка еще не является частью контракта. Значит, ее нужно вынести в открытый вопрос или отдельное решение до начала разработки.