Learning Platform
Глоссарий Troubleshooting
Урок 08.01 · 18 мин
Начальный
OpenAPISwaggerСпецификацииAPI contracts

OpenAPI 3.1: машинно-читаемый контракт API

В этом уроке мы рассмотрим, что такое OpenAPI Specification: как она появилась из Swagger, чем отличаются версии 2.0/3.0/3.1/3.2, какие у спеки обязательные секции и почему весь современный API-tooling — Swagger UI, Postman, кодогенераторы — это надстройка над одним YAML- или JSON-файлом.

Если REST — это набор соглашений о том, как использовать HTTP, то OpenAPI — это формальный язык для записи конкретных API: какие endpoints есть, какие параметры принимают, какие схемы JSON возвращают. Прочитав корректный OpenAPI-документ, вы узнаёте про API всё, что нужно для написания клиента, без единого вопроса в Slack автору.


Откуда взялся OpenAPI: краткая хронология

В 2010 году Tony Tam в компании Wordnik разработал внутренний формат для описания их HTTP API. Формат назывался Swagger. В 2011 он стал open-source, в 2014-2015 вокруг него вырос огромный экосистем инструментов: Swagger UI (рендерит спеку в интерактивный браузер), Swagger Codegen (генерирует клиенты на 30+ языках), Swagger Editor.

В 2015 году SmartBear (новый владелец Swagger) передал спецификацию в Linux Foundation, где была создана OpenAPI Initiative. Swagger 2.0 был переименован в OpenAPI Specification (OAS). Бренд Swagger остался за инструментами (Swagger UI, Swagger Editor), а сама спецификация теперь называется OpenAPI.

Эволюция OpenAPI Specification
Swagger 1.x2011-2014. Внутренний формат Wordnik, разные мелкие версии. Сейчас используется только в очень старых системах
Swagger 2.02014. Большой релиз. Строгая структура. Многие legacy-системы и до 2026 живут на 2.0 -- конвертация на 3.x не всегда тривиальна
OpenAPI 3.0Июль 2017. Передача в Linux Foundation. Переработка components, security, content negotiation. До 2024 -- основная версия в индустрии
OpenAPI 3.1Февраль 2021. Главное событие -- полная совместимость с JSON Schema 2020-12. Webhooks как объект первого класса. nullable заменён на type array. Текущий рекомендуемый baseline
OpenAPI 3.2Сентябрь 2025. Streaming responses (SSE/JSONL), hierarchical tags, поддержка HTTP QUERY (RFC 9651), уточнение security и parameter styles. Совместимость с 3.1 -- внедряется постепенно

Практически: если вы пишете новый API в 2026 году — берите OpenAPI 3.1. Если интегрируетесь с готовым API — может прилететь любая версия от 2.0 до 3.2. Большинство инструментов (Swagger UI, Redoc, openapi-generator) поддерживает все эти версии, но конкретные фичи (например, webhooks как top-level объект) появились только в 3.1.

NOTE

Различайте бренды. Swagger — это инструменты (Swagger UI, Swagger Editor, Swagger Codegen), которые делает SmartBear. OpenAPI — это спецификация, которой управляет OpenAPI Initiative. Когда коллега говорит «отправь мне Swagger», в 99% случаев он имеет в виду «отправь OpenAPI YAML/JSON, который можно открыть в Swagger UI».


Зачем нужна формальная спецификация

Без OpenAPI документация API живёт в Confluence, README или Notion. Это значит, что человек её читает, человек интерпретирует, человек пишет клиент по этой интерпретации. Опечатка в документации — клиент сломан. Документация устарела на квартал — клиент сломан. Backend поменял формат поля — frontend узнаёт об этом из 500 на проде.

OpenAPI решает эту проблему через простую идею: спецификация в машинно-читаемом формате, и из неё генерируются и документация для людей, и код для машин.

