сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · FastAPI, Django и API

Версионирование API

Версионирование API: менять, не ломая

Как только у API есть внешние клиенты, которых нельзя обновить одномоментно, встаёт вопрос эволюции контракта. Собес проверяет, отличаешь ли ты обратно совместимое изменение от ломающего и умеешь ли выбрать один способ версионирования вместо каши.

Типовые формулировки: «как версионировать API?», «какое изменение сломает клиентов?», «можно ли поменять тип поля в текущей версии».

Зачем и как версионировать

Версионируют публичный API, чтобы менять контракт, не ломая внешних клиентов, которых нельзя заставить обновиться разом. Способы: версия в пути (/v1 - наглядно и кэшируемо), в заголовке Accept (чище по URL), в query-параметре. Все рабочие - главное выбрать ОДИН и держаться его; смешивать в одном API нельзя, это путает интеграторов.

// Внутренний API между своими сервисами версионировать строго не обязательно - там клиентов обновляешь ты же; версионирование ценно именно для публичного контракта.

версионирование
параллельные версии контракта API для совместимости
обратная совместимость
изменение, не ломающее существующих клиентов

Совместимо против ломающего

Обратно совместимо - добавить НЕОБЯЗАТЕЛЬНОЕ поле: старые клиенты просто игнорируют неизвестное, ничего не ломается, новую версию заводить не надо. Ломающие изменения - переименование, удаление, смена типа или обязательности поля: они рвут парсинг у тех, кто читает контракт по-старому.

Отсюда правило: ломающие изменения катят в НОВУЮ версию, оставляя старую живой на переходный период. Сменить тип поля со строки на число «для единообразия» прямо в текущей версии - классика, которая роняет клиентов в проде.

// Практический признак: можешь ли ты выкатить изменение так, что существующий клиент не заметит? Да - совместимо, нет - новая версия.

ломающее изменение
переименование/удаление/смена типа поля

Как отвечать: «Какое изменение API сломает клиентов, а какое нет?»

Не сломает то, что старый клиент может просто не заметить: добавить необязательное поле в ответ или новый опциональный параметр - читающие по-старому его игнорируют. Сломает всё, что меняет уже существующий контракт: переименовать или удалить поле, сделать опциональное обязательным, поменять тип со строки на число. Такие вещи рвут парсинг у клиентов, которых я не могу обновить одномоментно, поэтому их я катаю в новую версию - /v2, и держу /v1 живой на переходный период. Проверочный вопрос себе: заметит ли изменение существующий клиент? Если да это ломающее.

Дан рабочий критерий (заметит ли старый клиент), перечислены оба класса с примерами и названа стратегия - новая версия плюс переходный период; практично и проверяемо.

На чём валят

  • Катить удаление или переименование поля в текущую версию - ломает читающих клиентов.
  • Менять тип поля со строки на число «для единообразия» - рвёт парсинг у клиентов.
  • Смешивать несколько способов версионирования в одном API - путаница для интеграторов.
  • Делать раньше опциональное поле обязательным - старые запросы без него начнут падать.

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 11, остальные разбираются в тренажёре.

  1. #api_versioning1 / 5
    Какие есть типичные способы версионировать REST API?
    A)Версию шлют в теле каждого запроса отдельным полем
    B)Версионирование задаётся исключительно кодом ответа сервера
    C)Префикс пути /v1, заголовок Accept или query-параметр
    D)Только смена доменного имени сервиса на каждую новую версию
    показать ответ и разбор
    +C)Префикс пути /v1, заголовок Accept или query-параметр

    // разбор: Распространены три подхода: версия в пути (/v1/users — просто и явно), в заголовке (Accept: application/vnd.api.v2+json — «чище» по URL), или query-параметром (?version=2). У пути лучшая наглядность и кэшируемость; заголовок ближе к «чистому REST». Главное — выбрать один и держаться его.

  2. #api_versioning2 / 5
    Какое изменение ответа безопасно для существующих клиентов?
    A)Поменять тип поля со строки на число для единообразия схемы
    B)Добавить новое необязательное поле в тело ответа
    C)Удалить поле, которым, как кажется, никто уже не пользуется
    D)Переименовать существующее поле в более понятное название
    показать ответ и разбор
    +B)Добавить новое необязательное поле в тело ответа

    // разбор: Обратно совместимо — добавление необязательного поля: корректные клиенты игнорируют неизвестное. Ломают: переименование, удаление, смена типа или обязательности существующего поля, изменение семантики. Ломающие изменения выносят в новую версию, а не катят в текущую.

  3. #api_versioning3 / 5
    Зачем публичному API вообще версионирование?
    A)Это чисто косметическое требование — на реальную работу API оно не влияет
    B)Ломающие изменения выкатывают в новой версии, не рушив старых клиентов
    C)Для ускорения API: новые версии работают быстрее предыдущих
    D)Чтобы вынудить клиентов обновиться до самой свежей версии
    показать ответ и разбор
    +B)Ломающие изменения выкатывают в новой версии, не рушив старых клиентов

    // разбор: У публичного API есть внешние потребители, которых нельзя ломать внезапно. Версионирование позволяет вводить несовместимые изменения в новой версии (v2), пока старая (v1) продолжает работать. Клиенты мигрируют в своём темпе, а вы объявляете политику устаревания. Без версий любое breaking change одномоментно рушит всех.

  4. #api_versioning4 / 5
    Какое изменение API можно внести без новой версии, не сломав клиентов?
    A)Изменить тип поля с числа на строку ради единообразия форматов ответа
    B)Добавить необязательное поле или новый эндпоинт — старые клиенты его не заметят
    C)Переименовать существующее поле ответа на более понятное и удобное имя
    D)Сделать ранее необязательный параметр запроса теперь обязательным для всех
    показать ответ и разбор
    +B)Добавить необязательное поле или новый эндпоинт — старые клиенты его не заметят

    // разбор: Обратно совместимы (не требуют новой версии) аддитивные изменения: новое опциональное поле в ответе, новый эндпоинт, новый необязательный параметр. Старые клиенты их просто игнорируют. Ломают: удаление/переименование поля, смена типа, новое обязательное требование, изменение семантики. Правило: только добавлять, ничего молча не менять и не убирать.

  5. #api_versioning5 / 5
    Версию API держат в пути (/v1/...) или в заголовке. Чем берёт вариант с путём?
    A)Он скрывает версию от клиента, снижая связанность между сторонами интеграции
    B)Версия в заголовке считается устаревшей, путь пришёл ей на смену
    C)Он виден и явен: версия читается прямо в URL, легко тестировать и кешировать
    D)Он позволяет менять версию, не трогая URL, что удобнее для клиентов интеграции
    показать ответ и разбор
    +C)Он виден и явен: версия читается прямо в URL, легко тестировать и кешировать

    // разбор: Версия в пути (/v1/users) наглядна: видна в URL, тривиально дёрнуть curl'ом, кешируется и логируется как разные ресурсы. Минус — версия просачивается в идентификатор ресурса. Версия в заголовке (Accept с медиа-типом или X-API-Version) держит URL чистым и «правильнее» по REST, но менее очевидна и сложнее в отладке. Оба подхода рабочие; путь популярнее за простоту.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.