— Где актуальный контракт сервиса рассрочек?
— В репозитории.
— В каком?
— Сейчас найду ссылку.
У нас этот диалог повторялся регулярно. Формально API-документация была. Фактически реестр хранился в памяти нескольких сотрудников, а поиск работал через WB Wiki и корпоративный мессенджер Band.
Меня зовут Олег Леонов, я руковожу отделом системного анализа в финтехе RWB. Мы занимаемся рассрочками и кредитами, инвесткопилкой и WB Кошельком в мобильном приложении и на сайте.
Swagger Aggregator я начинал как pet-проект. Хотел собрать контракты в одном месте и искать по ним примерно так же, как по коду. Потом агрегатор прижился у команды. Расскажу, что в итоге получилось и на каких местах я потратил больше времени, чем рассчитывал.
Swagger UI тут не помогал
Swagger UI нормально показывает одну спецификацию. Проблема в том, что у нас их много, а лежат они где угодно:
YAML или JSON во внутреннем GitLab;
документ по HTTP-адресу dev-сервиса;
ссылка в Wiki, которая когда-то была актуальной;
-
ссылка в чате, которую ещё надо найти.
Аналитик обычно ищет не конкретный файл. Он ищет понятие: где используется
paymentToken, какой сервис возвращает статус заявки, у кого поле суммы называетсяamount. Открывать контракты по одному и искать внутри каждого можно, но делать так каждый день быстро надоедает.Мне был нужен каталог с поиском по содержимому, версиями, diff и возможностью сразу продолжить работу с найденной ручкой.
Почему не взяли готовое решение
Сначала я посмотрел, что уже есть на рынке:
Решение |
Что умеет |
Почему не подошло |
|---|---|---|
SwaggerHub |
Совместное проектирование, style guide, портал документации |
SaaS для внутренних контрактов не подходит. Enterprise on-prem требует лицензий, бюджета и отдельного администрирования. Для команды из 15 аналитиков тяжеловесно |
Redocly |
OpenAPI-first, docs-as-code, сборка сайта документации |
Хорошо работает с документацией вокруг спецификации, но не решает наш сценарий поиска по содержимому всех контрактов |
Stoplight |
Визуальный редактор, валидация, governance |
Это отдельная платформа со своей авторизацией и хранилищем. Интеграцию с внутренним GitLab пришлось бы собирать отдельно |
Apicurio Registry |
Реестр схем, артефакты, версии |
Хороший registry, но для ежедневной работы аналитика не хватило просмотра операций, поиска по полям и прототипов |
Postman |
Тестирование, коллекции, совместная работа |
Работает с контрактом в первую очередь как с артефактом тестирования. Мне был нужен именно каталог |
Первым отвалился SaaS. Контракты финтеха нельзя загружать наружу: в них видны внутренние сервисы, модели и бизнес-логика. Я бы не стал этого делать даже без формального запрета.
Дальше упёрлись в корпоративный GitLab и его права. Агрегатор должен читать файл прямо из репозитория по проекту, ветке и пути. Если добавить промежуточный импорт, появится ещё одна копия, которая обязательно когда-нибудь устареет.
Дальше требования набрались из обычной работы: глобальный поиск, diff версий, проверка breaking changes, mock и конструктор прототипов с общей ссылкой. Готового решения со всем этим я не нашёл.
Ну и мне просто хотелось написать свой инструмент. Для pet-проекта это нормальная причина.
Весь проект — чистый вайбкод. Я задавал архитектуру и направление, тестировал и деплоил, а основную массу реализаций писал ИИ-кодинг-агент. Для внутренней штуки это идеальный сценарий: не нужно заказывать доработку у разработчиков, можно вечером сесть и за пару сессий выкатить очередную фичу.

Как агрегатор получает контракты
Сейчас есть два типа источников.
Для GitLab указываются проект, ветка и точный путь к файлу. Адаптер забирает raw-содержимое через API v4. Для развёрнутого сервиса достаточно URL.
Формат сначала определяется по Content-Type. Но часть сервисов отвечает application/octet-stream, поэтому есть запасной вариант: агрегатор смотрит на первый значимый символ и понимает, JSON перед ним или YAML.
После синхронизации контракт появляется в каталоге. В центре открывается Swagger UI 5, сверху лежат сведения о средах и ответственных. Сервисы можно раскладывать по папкам и перетаскивать. Это оказалось удобнее, чем держать список ссылок.

Каталог слева, Swagger UI по центру, метаданные сверху.

В контракте User Balance 72 операции.
Поиск
В левой панели сервисы фильтруются по имени. Внутри открытой спецификации поиск проверяет параметры, request body, ответы, вложенные схемы и массивы. На экране остаются только подходящие операции.
Но чаще проблема другая: помнишь название поля или кусок пути, а сервис не помнишь. Для этого я добавил глобальный поиск. Бэкенд находит спецификации, где встречается строка, фронтенд разбирает совпадения до метода, пути и описания операции.

combo-payment нашёлся в контракте User Balance.По клику агрегатор открывает нужный контракт, разворачивает операцию и подсвечивает её. Отсюда можно скопировать curl, получить описание ручки в Markdown, создать mock или перейти к сравнению версий.


amount внутри одной спецификации.Всю спецификацию можно выгрузить как Postman Collection 2.1.
Версии и breaking changes
При изменении источника предыдущая версия уходит в архив. Семантический diff сравнивает операции, параметры, request body и ответы. Можно открыть две версии рядом или посмотреть короткий список изменений.