Что можно сделать из одного OpenAPI-файла
OpenAPI YAML/JSONЕдиный источник правды. Хранится в репозитории рядом с кодом, версионируется в git
Swagger UI / RedocИнтерактивная HTML-документация. 'Try it out' прямо из браузера. Для людей
openapi-python-clientСгенерированный Python-клиент с typed методами. import client; client.get_user(id=42) вместо requests.get(...)
Mock serverPrism, Mockoon -- поднимают сервер, который отвечает по спеке. Frontend разрабатывается параллельно с backend
Postman / InsomniaИмпорт спеки -> готовая коллекция запросов в GUI-клиент
Contract testsSchemathesis, Dredd: на каждый endpoint генерируются property-based тесты, которые проверяют, что сервер реально отвечает по спеке
ValidationMiddleware на сервере проверяет request/response на соответствие схеме. Поломал контракт -- упал тест

Это ровно та причина, по которой Junior DE стоит научиться читать OpenAPI как родной русский. Когда вам приносят задачу «забери данные из API сервиса X», и сервис X отдаёт https://api.example.com/openapi.yaml — вы за пять минут видите все endpoints, форматы и нужные заголовки. Без OpenAPI вы час разбираетесь по примерам в README и пишете в чат «а как у вас называется поле created_at или createdAt?».


Структура спецификации: семь ключевых секций

OpenAPI-документ — это один JSON или YAML файл с фиксированной верхнеуровневой структурой. У документа есть семь ключевых секций. Три обязательны, остальные опциональны, но в реальном API почти всегда присутствуют.

Структура OpenAPI 3.1 документа
openapiВерсия спеки. Строка вида '3.1.0'. Обязательно. По этому полю инструменты понимают, какую грамматику парсить
infoМетаданные: title, version (версия API, не спеки!), description, contact, license. Обязательно. Используется для заголовка в Swagger UI
pathsГлавное содержимое: словарь путей и методов. /users/{id} -> get/post/put/delete. Обязательно для классического REST API
serversСписок base URL. Обычно production + staging + dev. Если опущено, default -- относительный путь от документа
componentsПереиспользуемые куски: schemas, parameters, responses, security schemes. Сюда выносится всё, что встречается больше одного раза
securityГлобальные требования к авторизации. Применяются ко всем операциям, если не переопределены
tagsЛогические группы операций. Swagger UI рендерит их как разделители. В 3.2 появилась иерархия (parent/children)
webhooksПоявилось в 3.1. Описание исходящих вебхуков, которые сервер шлёт клиентам. Не путать с paths (входящие запросы)
externalDocsСсылка на внешнюю документацию (например, гайд в Confluence)

Заметим, что components — это библиотека определений, на которые ссылаются из paths через механизм $ref. Это критично для DRY: если у нас 30 endpoints возвращают один и тот же объект User, мы не пишем его 30 раз — мы выносим в components/schemas/User и ссылаемся.


YAML или JSON: какой формат выбрать

OpenAPI поддерживает два формата сериализации, эквивалентных по выразительности: JSON и YAML. Файл openapi.json и openapi.yaml могут описывать абсолютно одинаковый API. Большинство инструментов читает оба.

JSON vs YAML для OpenAPI
JSONСкобки, кавычки, запятые. Машинно-нейтральный формат, парсится быстрее, но визуально шумный
YAMLОтступы, без кавычек, поддержка комментариев. Менее формально, но в 5 раз компактнее визуально для тех же данных. De facto стандарт OpenAPI
Размер для людейJSON-спека на 50 endpoints -- это 3000 строк скобок. YAML той же спеки -- 1500 строк, читается как структурированный текст
КомментарииJSON по стандарту не поддерживает комментарии. YAML поддерживает через #. Для документации схем -- критично
ToolingFastAPI отдаёт по умолчанию /openapi.json. Большинство ручных спек пишутся в YAML и при необходимости конвертируются в JSON

На практике: если спеку генерирует фреймворк (FastAPI, drf-spectacular, NestJS) — почти всегда JSON; если её пишут руками — почти всегда YAML. Конвертация в обе стороны тривиальна, в Python через yaml и json модули в две строки.


Минимальный валидный OpenAPI-документ

Посмотрим на самую маленькую спеку, которая пройдёт валидацию OpenAPI 3.1. У нас один endpoint, одна операция, один ответ.

openapi: 3.1.0
info:
  title: Hello API
  version: 1.0.0
paths:
  /hello:
    get:
      summary: Возвращает приветствие
      responses:
        '200':
          description: Успешный ответ
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Hello, world!"

