Налаштування стратегії API Versioning у CI/CD

Інтеграції ламаються, коли контракт змінюється непомітно для клієнтів. Ми налаштовуємо версіонування API та перевірку контрактів у складальному конвеєрі під ключ — від режиму сумісності до регламентів у репозиторії. Розбіжність версій перестає доходити до користувачів, а випуск нових версій прискорюється без ризику для інтеграцій.
Часті запитання

Чому без версіонування API ламаються інтеграції

Перший збій зазвичай виглядає нешкідливо: сервіс трохи змінив відповідь — перейменував одне поле, змінив тип або прибрав застаріле.

З боку постачальника все зелене, а в споживача розвалюється розбір відповіді: він написаний під жорстко зашитий контракт сервісу й очікує попередню структуру. Формально сервіс живий і відповідає успіхом, фактично інтеграція мертва.

Корінь у тому, що контракт живе не в коді, а в домовленостях і листуванні. Ламальні зміни проходять непоміченими, бо перевірки споживача працюють на заздалегідь підготовлених відповідях, а не справжніх; неузгодженість схем випливає лише на живому трафіку. Документація на цей момент уже описує нову структуру, тому проблему шукають не там.

Далі — ніч, розбір запитів з обох сторін і питання «хто винен». Споживач вносить ручні правки прямо в прод, постачальник відкочує реліз, який пройшов усі перевірки. Кожна така історія коштує кількох годин простою і, що гірше, довіри між командами.

Версіонування API знімає це не саме по собі, а разом із правилами: версія фіксується явно, стара залишається робочою, нова з'являється поряд, виведення з експлуатації відбувається за оголошеним строком і з попередженням споживачів. Зворотна сумісність тоді стає властивістю, яку можна перевірити, а не обіцянкою.

Розбираємо, як це закривається — від вибору схеми версіонування до контрактних перевірок у збірці, які не дають ламальній зміні дійти до проду.

Що змінюється після впровадження керованих контрактів

До керованих контрактів схема API жила в листуванні та в головах: специфікацію правили за фактом, а споживачі дізнавалися про ламальну зміну вже після випуску.

Відновлення розтягувалося — спочатку шукали, яка інтеграція відвалилася, потім домовлялися, хто і що відкочує, і лише потім правили прод.

Після впровадження контракт стає таким самим артефактом, як код: опис в OpenAPI лежить у репозиторії, а перевірка контрактів запускається на кожній зміні й порівнює нову схему з опублікованою.

Видалене поле, зміна типу або перейменування маршруту не проходять перевірку до злиття — тобто до того, як це побачить хоча б один споживач.

Звідси вимірювані сліди. Частка випусків, які проходять без ручного узгодження схем, зростає з одиниць до більшості: узгодження замінено машинним порівнянням, ручний крок залишається лише для навмисно ламальних правок.

Час випуску скорочується, бо очікування домовленості зі споживачами перестає бути окремим етапом розгортання.

Зникає цілий клас відмов — несумісність версій у проді.

Стабільність інтеграцій тримається не на дисципліні й не на уважності рев'юера, а на правилі в збірці: якщо схема змінюється незворотно, випуск зупиняється й вимагає явного оголошення нової версії та періоду підтримки старої.

Відкат при цьому передбачуваний — попередня версія маршруту продовжує працювати, поки споживачі переїжджають на нову.

Підходи до версіонування API: порівняння режимів

Версіонування — це не про вигляд посилання, а про контракт: клієнт інтегрується один раз і повинен заздалегідь знати, коли його зламають. Нижче чотири режими, між якими реально обирають на старті, і всі вони перевіряються на етапі збірки, а не після релізу.

Варіант Коли підходить Обмеження
Версія в шляху Публічні інтерфейси, де важлива наочність і кешування за адресою Мажорний перехід змінює адреси: кожен інтегратор мусить мігрувати
Версія в заголовку Внутрішні сервіси з єдиною адресою для всіх споживачів Кеш і проксі бачать одну адресу; версію легко не передати, налагодження складніше
Узгодження вмісту Коли змінюється і структура полів, і формат відповіді Високий поріг для інтеграторів, версія погано читається в логах доступу
Дата випуску версії Продукти з частими релізами та плавним розвитком контракту Межі розмиті: прив'язка до дати, а не до факту ламальної зміни

Мажорна версія змінює форму відповіді або прибирає поле — це ламальна зміна, і в конвеєрі вона йде окремою гілкою контракту з повним набором перевірок сумісності.

Мінорна додає необов'язкові поля та нові методи, зворотно сумісна й випускається звичайним шляхом, без паралельної гілки.

Застарілі методи позначаємо в описі OpenAPI ознакою застарілості, віддаємо заголовок із датою вимкнення й рахуємо частку викликів за журналами.

Поки частка не впала до нуля, метод працює — але новий трафік на нього не спрямовуємо, а заміну та строк вимкнення фіксуємо в документації заздалегідь.

