Сервису требуется изменить несовместимое поле в API, но клиенты обновляются не одновременно. Как организовать переход без принудительного одновременного релиза?
Нужно сохранить старый контракт для существующих клиентов и ввести отдельную версию изменённого контракта. Новую версию следует развивать параллельно, предоставить период миграции, контролировать использование старой версии и удалить её только после согласованного завершения перехода.
API часто используют независимо развиваемые клиенты: мобильные приложения, веб-интерфейсы, партнёрские системы и внутренние сервисы. Их релизы не происходят одновременно, поэтому изменение формата ответа или смысла поля может сломать часть потребителей.
Версионирование появилось как способ управлять эволюцией распределённого контракта. Оно отделяет изменения поставщика API от жизненного цикла клиентов и делает несовместимость явной, а не случайной.
Если заменить поле на месте, старый клиент может не распознать новый формат, неверно интерпретировать значение или завершиться ошибкой при разборе ответа. Особенно опасны изменения типа, обязательности, допустимых значений и семантики поля.
Даже если техническая обработка запроса продолжит работать, клиент может принять корректный с точки зрения сервера ответ за другой смысл. Поэтому совместимость нужно оценивать не только по структуре данных, но и по поведению контракта.
Сначала фиксируют границу несовместимого изменения и определяют новую версию контракта. Версия может быть выражена частью адреса ресурса, заголовком или согласованием формата через заголовки; важно, чтобы способ был единообразным, документированным и проверяемым.
Старая версия продолжает обслуживаться по прежним правилам. Новая версия получает изменённое поле и отдельную спецификацию, а сервер при необходимости преобразует внутреннюю модель данных в представление каждой версии. Внутренняя модель не должна автоматически считаться публичным контрактом.
Переход обычно включает несколько этапов:
Добавление необязательного поля иногда позволяет обойтись без новой версии, если старые клиенты корректно игнорируют неизвестные поля, а изменение не меняет смысл существующих данных. Однако изменение типа, обязательности или семантики поля обычно требует отдельного контракта.
Версионирование увеличивает стоимость сопровождения: некоторое время нужно поддерживать несколько вариантов поведения, документации, тестов и мониторинга. Компромисс состоит в том, чтобы не версионировать каждое расширение, но чётко выделять изменения, нарушающие совместимость.
Платёжный сервис возвращал сумму как целое число в минимальных денежных единицах. Для нового набора валют потребовалось передавать десятичную сумму и код точности. Простая замена типа поля была рискованной: старые мобильные клиенты могли показать неверную сумму.
Рассматривались два варианта. Первый — изменить существующее поле и надеяться на обновление клиентов; это давало быстрый релиз, но создавало неконтролируемый риск неверного отображения денег. Второй — добавить новые поля в старый ответ; это сохраняло старых клиентов, но не решало проблему для клиентов, которые обязаны использовать новую точность, и могло привести к двум противоречащим друг другу представлениям.
Выбрали новую версию контракта с явным форматом суммы, оставив старую версию неизменной. Клиентам предоставили адаптационный период, включили метрики вызовов по версиям и установили критерий отключения старого формата — отсутствие обращений от поддерживаемых потребителей в течение согласованного периода.
Такой подход увеличил объём временной поддержки, но исключил тихое искажение денежных значений. После миграции клиентов старую версию удалили вместе с её документацией и тестами.
Нет. Версия только разделяет контракты, но не определяет процесс перехода. Нужно описать различия, поддерживать старую версию, тестировать каждую версию отдельно, уведомлять потребителей и наблюдать фактическое использование.
Также важно учитывать связанные артефакты: схемы данных, коды ошибок, ограничения полей, авторизацию, документацию и мониторинг. Если новая версия формально доступна, но не покрыта этими элементами, клиент столкнётся с несовместимостью в другой части контракта.
Это зависит от поведения потребителей. Добавление необязательного поля часто совместимо, если клиенты игнорируют неизвестные поля. Но добавление нового обязательного поля, изменение типа, сужение допустимых значений или изменение смысла существующего поля может нарушить работу даже без изменения структуры запроса.
Оценивать совместимость нужно по реальным правилам разбора и использования данных, а не только по сравнению схем. Для критичных контрактов полезны автоматические проверки совместимости схем и контрактные тесты с представителями потребителей.
Сначала нужно определить владельца потребителя и выяснить причину задержки. Отключение без оценки последствий допустимо только при заранее согласованной политике, наличии резервного плана и понимании затронутых клиентов.
Если потребитель критичен, старую версию временно оставляют, но фиксируют новый срок и ограничения. Если поддержка невозможна, следует предоставить адаптер или шлюз преобразования, однако это временная мера: постоянный адаптер скрывает проблему, увеличивает сложность и может сохранить устаревший контракт на неопределённый срок.