Эта спека описывает API из одного endpoint GET /hello, который возвращает JSON с полем message. Уже из этих 16 строк инструменты:

  • Сгенерируют интерактивную документацию в Swagger UI
  • Создадут typed Python-клиент с методом client.get_hello()
  • Поднимут mock-сервер, который на запрос GET /hello вернёт {"message": "string"}
  • Запустят contract-тесты, которые проверят, что реальный сервер действительно возвращает поле message типа string

Заметьте структурную иерархию: paths -> путь /hello -> метод get -> responses -> статус-код '200' -> content -> media type application/json -> schema. Это типичная глубина OpenAPI: четыре-пять уровней вложенности. Поэтому YAML с отступами читать удобнее, чем JSON со скобками.

TIP

Скопируйте спеку выше в editor.swagger.io. Слева — YAML, справа — Swagger UI. Поменяйте Hello, world! на свой текст и нажмите «Try it out» — увидите, как работает интерактивная документация. Это и есть UX, который OpenAPI даёт бесплатно.


Чуть более реалистичный пример: /users/{id}

Минимальный пример выше — это игрушка. Реальный API содержит параметры пути, query-параметры, ошибки. Покажем второй уровень сложности: endpoint, который читает пользователя по ID, использует переиспользуемую схему и описывает ошибки 404.

openapi: 3.1.0
info:
  title: Users API
  version: 2.0.0
  description: |
    Управление учётками пользователей.
    Документация: https://docs.example.com/users
servers:
  - url: https://api.example.com/v2
    description: Production
  - url: https://staging-api.example.com/v2
    description: Staging
paths:
  /users/{user_id}:
    get:
      summary: Получить пользователя по ID
      operationId: getUserById
      tags: [users]
      parameters:
        - name: user_id
          in: path
          required: true
          schema:
            type: integer
            minimum: 1
      responses:
        '200':
          description: Пользователь найден
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          description: Пользователь не найден
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    User:
      type: object
      required: [id, email, created_at]
      properties:
        id:
          type: integer
          example: 42
        email:
          type: string
          format: email
        created_at:
          type: string
          format: date-time
    Error:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
          example: not_found
        message:
          type: string

Что нового по сравнению с минимальным примером:

  • servers — два окружения. Сгенерированный клиент даёт переключение через параметр конструктора.
  • parameters — параметр пути user_id, который описан как integer с минимумом 1. Если кто-то вызовет /users/-5, валидатор поймает ошибку.
  • operationId — уникальный идентификатор операции. Кодогенератор использует его для имени метода: client.get_user_by_id(user_id=42).
  • $ref — ссылка на переиспользуемую схему. Если у нас 20 endpoints возвращают User, мы не дублируем определение.
  • Несколько responses — кроме 200 описан 404. Клиент знает, что 404 содержит структуру {code, message}.

Как это выглядит на стороне FastAPI

В реальном Python-проекте OpenAPI-спеку обычно не пишут руками — её генерирует фреймворк из аннотаций. FastAPI генерирует OpenAPI 3.1 из подсказок типов и Pydantic-моделей. Посмотрим, как тот же endpoint выглядит в коде.

from datetime import datetime
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, EmailStr

app = FastAPI(title="Users API", version="2.0.0")


class User(BaseModel):
    id: int
    email: EmailStr
    created_at: datetime


class Error(BaseModel):
    code: str
    message: str


@app.get(
    "/users/{user_id}",
    response_model=User,
    responses={404: {"model": Error}},
    tags=["users"],
)
def get_user_by_id(user_id: int) -> User:
    if user_id != 42:
        raise HTTPException(status_code=404, detail="not found")
    return User(id=42, email="[email protected]", created_at=datetime.now())

Запустить uvicorn main:app, открыть http://localhost:8000/openapi.json — получите готовую спеку, очень близкую к нашему YAML-примеру. По адресу /docs будет Swagger UI, по /redoc — Redoc. Это и есть стандартный workflow в современном Python: типы -> автоматическая спека -> генерируемая документация.

TIP

Для Junior DE это значит следующее: если интегрируетесь с FastAPI-сервисом, спека уже есть по адресу <base_url>/openapi.json. Не нужно просить разработчиков «отправить документацию» — она генерируется автоматически из кода и всегда актуальна.


