Короткий ответ
Варианты — версионирование API (новый путь/заголовок версии), поддержка старого и нового формата одновременно через дополнительные поля с периодом параллельной поддержки, либо строгая политика deprecation с заранее объявленным сроком отключения старого контракта; выбор зависит от того, кто клиенты, насколько они управляемы и насколько критична обратная совместимость.
Как это работает подробнее
Явное версионирование (/v2/... или заголовок) позволяет годами поддерживать старые клиенты параллельно с новыми, но увеличивает поверхность поддержки кода. Расширение контракта (добавление нового поля рядом со старым, двойная запись в оба поля) позволяет клиентам мигрировать поэтапно без немедленной жёсткой поломки, но временно усложняет схему данных и сериализацию.
Жёсткое версионирование даёт предсказуемость для внешних клиентов, но дорого в поддержке нескольких параллельных версий логики и тестов; расширение контракта без версии дешевле в моменте, но увеличивает сложность схемы и риск, что часть клиентов так и не мигрирует. Решение должно учитывать контроль над клиентами, критичность изменения и готовность команды поддерживать параллельные версии ограниченное время.
Пример кода
# Переходный вариант: оба поля временно присутствуют в ответе
class OrderOutV1Compat(BaseModel):
order_id: int # старое имя поля, помечено как deprecated в OpenAPI
id: int # новое имя того же значения
total_amount: float # старый тип (float)
amount_cents: int # новый тип (int, в минимальных единицах валюты)
# Через объявленный срок (например, 3 месяца и уведомление клиентов)
# поля order_id/total_amount удаляются в /v2.Что использовать на практике
- Практика. Критерии выбора: количество и управляемость клиентов (внутренний сервис с контролируемым деплоем — можно быстро заменить все вызовы; публичное API с неизвестными внешними клиентами — нужна параллельная поддержка и объявленный срок устаревания), частота изменений контракта, наличие контрактных тестов/схемы (OpenAPI) для отслеживания breaking changes.
Подводные камни
- Риск. Меняют публичный контракт «по месту» без версионирования, полагаясь на то, что клиенты «обновятся сами»; держат старую версию бесконечно без чёткого плана и даты отключения, из-за чего накапливается технический долг и поддержка нескольких версий становится постоянной нагрузкой.