REST API как проверяемый договор
Практический чеклист по контракту REST API: что согласовать по данным, ответам, ошибкам, повторам и безопасности и как превратить договоренности в критерии приемки.
Когда нужен этот материал
Этот чеклист нужен перед стартом интеграции, когда уже понятно, какие системы должны обмениваться данными, но еще не согласованы границы ответственности, ответы, ошибки, безопасность и правила изменения REST API.
Его цель — не заменить OpenAPI, Swagger или техническую документацию, а превратить их в договоренности, которые одинаково понимают поставщик API, потребитель и тот, кто будет принимать результат.
Почему API — это договор
Список эндпоинтов и полей еще не объясняет, как две системы должны вести себя вместе. Проверяемый контракт отвечает не только на вопрос «какой JSON отправить», но и на более дорогие вопросы:
- кто отвечает за данные и результат операции;
- что означает успешный ответ и можно ли считать операцию завершенной;
- как отличить ошибку данных от временной технической ошибки;
- что произойдет при таймауте или повторном запросе;
- какой результат увидят пользователь, оператор и поддержка;
- какие изменения потребитель обязан выдержать, а какие считаются ломающими.
Договоренность становится проверяемой, когда для нее можно подготовить запрос, назвать ожидаемый ответ и увидеть результат в интерфейсе, статусе или журнале. Если проверить ее нельзя, стороны пока договорились только на словах.
Короткий чеклист
Перед разработкой нужно уметь ответить на такие вопросы:
- Для чего существует API и где заканчивается ответственность каждой стороны?
- Какие сценарии считаются основными, а какие — исключениями?
- Какие данные передаются, кто является их источником истины и где они хранятся?
- Как выглядят успешные ответы, ошибки, повторные вызовы и таймауты?
- Какие требования есть к авторизации, аудиту, логированию и чувствительным данным?
- Как будут меняться контракты без поломки текущих потребителей?
- Как команда поймет, что интеграция готова к MVP или production-включению?
Паспорт одного сценария
Необязательно сразу описывать весь API. Для начала возьмите один бизнес-сценарий и заполните короткий паспорт:
| Что фиксируем | Вопрос для команды |
|---|---|
| Назначение | Какую работу выполняет сценарий и что остается за его границей? |
| Участники | Кто вызывает API, кто обрабатывает запрос и кто принимает результат? |
| Метод и ресурс | Какой метод и URL выражают действие над ресурсом? |
| Входные данные | Какие поля обязательны, откуда они берутся и кто отвечает за их корректность? |
| Успешный ответ | Какой HTTP-статус, тело ответа и состояние операции означают успех? |
| Ошибки | Какие коды возвращаются, что они означают и какие из них можно повторять? |
| Повтор | Что произойдет при том же запросе после таймаута или повторного клика? |
| Наблюдаемость | Где видны статус, причина ошибки и идентификатор для диагностики? |
| Доступ и данные | Кто имеет право вызвать API и что нельзя писать в логи? |
| Совместимость | Какие изменения допустимы без новой версии, а какие сломают потребителя? |
| Граница первой версии | Что входит в приемку сейчас, а что остается ручным или отложенным? |
Такой паспорт не заменяет спецификацию. Он связывает спецификацию с реальным сценарием, ответственностью сторон и приемкой.
1. Назначение и границы ответственности
Сначала стоит зафиксировать не поля запроса, а смысл API:
- какую бизнес-задачу закрывает интеграция;
- какая система инициирует обмен;
- какая система является источником истины для ключевых данных;
- что API делает сам, а что остается на стороне потребителя;
- какие действия нельзя выполнять через этот API.
Хорошая формулировка границы помогает не превратить интеграцию в неявный общий модуль, где каждая сторона ожидает, что другая “сама догадается”.
2. Сценарии и нештатные ситуации
Для каждого основного сценария полезно описать:
- стартовое событие или пользовательское действие;
- обязательные входные данные;
- ожидаемый результат;
- допустимое время ответа;
- что происходит при частичном отказе;
- как пользователь или оператор узнает статус.
Отдельно стоит выписать нештатные ситуации: недоступность внешнего сервиса, повторный запрос, некорректные данные, истекший сертификат, просроченный токен, дубль операции, несовпадение статусов между системами.
3. Контракты запросов, ответов и ошибок
Минимальный контракт должен отвечать на вопросы:
- какие поля обязательны, а какие опциональны;
- какие форматы дат, идентификаторов, сумм и статусов используются;
- какие ограничения есть на длину, кодировку и допустимые значения;
- какие ошибки возвращаются как бизнес-ошибки, а какие как технические;
- есть ли единый формат error response;
- можно ли безопасно повторять запрос;
- есть ли idempotency key или другой способ защититься от дублей.
Если API использует XML, подписи, сертификаты или нестандартные форматы, это лучше вынести в отдельную проверку до привязки к основной бизнес-логике.
4. Совместимость и изменения
До разработки нужно договориться, что считается breaking change. Например:
- удаление поля;
- изменение типа поля;
- изменение обязательности;
- новое значение enum без готовности потребителя;
- изменение семантики статуса;
- изменение правил подписи, авторизации или проверки сертификата.
Полезно заранее определить:
- как версионируется API;
- сколько живет старая версия;
- как уведомляются потребители;
- как тестируется обратная совместимость;
- какие изменения можно выкатывать без отдельного согласования.
5. Безопасность, аудит и данные
Интеграции часто ломаются не на JSON или XML, а на границах доверия. Перед разработкой нужно явно проговорить:
- кто и как получает доступ к API;
- какие токены, сертификаты или ключи используются;
- где они хранятся и как ротируются;
- какие данные нельзя писать в логи;
- какие события нужно аудитить;
- кто имеет доступ к тестовым и production-данным;
- как обезличиваются примеры для документации и отладки.
Если в интеграции есть персональные, финансовые или другие чувствительные данные, договоренности по логированию и хранению нужно принимать до первого production-запроса.
6. Готовность к MVP
MVP интеграции не обязан закрывать все будущие сценарии, но должен иметь понятные критерии готовности:
- основной happy path проходит на тестовом контуре;
- ошибки и таймауты диагностируются, а не выглядят как “что-то не работает”;
- есть минимальный набор тестовых данных;
- известны ограничения первой версии;
- понятно, какие ручные операции остаются после запуска;
- есть план мониторинга и поддержки после включения.
Для сложных внешних интеграций полезно сначала собрать проверочный контур: транспорт, авторизация, формат сообщения, подпись, отправка запроса, получение ответа, обработка ошибки. Только после этого стоит связывать обмен с основной продуктовой логикой.
Пример контракта: запуск внешней проверки
Ниже полностью вымышленный пример. Идентификаторы, ресурс и поведение не относятся к реальной системе — они нужны, чтобы показать форму проверяемого договора.
Сервис заявок передает запрос в сервис проверок:
POST /verification-requests
Idempotency-Key: verify-app-42-v1
X-Correlation-Id: corr-2026-42
Content-Type: application/json
{
"applicationId": "app-42",
"subjectId": "subject-17",
"consentId": "consent-9"
}
Минимальные договоренности по этому сценарию:
| Часть контракта | Договоренность |
|---|---|
| Ответственность | Сервис заявок отвечает за заявку и действующее согласие; сервис проверок — за состояние проверки и связь с внешним контуром. |
| Принятие запроса | Валидный запрос возвращает 202 Accepted, потому что проверка продолжается асинхронно. |
| Тело ответа | Ответ содержит стабильный operationId и начальный статус pending. |
| Повтор | Тот же запрос с тем же Idempotency-Key возвращает тот же operationId и не запускает вторую проверку. |
| Конфликт | Тот же ключ с другим телом возвращает 409 IDEMPOTENCY_CONFLICT. |
| Данные | Отсутствующее или просроченное согласие возвращает 422 CONSENT_REQUIRED; внешний вызов не выполняется. |
| Временный отказ | Если сервис не может принять запрос, он возвращает 503 TEMPORARILY_UNAVAILABLE и признак retryable: true. |
| Диагностика | Каждый ответ содержит correlationId; токены и персональные атрибуты не попадают в текст ошибки и журнал. |
| Статус | GET /verification-requests/{operationId} возвращает только согласованные состояния и понятную причину остановки. |
| Совместимость | Новое опциональное поле допустимо; удаление поля, смена типа или смысла статуса считается ломающим изменением. |
Пример ответа на принятый запрос:
HTTP/1.1 202 Accepted
Content-Type: application/json
{
"operationId": "op-781",
"status": "pending",
"correlationId": "corr-2026-42"
}
Пример предметного отказа:
HTTP/1.1 422 Unprocessable Content
Content-Type: application/json
{
"code": "CONSENT_REQUIRED",
"message": "Для проверки требуется действующее согласие",
"retryable": false,
"correlationId": "corr-2026-42"
}
В реальной работе рядом с этим описанием нужны OpenAPI-схема, правила авторизации, перечень состояний и тестовые данные. Но уже такой пример позволяет обсуждать не названия полей, а поведение системы.
Как проверить пример на приемке
Из контракта получаются конкретные проверки:
| Сценарий | Проверяемый результат |
|---|---|
| Валидный запрос | API возвращает 202, operationId, pending и переданный correlationId. |
| Точный повтор | Запрос с тем же ключом и телом возвращает прежний operationId; вторая проверка не появляется. |
| Конфликт повторов | Тот же ключ с другим телом возвращает 409 IDEMPOTENCY_CONFLICT. |
| Нет действующего согласия | API возвращает 422 CONSENT_REQUIRED, внешний вызов не выполняется. |
| Временная недоступность | API возвращает диагностируемый 503 с retryable: true; потребитель не повторяет запрос бесконечно. |
| Безопасность и диагностика | По correlationId можно связать запрос и ответ, но в логах нет токена и персональных атрибутов. |
| Несогласованное состояние | API не возвращает значение статуса, которого нет в контракте; изменение набора статусов проходит отдельную проверку совместимости. |
Теперь фраза «интеграция готова» означает не наличие эндпоинта, а прохождение согласованного набора наблюдаемых проверок.
Как довести договоренности до приемки
Чеклист по API не должен оставаться списком вопросов. После согласования границ нужно перевести ключевые договоренности в критерии приемки:
| Что зафиксировали | Как проверить |
|---|---|
| Основной сценарий и ответственность систем | Happy path с понятным результатом и владельцем |
| Данные и источник истины | Набор тестовых данных, обязательные поля и спорные значения |
| Ошибки, таймауты и повторы | Критерии для технических ошибок, предметных отказов и повторных запросов |
| Авторизация, аудит и логи | Проверка доступа, маскирования данных и correlation id |
| Граница MVP | Явный список того, что входит, что остается ручным и что не проверяется в первой версии |
Если договоренность нельзя проверить, она еще слишком общая. Следующий шаг — сформулировать ее как критерий приемки: при каком условии проверяем, что происходит и какой результат должен быть виден.
Как использовать
Перед стартом разработки можно пройтись по этому чеклисту вместе с разработчиком, аналитиком, тимлидом и владельцем процесса. На выходе должны появиться не идеальные документы, а паспорт хотя бы одного сценария, список закрытых договоренностей, открытых вопросов и технических гипотез для проверки.
Если ответ на вопрос неизвестен, это не провал. Это сигнал, что неизвестное место нужно вынести в отдельную задачу, spike, решение или риск.