Что нового в OpenAPI 3.2 (Sept 2025)

OpenAPI 3.2, вышедший в сентябре 2025, добавляет несколько важных вещей, релевантных для Data Engineers:

Ключевые улучшения OpenAPI 3.2
Streaming responsesОписание SSE (text/event-stream) и JSONL (application/x-ndjson) как first-class объекты. До 3.2 streaming приходилось описывать как 'тут произвольный поток байтов'
Hierarchical tagsТеги могут иметь parent/children. Swagger UI рендерит дерево разделов вместо плоского списка. Большие API становятся читаемее
QUERY methodHTTP QUERY (RFC 9651) -- GET с body. Раньше для search-endpoints приходилось выбирать между GET с query string (короткая) и POST (некорректно семантически). QUERY решает дилемму
Уточнения securityЛучшее описание OAuth2 scopes на уровне отдельных операций, а не только глобально. Меньше копипасты

На практике для Junior DE в 2026: пишите новые спеки как 3.1, но имейте в виду, что часть API в индустрии будет постепенно переезжать на 3.2 в течение 2026-2027. Инструменты Swagger UI и Redoc уже поддерживают 3.2.


Kubernetes: декларативные манифесты и API-версионирование

Где OpenAPI не подходит

OpenAPI — спецификация для HTTP-based API с request/response семантикой. Она хорошо описывает REST, частично описывает RPC-подобные API. Плохо подходит для:

  • GraphQL — у GraphQL свой формат описания схемы (SDL). OpenAPI нерелевантен.
  • gRPC — описывается через .proto файлы. OpenAPI используется только если поверх gRPC сделан REST-gateway.
  • WebSocket / двунаправленные протоколы — OpenAPI описывает только запрос-ответ. Для bidirectional streaming используется AsyncAPI (отдельный, родственный стандарт).
  • Real-time / событийные системы — Kafka topics, AMQP queues — это AsyncAPI, не OpenAPI.

Для Junior DE правило простое: если API общается через HTTP запросами и ответами — OpenAPI. Если что-то другое — другая спецификация (или вообще без спецификации, что тоже встречается).


Итоги урока

OpenAPI — это машинно-читаемое описание HTTP API в формате JSON или YAML. Эволюция: Swagger 2.0 (2014) -> OpenAPI 3.0 (2017) -> 3.1 (2021, JSON Schema 2020-12) -> 3.2 (2025, streaming/QUERY/иерархия тегов). Сейчас baseline для нового API — 3.1.

Структура документа: обязательные секции openapi, info, paths; опциональные servers, components, security, tags, webhooks. YAML — стандарт для ручных спек, JSON — для генерируемых фреймворком.

Из одной OpenAPI-спеки получается: интерактивная документация (Swagger UI/Redoc), кодогенерированный клиент, mock-сервер, contract-тесты, Postman-коллекция. Это даёт огромный leverage: 200 строк YAML заменяют 1000 строк ручной документации и плюс минус 500 строк boilerplate-кода клиента.

В следующем уроке разберём components/schemas глубоко — это сердце спецификации, описывающее формы данных, и именно там Data Engineer проводит большую часть времени при чтении чужих API.


Проверка знанийKnowledge check
Команда сообщает: 'наш API на FastAPI, спека по адресу /openapi.json'. Junior открывает файл -- там 8000 строк JSON. Какие действия наиболее продуктивны для понимания API за 30 минут?
ОтветAnswer
Не читать 8000 строк глазами. Действия по убыванию полезности: (1) Открыть Swagger UI по адресу /docs или /redoc -- это та же спека в виде интерактивной документации, удобной для обзора. Сразу видно тэги, группы операций, схемы. (2) Найти секцию 'tags' и понять логические группы endpoints -- обычно их 5-15. (3) В components/schemas найти 3-5 главных моделей (User, Order, Product) -- они переиспользуются везде. (4) Посмотреть на security -- какая аутентификация требуется. (5) Если будете писать клиент -- запустить openapi-python-client на этой спеке, получить готовый Python-пакет с typed методами. Чтение JSON-спеки руками -- крайнее средство, когда инструменты сломались. OpenAPI задумана для машин, а не для людей.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Какое самое важное изменение принёс OpenAPI 3.1 относительно 3.0?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 3