Короткий ответ
Нужно вводить изменения контракта только обратно совместимым образом (добавление новых необязательных полей, новых эндпоинтов, без удаления/переименования существующих без периода параллельной поддержки) и проверять совместимость автоматически в CI через consumer-driven contract-тесты (например, Pact), которые падают до релиза, если новая версия API сервиса B не удовлетворяет ожиданиям, зафиксированным сервисом A как потребителем.
Как это работает подробнее
consumer-driven contract testing — потребитель (сервис A) публикует «контракт» с описанием, какие конкретно запросы и ожидаемые ответы ему нужны от поставщика (сервиса B); пайплайн сервиса B перед релизом проверяет новую версию API против всех известных контрактов потребителей, не требуя разворачивать весь стек сервисов для end-to-end теста.
Пример кода
// Pact-контракт, опубликованный сервисом A (потребитель) для сервиса B (поставщик)
{
"request": {"method": "GET", "path": "/orders/123"},
"response": {
"status": 200,
"body": {"id": 123, "status": "shipped", "total_cents": 4599}
}
}Что использовать на практике
- На практике. это дешевле и быстрее полноценных end-to-end тестов между сервисами и даёт раннюю обратную связь именно на этапе CI сервиса-поставщика, до того как несовместимое изменение попадёт в прод. Параллельно важна версионированная поддержка API (например, `/v1/` и `/v2/` эндпоинты одновременно на переходный период) для случаев, когда обратная совместимость в принципе невозможна.
- Пример. Ожидаемое поведение: если в пайплайне сервиса B новая версия API вернёт поле `total` вместо `total_cents`, pact-verification шаг падает ещё до деплоя, явно показывая, какой контракт нарушен и каким потребителем он был опубликован.
Подводные камни
- Частые ошибки. меняют формат ответа существующего эндпоинта «по-тихому», полагая, что раз «внутренний» сервис — то можно координировать изменение устно, без автоматической проверки; не версионируют API вообще, из-за чего любое изменение контракта становится потенциально ломающим для всех потребителей одновременно.