OpenAPI — это формат описания HTTP API в виде обычного файла YAML или JSON. В нём перечислено, какие у API есть адреса, какие методы они принимают, какие поля уходят в запросе и что возвращается в ответе. Файл читает и человек, и программа: по нему генерируют документацию, клиентские библиотеки и заглушки для тестов.
Формальное название — OpenAPI Specification, сокращённо OAS. Развивает её OpenAPI Initiative, проект с открытым управлением под эгидой Linux Foundation.
Дальше — как устроен документ, чем OpenAPI отличается от Swagger, что изменилось в версиях 3.1 и 3.2 и почему главное обещание этого формата — «документация никогда не устареет» — само по себе не работает.
Как выглядит документ OpenAPI
Минимальный рабочий файл короче, чем кажется:
openapi: 3.1.0
info:
title: Ссылки
version: "1.0"
paths:
/links:
post:
summary: Создать короткую ссылку
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [url]
properties:
url:
type: string
format: uri
responses:
'201':
description: Ссылка создана
Обязательных полей верхнего уровня всего два — openapi и info; кроме них документ должен содержать хотя бы одно из paths, components или webhooks. Так это описано в спецификации OAS 3.1.1.
Здесь же прячется путаница, которую я встречал в чужих файлах не раз: openapi и info.version — это разные вещи. Первое — версия самого формата, по которой инструменты понимают, как читать документ. Второе — версия вашего API. Спецификация говорит об этом прямо, но интуиция подсказывает обратное, и в результате появляются файлы, где openapi: 1.0.
Крупные спецификации обычно разносят по файлам через $ref: корневой документ ссылается на ./paths/links.yaml, тот — на ./schemas/link.yaml. Это удобно и создаёт одну неочевидную проблему, к которой я вернусь в конце.
OpenAPI и Swagger — это не одно и то же
Самая частая путаница в теме.
| Что это | Кто отвечает | |
|---|---|---|
| OpenAPI | стандарт, описание формата | OpenAPI Initiative, Linux Foundation |
| Swagger | набор инструментов, которые этот формат читают | SmartBear |
История объясняет, откуда взялась каша. Сначала Swagger был одновременно и спецификацией, и инструментами. Потом спецификацию передали в OpenAPI Initiative, и она стала называться OpenAPI Specification, а имя Swagger осталось за инструментами — Swagger UI, Swagger Editor и прочими.
Практический вывод: «у нас Swagger» обычно означает «у нас есть OpenAPI-файл, и мы показываем его через Swagger UI». Файл при этом можно открыть чем угодно другим — Redoc, Scalar, генераторами клиентов. Инструмент и формат не связаны намертво.
Версии: 3.0, 3.1 и 3.2
Различия между ветками — не косметика.
3.0 — самая распространённая версия. Её ограничение в том, что схемы данных в ней похожи на JSON Schema, но совместимы не полностью, и это регулярно ломает совместную работу инструментов.
3.1 закрыла этот разрыв: объект Schema стал надмножеством JSON Schema Draft 2020-12. Если вы уже описываете данные через JSON Schema, в 3.1 их можно переиспользовать без переписывания. Последняя редакция — 3.1.1, опубликована 24 октября 2024 года.
3.2 вышла в сентябре 2025 года. Из анонса OpenAPI Initiative заметнее всего:
- HTTP-метод
query— для идемпотентных запросов, где параметры не влезают в строку адреса; additionalOperationsдля нестандартных методов;- потоковые форматы: Server-Sent Events, JSON Lines, JSON-последовательности;
- теги научились иерархии — появились
summary,parentиkind; - OAuth 2.0 device flow для устройств без удобного ввода.
Выбирать версию стоит по инструментам, а не по номеру. Поддержка 3.1 в экосистеме хорошая, 3.2 новее и местами ещё догоняется. Наша собственная спецификация объявлена как 3.1.0.
Что спецификация даёт на практике
Один файл закрывает сразу несколько задач:
- интерактивная документация — Swagger UI или Redoc строят страницу прямо из файла, включая форму «попробовать запрос»;
- клиентские библиотеки — генераторы собирают SDK под нужный язык, не заставляя писать обёртки руками;
- заглушки — мок-сервер поднимается по описанию до того, как готов бэкенд, и фронтенд не ждёт;
- проверка контракта — тесты сверяют реальные ответы со схемами и ловят момент, когда ответ перестал совпадать с описанием.
Именно из этого списка вырастает главный аргумент в пользу OpenAPI: документация перестаёт быть отдельным текстом, который кто-то забывает обновить.
Аргумент верный. Но он верен не сам по себе.
Спецификацию ничто не связывает с кодом
Это то, о чём почти не пишут в статьях «что такое OpenAPI», и то, обо что спотыкаются в реальности.
Файл спецификации — просто файл. Роутер о нём не знает. Контроллер о нём не знает. Вы можете удалить эндпоинт, добавить новый, поменять обязательное поле на необязательное — и ни один тест не упадёт. Документация не «синхронизируется автоматически», она синхронизируется ровно настолько, насколько кто-то помнит её править.
Разъезжается это в обе стороны, и обе вредны по-разному:
- описано, но не работает. Разработчик читает документацию, шлёт запрос и получает 404. Доверие к остальной документации падает мгновенно — раз здесь соврали, где ещё?
- работает, но не описано. Функциональность просто не существует для того, кто её ищет. Её не найдут, за неё не заплатят.
Второй случай коварнее, потому что никто не жалуется. Жаловаться некому: пользователь не знает, что эндпоинт есть.
У нас так и вышло. В API Lix.li работали три эндпоинта для конверсий — лента событий и приём постбеков, одиночный и пакетный, — и ни одного из них не было в спецификации. Код работал, тесты проходили, на витрине API-лендинга при этом были нарисованы два совсем других адреса, которых в коде не было вовсе. Обнаружилось это не по жалобе, а при сплошной сверке.
Как поймать расхождение автоматически
Лечится это не дисциплиной, а тестом. Идея простая: взять список путей из спецификации, взять список маршрутов из роутера и сравнить множества в обе стороны.
пути из openapi.yaml → есть такой маршрут? → иначе документация врёт
маршруты из роутера → есть такой путь? → иначе функциональность невидима
Проверку «описанное работает» удобно делать живым запросом: дёрнуть эндпоинт без авторизации и убедиться, что ответ — 401, а не 404. Отличие важное. 401 значит «маршрут найден, нужен ключ», 404 — «такого адреса нет». Никаких побочных эффектов при этом не происходит: аутентификация отрабатывает раньше, чем контроллер.
Обратную проверку делают по конфигурации маршрутов. Заодно придётся явно перечислить исключения — служебные эндпоинты, которым в публичном контракте не место. Список исключений полезен сам по себе: он заставляет один раз осознанно решить, что именно вы считаете публичным API.
Мы такой тест написали после истории с конверсиями. Проверка себя оправдала сразу: если убрать конверсии из спецификации, тест падает и называет оба пропавших адреса поимённо.
Две ловушки, о которых узнаёшь поздно
$ref и относительные пути. Если спецификация разбита на файлы, ссылки внутри неё разрешаются относительно адреса, с которого файл отдали. Корневой документ, доступный по /openapi, будет искать ./paths/links.yaml по адресу /paths/links.yaml — и не найдёт. В браузере через Swagger UI всё выглядит нормально, потому что там файл загружается со своего настоящего места, а вот генератор клиента на том же документе споткнётся. Либо отдавайте спецификацию только с её собственного каталога, либо собирайте её в один файл без внешних $ref.
Swagger UI пуст для поисковика. Страница документации на Swagger UI — это несколько строк разметки и скрипт, который дорисовывает содержимое в браузере. В исходном HTML нет ни одного адреса эндпоинта. Для читателя страница нормальная, для индексации — пустая. Добавьте сюда частую ошибку в robots.txt: правило Disallow: /api/ пишут, чтобы закрыть JSON-эндпоинты, а закрывают заодно и человеческую документацию по тому же префиксу. Закрывать стоит точный путь версии — например /api/1.0/, — а не весь раздел.
С чего начать
Если API уже есть, а описания нет, порядок примерно такой:
- Опишите один эндпоинт руками — этого хватит, чтобы понять структуру.
- Возьмите версию, которую уверенно держат ваши инструменты; по умолчанию 3.1.
- Разнесите файл по
$ref, когда он перестанет помещаться на экран, и сразу зафиксируйте, с какого адреса он отдаётся. - Поставьте тест, сверяющий спецификацию с роутером в обе стороны. До этого шага любые обещания об актуальности документации — обещания.
Посмотреть, как это выглядит на живом API, можно в документации API Lix.li: там описаны ссылки, группы, A/B-тесты и конверсии. Если интересно, как устроен сам сервис вокруг этого API, есть страница API сокращения ссылок, а из соседних тем — что такое вебхуки, разбор редиректов 301, 302, 307 и 308 и пример работы через PHP SDK.