Проверка обратной совместимости ловит удаление операции или параметра, появление нового обязательного параметра и смену типа.
Сразу обозначу ограничение: полноценной сохранённой классификации breaking / non-breaking / patch для каждой версии пока нет. Сама проверка breaking changes работает, трёхуровневая классификация ещё в планах.
Конструктор прототипов
Аналитик собирает OpenAPI-контракт через формы и сразу видит результат в Swagger UI. Сохранённый прототип открывается по share-токену без авторизации.
Сценарий простой: собрал контракт, отправил ссылку разработчику, внёс изменения, отправил ту же ссылку ещё раз. YAML руками править не обязательно.

Mock, который возвращает что-то полезнее {}
Mock-сессия живёт от одного до 24 часов и хранит выбранные операции. Запрос сопоставляется одновременно по HTTP-методу и пути. Если смотреть только на путь, GET /users и POST /users начинают конфликтовать.
Если тело ответа не задано вручную, генератор ищет 200, 201 или первый 2xx. Затем раскрывает локальные $ref и строит JSON по схеме. Поддерживаются примеры, объекты, массивы, числа, строки, boolean и композиция схем.
Для каждого запроса создаётся отдельный генератор. Иначе параллельные обработчики делили бы случайное состояние и разобранную спецификацию.

Активные mock-сессии и оставшееся время жизни.
Путь, body, headers и cookies можно переопределить. Настраиваемого status code, задержки и отдельного mock-поддомена сейчас нет. Это именно планы, а не работающий функционал.
Архитектура
В основе порты и адаптеры. Ядро знает интерфейсы. HTTP-обработчики работают с ним через порты. GitLab, HTTP-источники, PostgreSQL, SQLite и уведомления подключены адаптерами.

Схема основных компонентов.
Хранилище выбирается переменной окружения, оба варианта реализуют одинаковые порты. Я не считаю, что каждый пет-проект обязательно надо строить так. Здесь подход оказался удобным: можно локально запустить SQLite, а в окружении подключить PostgreSQL без изменений в ядре.
Планировщик синхронизирует источники по расписанию, по умолчанию раз в сутки. Авторизацию можно включить через Keycloak OIDC. Для локального запуска она не нужна.

Синхронизация, проверка хеша, архив и дальнейшая работа с версией.
Где я потратил больше всего времени
Дубли ключей в YAML
В одной спецификации встретились одинаковые ключи на одном уровне. Человек такой дубль легко пропускает, а парсер отказывается декодировать документ.
Терять весь контракт из-за одного ключа не хотелось. Теперь синхронизатор сначала строит дерево YAML, рекурсивно убирает дубли и оставляет последнее значение. Только после этого документ разбирается как OpenAPI.
Важно, что YAML пересобирается лишь при реальном дубле. Если нормализовать каждый файл всегда, косметические изменения форматирования меняют хеш и создают ложные версии.
Контракт от такой обработки не становится правильным. Он просто остаётся доступен в каталоге, а проблему можно увидеть и исправить в источнике.
Автообнаружение Swagger в GitLab
Первая идея была очевидной: рекурсивно пройти репозиторий и найти все swagger.yaml. На монорепозитории этот вариант быстро перестал нравиться. GitLab отдаёт дерево страницами, оно может измениться между запросами, а большая часть найденных файлов не относится к нужному сервису.
Для отдельного discovery-скрипта работает проверка небольшого набора известных путей через лёгкие запросы. В самом приложении источник хранит точный путь, и адаптер забирает raw-файл.
Автоматического сканера групп сейчас нет. Управляемый список оказался надёжнее робота, который иногда приносит не тот Swagger.
Что есть в репозитории сейчас
Цифры в таблице — срез по актуальной базе (август 2026). Всего в агрегаторе 209 спецификаций, большая часть приходит из GitLab (194) и deployed-хостов (15).
Метрика |
Значение |
|---|---|
Спецификаций |
209 |
Источников GitLab / URL |
194 / 15 |
Методов |
2 467 |
Суммарный размер контрактов |
7 767 980 байт, около 7,4 МиБ |
Пользователей |
82 |
Для меня важнее не размер каталога. Важно, что поиск API теперь начинается с сущности или поля, а не с вопроса в чат: «У кого была ссылка?»
Пара слов в конце
Полезен агрегатор оказался не перечнем функций, а тем, что из работы ушёл один вопрос: где лежит актуальный контракт и что в нём поменялось. Сейчас в каталоге 209 спецификаций и 2467 методов, ими пользуются 82 человека. Для команды это уже не эксперимент, который один раз показали на встрече, а постоянно открытая вкладка. В ней ищут по всем контрактам, смотрят версии и diff, поднимают mock, собирают прототипы. Начиналось всё с простого желания не тратить пару минут на поиск ссылки в чатах — с этим мы справились.
Заодно выяснил, что полезная внутренняя штука часто вырастает не из большого замысла, а из одной надоевшей проблемы, которую наконец перестали терпеть. Если у вас похоже — интересно сравнить, как это организовано у вас. Где живут ваши OpenAPI-спецификации, как вы ищете сразу по нескольким контрактам, кто разбирается с версиями и breaking changes? Расскажите в комментариях, что из этой рутины раздражает сильнее всего и как вы с этим справляетесь.
chemtech
А где исходники?