Як вбудувати перевірку контрактів у конвеєр збірки

Перевірка контрактів приносить користь лише тоді, коли стоїть на тому самому кроці конвеєра, де збирається артефакт. Інакше розходження між описом інтерфейсу та реалізацією випливає вже у споживача — у найнезручніший момент.

Порядок нижче відпрацьований на сервісах, де випуск відбувається кілька разів на тиждень, а споживачів в одного інтерфейсу більше десятка.

  1. Аудит схем. Збираємо описи у форматі OpenAPI і список тих, хто реально викликає методи: які поля читаються, які потрібні лише для відображення, а які вже ніхто не запитує.
  2. Цільова схема версій. Фіксуємо, що вважається ламальною зміною, як нумеруються версії та де живе попередній контракт. Це правило в репозиторії, а не домовленість на словах.
  3. Автоперевірка контракту. Крок порівняння поточного опису з зафіксованим в основній гілці: видалення поля, зміна типу або обов'язковості зупиняє збірку до правок.
  4. Регресійний прогін. Тести запускаються проти попередньої версії інтерфейсу — так ловимо випадки, коли формально контракт сумісний, а поведінка змінилася.
  5. Обкатка на копії. Схема випуску перевіряється на копії промислового контуру: стара й нова версії працюють одночасно, споживачі переводяться поступово, відкат займає хвилини.
  6. Передача регламенту. Розробникам і черговій зміні надходить документ: обов'язкові перевірки, порядок відкату, хто узгоджує несумісну зміну.

Артефакти та регламенти, які залишаються в репозиторії

Усе, що описує роботу з версіями, живе поряд із кодом, а не в листуванні й головах окремих інженерів. Репозиторій залишається єдиним джерелом правди: за ним нова людина в команді розбирається, як випускається сервіс, а черговий розуміє, що робити при відмові. Нижче — мінімальний набір, який ми передаємо на руки разом із налаштованим конвеєром.

  • Описи сервісів — що за сервіс, які версії контракту віддає й споживає, хто власник і куди йти при інциденті. Формат єдиний, тому карта залежностей збирається автоматично, а не відновлюється з пам'яті.
  • Політики доступу та ролі — хто може змінювати контракт, хто лише читає специфікацію, хто випускає мажорну версію. Права вбудовані в налаштування репозиторію, а не в усні домовленості.
  • Правила сумісності — що вважається ламальною зміною і які правки проходять без нової мажорної версії. Перевірка вбудована в збірку, тому спірні зміни не доїжджають до основної гілки.
  • Регламент випуску — порядок публікації, обов'язкові перевірки, умови відкату й те, хто підтверджує випуск. Однаковий для всіх команд, включно з терміновими правками.
  • Порядок виведення версій з обігу — скільки версія живе після оголошення застарілої, як збирається статистика звернень і коли шлюз перестає її пропускати. Без цього кроку старі версії залишаються назавжди.
  • Інструкції для команд — покрокові сценарії: додати поле, випустити нову версію, відкотитися, підключити нового споживача.
  • Шаблони конфігурацій і схем — заготовки маніфестів і описів, щоб команда починала з робочого прикладу.

Частину пунктів оформлено як перевірки в збірці — тоді регламент не розходиться з реальністю: порушення видно на етапі перевірки змін, а не через місяць у звіті. За кожним пунктом фіксуємо відповідального, інакше документ застаріває після першого великого релізу.

Кейс: неузгодженість версій ламала мобільний клієнт

Що було

Мобільний клієнт випускався раз на квартал, серверна частина оновлювалася щодня — релізи розходилися.

Сервер перейменував поле у відповіді, і застосунок падав просто при запуску: підтримка отримала третину звернень із формулюванням «не відкривається», а App Store — хвилю однозіркових відгуків.

Відновлення займало години: черговий шукав останній робочий стан, відкочував реліз і зводив гілки, які встигли розійтися.

Що змінили

Контракт перевели на правило «лише додавання»: поля можна вводити, змінювати їхній сенс — лише в новій мажорній версії. Номер версії вшили в адресу виклику, маршрутизацією зайнявся шлюз: у кожної версії своя схема, свій набір перевірок і телеметрія за часткою викликів.

Версію гасили за фактом, а не за календарем — поки старі збірки дають помітну частку запитів, вона живе; нижче порога вимкнення планується заздалегідь. Ручні правки в гілках припинилися: схема одна, гілки збираються з неї.

Що стало

Частка звернень у підтримку щодо несумісності впала з третини до одиниць відсотків. Відновлення після невдалого випуску — хвилини: відкат це перемикання маршруту на попередню версію, а не перезбірка й пошук коміту. Одночасно в обігу тримаємо 2-3 версії замість шести-семи. Ручні правки пішли як клас — розходженню між описом контракту й кодом просто ніде виникнути.

Чим відрізняється мажорна версія від мінорної в контракті?

Межі сумісності проходять по одному питанню: чи продовжить працювати наявний клієнт, не змінюючи свій код. Якщо так — це мінорна версія, тобто сумісне розширення контракту. Якщо ні — мажорна версія, бо ламальну зміну не можна внести в той самий номер.

Мінорна версія додає: нове необов'язкове поле у відповіді, новий метод, новий необов'язковий параметр із розумним значенням за замовчуванням. Старий клієнт такі поля просто не читає — він бачить звичну структуру й не падає.

Ознаки несумісності визначаються без спорів: видалення або перейменування поля, зміна типу (рядок замість числа), новий обов'язковий параметр у запиті, інший код відповіді за тієї самої ситуації, зміна семантики під попереднім іменем.

Кожен такий пункт означає, що частина інтеграцій зламається в робочому середовищі, а не в перевірках.

Спірний випадок — розширення переліку та посилення валідації: формально поле залишилося, але клієнт, який надсилає значення, що раніше приймалося, тепер отримує відмову.

Тут працює перевірка «що саме побачить клієнт попередньої версії»: якщо набір допустимих значень звузився, зміна ламальна.

Щоб межа не перетворювалася на переговори між командами, її фіксують у контракті: номер версії в адресі або заголовку запиту, контрактні перевірки в збірці — вони падають, якщо правка ламає старий варіант, а попередні версії живуть до явного вимкнення.

Технічні сумніви перед впровадженням

Сумніви зазвичай випливають не на старті, а коли друга версія контракту вже в проді й потрібно вирішити, що робити з першою.

Нижче — питання, які найчастіше піднімають на етапі проєктування: від відповідей залежить обсяг роботи команди супроводу й те, як швидко продукт зможе випускати зміни.

Скільки версій тримати одночасно і як їх розділяти?

Версії живуть паралельно, розділення — за шляхом або заголовком запиту, вибір фіксується в маршруті, а не в коді обробника. Робоче правило: поточна версія плюс одна попередня, а мінімальний строк життя старої — два цикли випуску.

Вимкнення робиться не видаленням коду, а зняттям маршруту: звернення до нього повертає явну помилку з посиланням на актуальну версію.

Чи можна впроваджувати версіонування без зупинки випусків?

Так, і це основний сценарій. Маршрутизатор ставиться перед сервісами, стара гілка маршрутів залишається ввімкненою, нова піднімається поряд і отримує трафік частинами.

Випуски в цей час ідуть своїм ходом, а відкат зводиться до перемикання маршруту — без перезбірки й повторного проходження перевірок.

Хто відповідає за схеми та сумісність?

Схема лежить у тому самому репозиторії, що й код, і змінюється тією самою зміною. Перевірка сумісності вбудована в збірку: несумісна зміна не проходить, поки не підвищено major-версію.

Відповідальність несе команда, яка володіє сервісом, — інакше описи схем розходяться з реалізацією, і споживачі дізнаються про це з помилок у проді.

Що відбувається зі старими методами — їх видаляють?

Спочатку переводяться споживачі, потім метод позначається застарілим, і лише після цього вимикається. Виклики старого методу пишуться в журнал: видно, хто ще не мігрував і скільки звернень залишилося. Поки лічильник не обнулився, метод тримається — це дешевше, ніж розбирати наслідки вимкнення.

Обговоримо вашу задачу і повернемося з планом

Щоб повернутися з оцінкою, а не з уточнювальними питаннями, нам вистачає кількох артефактів. Нічого спеціально готувати не потрібно — достатньо того, що вже є в роботі: описів сервісів, списку сторін, що викликають, та історії релізів.

  • Опис задачі: що не влаштовує зараз — ламальні правки б'ють по споживачах, старі версії живуть роками, чи немає регламенту виведення версії з підтримки.
  • Поточні описи сервісів: контракти, специфікації, реєстр методів і точок входу — у будь-якому вигляді, де вони зараз лежать.
  • Список споживачів за кожним сервісом: хто викликає, на якій версії сидить, чи є клієнти, які не можна оновити швидко (мобільні застосунки, партнерські інтеграції, зовнішні системи).
  • Історія ламальних правок: що змінювалося, як попереджали споживачів, де траплялися простої та як їх гасили.
  • Релізний цикл: як часто випускаєте, хто ухвалює рішення про виведення версії з підтримки, чи є вікна для зворотно несумісних змін.
  • Обмеження: вимоги безпеки, роздільні контури, заборони на зовнішні сервіси, зобов'язання перед партнерами.

Перший крок — розбір задачі з інженером: дивимося, які методи вже розійшлися за версіями і де ламаються споживачі.

Далі повертаємося з планом впровадження: схема версіонування, політика підтримки старих версій і порядок виведення їх з обігу, обсяг робіт за етапами, точки контролю в конвеєрі збірки й порядок оцінювання. Опишіть задачу — призначимо розбір і повернемося з оцінкою та планом.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    816
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1141