OpenAPI — это открытая спецификация для описания REST API. Изначально она называлась Swagger, но в 2016 году была переименована в OpenAPI Specification и передана под управление OpenAPI Initiative. На данный момент Swagger — это набор инструментов для работы со спецификацией OpenAPI (Swagger UI, Editor, Codegen).

В OpenAPI определяются пути, параметры, тела запросов и ответов, коды статусов, схемы данных, типы аутентификации. В статье мы рассмотрим спецификацию OpenAPI версии 3.0: разберем из каких обязательных блоков она состоит и как правильно описывать типы данных и параметры запросов.

Создаем первый эндпоинт

Для начала создадим пример, на котором изучим базовые концепции. Ниже представлен yaml-файл с одной точкой API:

openapi: 3.0.3
info:
  title: API
  version: 0.1.0
servers:
  - url: http://localhost:4010
paths:
  /test:
    get:
      summary: Test
      tags: [test]
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required: [id, title]
                  properties:
                    id:
                      type: string
                      description: Unique todo identifier
                    title:
                      type: string
                      description: Human readable title

Файл спецификации содержит описание единственного эндпоинта /test, который возвращает массив объектов. Для демонстрации его функциональности мы используем два инструмента: Prism (для развертывания мок-сервера) и Swagger UI (для визуализации документации и интерактивного тестирования).

docker-compose 
services:
  prism:
    image: stoplight/prism:latest
    command: >-
      mock -h 0.0.0.0 -p 4010 --cors --errors --dynamic /spec/${SPEC_PATH:-openapi/openapi.yaml}
    ports:
      - "${PRISM_PORT:-4010}:4010"
    volumes:
      - ./docs:/spec:ro
    restart: unless-stopped

  swagger:
    image: swaggerapi/swagger-ui
    environment:
      SWAGGER_JSON: /spec/${SPEC_PATH:-openapi/openapi.yaml}
    ports:
      - "${SWAGGER_PORT:-8080}:8080"
    volumes:
      - ./docs:/spec:ro
    depends_on:
      - prism
    restart: unless-stopped

Далее запускаем контейнеры при помощи команды SPEC_PATH=basic.yaml docker compose up -d, затем переходим по ссылке http://localhost:8080/. Если всё правильно работает, то в интерфейсе появится роут test.

Затем раскрываем его и нажимаем кнопки "Try it out" и "execute". После чего увидим примерно такой ответ:

Практический пример документирования API

В этом разделе мы создадим API-документацию для блога, чтобы наглядно понять концепции OpenAPI. В примере подробно разберем, как документировать эндпоинты.

Структура спецификации

Так как полный файл спецификации достаточно объемный, то в статье рассматриваются только его ключевые элементы. Полная версия файла и инструкция по запуску находится тут. Спецификация OpenAPI состоит из восьми корневых элементов:

openapi (обязательный)

Версия спецификации OpenAPI всегда указывается первой строкой:

openapi: 3.0.3

info (обязательный)

Раздел метаданных API. Обязательно указываются название (title) и версия (version). Опционально добавляются описание (description), контакты (contact) и лицензия (license). Описание можно форматировать через Markdown.

info:
  title: Blog API
  description: |
    **Простое API блога** для изучения OpenAPI 3.0
  version: 1.0.0
  contact:
    name: Blog API Support
    email: support@blog.com
  license:
    name: MIT

servers

В этом разделе указывается список серверов, на которые могут отправляться запросы. URL формируются относительно базового адреса (например, https://api.blog.com/v1). В разделе variables можно настроить динамические параметры, которые будут подставляться в URL.

paths (обязательный)

В этом разделе описываются эндпоинты API: пути, HTTP-методы, параметры, тела запросов и форматы ответов, эти поля детально рассмотрим в статье позже.

paths:
  /auth/login:
    post:
      summary: Вход в систему
      tags: [Auth]
      # ... детали операции
      
  /posts:
    get:
      summary: Получить список постов
      tags: [Posts]
      # ... параметры и ответы
    post:
      summary: Создать новый пост
      tags: [Posts]
      # ... тело запроса и ответы
      
  /posts/{postId}:
    get:
      summary: Получить пост по ID
      parameters:
        - name: postId
          in: path
          required: true
          schema:
            type: integer
      # ...

components

Стандарт OpenAPI позволяет нам создавать необходимые компоненты один раз и затем переиспользовать их при необходимости.

Основные типы компонентов:

  • schemas — модели данных (User, Post, Error),

  • securitySchemes — способы аутентификации,

  • responses — общие ответы (404, 401 и т. д.),

  • parameters — переиспользуемые параметры.

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      
  schemas:
    User:
      type: object
      required: [id, email, name]
      properties:
        id: { type: integer }
        email: { type: string, format: email }
        name: { type: string }
        # ...
        
  responses:
    NotFoundError:
      description: Ресурс не найден
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

security

Объект security определяет метод аутентификации по умолчанию для всех эндпоинтов:

security:
  - BearerAuth: []

В OpenAPI поддерживаются 4 типа аутентификации, которые описаны в комментариях примера:

components:
  securitySchemes:
    # 1. API Key (в header, query или cookie)
    ApiKeyAuth:
      type: apiKey
      name: X-API-Key
      in: header
    
    # 2. HTTP аутентификация (Basic, Bearer)
    BearerAuth:
      type: http
      scheme: bearer
    
    # 3. OAuth 2.0
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://api.example.com/oauth/authorize
          tokenUrl: https://api.example.com/oauth/token
    
    # 4. OpenID Connect
    OpenID:
      type: openIdConnect
      openIdConnectUrl: https://api.example.com/.well-known/openid-configuration

Для отдельных операций можно изменить настройки безопасности:

/public:
  get:
    security: []  # Публичный доступ
    
/secure:
  get:
    security: 
      - BearerAuth: []  # Требует JWT токен

tags

Объект tags позволяет логически группировать эндпоинты API по разделам, благодаря чему становится проще ориентироваться в документации. Теги объявляются в корне файла спецификации OpenAPI:

tags:
  - name: Пользователи
    description: Управление пользователями блога
  - name: Статьи
    description: Операции с публикациями
  - name: Комментарии
    description: Работа с комментариями
  - name: Категории
    description: Управление категориями статей

После того, как мы распределим роуты, страничка документации будет выглядеть примерно так:

Каждый эндпоинт отдельно помечается соответствующими тегами:

paths:
  /users:
    get:
      tags: ["Пользователи"]
      summary: Получить список пользователей
    post:
      tags: ["Пользователи"]
      summary: Создать нового пользователя

  /posts:
    get:
      tags: ["Статьи"]
      summary: Получить список статей
    post:
      tags: ["Статьи"]
      summary: Создать новую статью

  /posts/{postId}/comments:
    get:
      tags: ["Статьи", "Комментарии"]
      summary: Получить комментарии к статье
    post:
      tags: ["Статьи", "Комментарии"] 
      summary: Добавить комментарий к статье

externalDocs

Объект externalDocs предоставляет ссылки на дополнительную документацию, которая может быть полезной для пользователей API. Изначально его можно использовать на корневом уровне:

yaml
externalDocs:
  description: Полная документация API блога
  url: https://docs.example.com/api/blog

Но при необходимости можно добавлять ссылки к конкретным эндпоинтам для уточняющей информации:

yaml
paths:
  /posts/{postId}/comments:
    get:
      summary: Получить комментарии к статье
      externalDocs:
        description: Руководство по работе с комментариями
        url: https://docs.example.com/guides/comments

Структура эндпоинтов и HTTP-методов

Рассмотрим детализацию документации для конкретных эндпоинтов API на примере работы со статьями блога. В данном примере описана спецификация для эндпоинтов /posts и /posts/{postId}, где для каждого определены соответствующие HTTP-методы: GET, POST, PUT, DELETE, PATCH.

yaml
paths:
  /posts:
    get:        # Получить список постов
      summary: Получить список постов
      tags: [Статьи]
      security: []  # Публичный endpoint
      parameters: 
        - name: page
          in: query
          schema: { type: integer, default: 1 }
      responses:
        '200':
          description: Список постов
          # ...
          
    post:       # Создать новый пост
      summary: Создать новый пост
      tags: [Статьи]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PostCreate'
      responses:
        '201':
          description: Пост создан
          # ...

  /posts/{postId}:
    get:        # Получить пост по ID
      # ...
    put:        # Обновить пост
      # ...  
    delete:     # Удалить пост
      # ...

Важные параметры HTTP-методов:

  • summary — краткое описание операции,

  • tags — группировка эндпоинтов (например, [Статьи]),

  • security — настройки доступа ([] для публичных эндпоинтов),

  • parameters — параметры запроса (query, path, header),

  • responses — описание возможных ответов (200, 201, 400, etc.),

  • requestBody — тело запроса для POST/PUT операций.

Обратите внимание на то, как описывается параметр в GET-методе у /posts.

Параметр page является query-параметром целочисленного типа со значением по умолчанию 1. В запросе он передается через строку запроса: /posts?page=2.

В методе POST для /posts используется ссылка $ref: '#/components/schemas/PostCreate'. Конструкция $ref представляет собой ссылку на переиспользуемую схему данных PostCreate, определенную в разделе components/schemas. Такой подход позволяет избежать дублирования кода, централизованно управлять схемами данных и упростить поддержку и обновление спецификаций.

Параметры

В OpenAPI существует четыре варианта передачи параметров: path, query, header и cookie. Каждый тип имеет свою область применения. 

Path-параметры — обязательные параметры, встроенные в URL-путь. Используются для идентификации конкретного ресурса:

paths:
  /posts/{postId}:
    get:
      parameters:
        - name: postId
          in: path
          required: true
          schema:
            type: integer
            minimum: 1

Query-параметры — необязательные параметры, передаваемые после знака ? в URL. Применяются для фильтрации, сортировки и пагинации:

paths:
  /posts:
    get:
      parameters:
        - name: page
          in: query
          description: Номер страницы
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: published
          in: query
          schema:
            type: boolean
            default: true

Header-параметры — передаются в HTTP заголовках запроса. Используются для метаданных, версионирования API и авторизации:

paths:
  /status:
    get:
      parameters:
        - name: X-API-Version
          in: header
          description: Версия API
          schema:
            type: string
            enum: [v1, v2]
            default: v1

Cookie-параметры — передаются через HTTP cookies. Применяются для сессий, настроек пользователя и состояния:

paths:
  /cart:
    get:
      parameters:
        - name: session_id
          in: cookie
          description: Идентификатор сессии
          schema:
            type: string
            minLength: 1

После описания параметров в спецификации они автоматически появляются в интерфейсе Swagger UI. Параметры группируются по типам и отображаются с описаниями и примерами:

Path-параметры обязательны, Query-, Header- и Cookie-параметры опциональны по умолчанию. Для пояснения параметров используйте поле description. Валидацию определяйте через schema (тип, ограничения, значения по умолчанию)

Request Body

В этом разделе описывается тело запроса для методов, у которых есть payload (обычно POST/PUT/PATCH). Обязательно указывайте content с медиатипами (например, application/json) и схему (schema) — часто через $ref на components/schemas. Флаг required: true означает, что тело запроса обязательно.

paths:
  /posts:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PostCreate'
            example:
              title: "Изучаем OpenAPI"
              content: "В этой статье разберем основы..."
              published: false

Responses

Раздел ответов описывает возможные результаты выполнения операции по HTTP статус-кодам. Для каждого ответа указывайте description, а при наличии тела ответа — content и schema (например через $ref). Стандартные ответы об ошибках удобно выносить в components/responses и переиспользовать.

Компоненты и схемы

Компоненты размещаются в объекте components и позволяют переиспользовать общие элементы спецификации через поле $ref. При создании моделей данных стоит использовать следующие поля:

  • type — указывает тип данных, в нашем примере это объект JSON

  • properties — определяет все поля объекта с их типами и ограничениями

  • required: [...] — массив обязательных полей, которые должны присутствовать

  • example — примеры значений для полей, упрощают понимание и тестирование

components:
  schemas:
    User:
      type: object
      required: [id, email, name]
      properties:
        id: { type: integer, readOnly: true, example: 1 }
        email: { type: string, format: email, example: "john@blog.com" }
        name: { type: string, maxLength: 100, example: "John Doe" }

    Post:
      type: object
      required: [id, title, content]
      properties:
        id: { type: integer, readOnly: true, example: 42 }
        title: { type: string, maxLength: 200 }
        content: { type: string }
        author: { $ref: '#/components/schemas/User' }

Также дополнительно можно использовать следующие поля:

  • nullable: true — позволяет принимать значение null

  • oneOf/anyOf/allOf — логические операции для схем данных
    - oneOf — значение должно соответствовать одной из схем (варианты)
    - anyOf — может соответствовать любой из схем (объединение)
    - allOf — должно соответствовать всем схемам (наследование/расширение)

  • additionalProperties — разрешает объекту иметь поля, не описанные в properties (true — любые поля разрешены, false — разрешены только указанные)

  • uniqueItems: true — для массивов, гарантирует уникальность элементов

securitySchemes

Схемы аутентификации определяются один раз, после чего они подключаются к любым эндпоинтам через security.

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

Переиспользуемые компоненты

В разделе components есть 4 объекта:

  • parameters — переиспользуемые параметры (postId, page),

  • headers — общие заголовки (X-Total-Count, X-RateLimit),

  • responses — стандартные ответы (ошибки 404, 400),

  • securitySchemes — схемы аутентификации (Bearer, API Key).

Все подключаются через $ref: '#/components/тип/название'.

parameters

Переиспользуемые параметры для нескольких эндпоинтов. Гарантирует единообразие типов и описаний.

parameters:
    PostIdParam:
      name: postId
      in: path
      required: true
      description: ID поста
      schema:
        type: integer
        minimum: 1
      example: 42

PostIdParam — параметр для переиспользования:

  • name: postId — имя параметра,

  • in: path — параметр в пути URL (/posts/{postId}),

  • required: true — обязательный,

  • schema — целое число от 1,

  • example: 42 — пример значения.

Использование: $ref: '#/components/parameters/PostIdParam'

headers  

Переиспользуемые заголовки ответов:

headers:
    TotalCount:
      description: Общее количество элементов
      schema:
        type: integer
      example: 150

TotalCount — заголовок для переиспользования:

  • description — описание

  • schema — целое число

  • example — пример

Использование: $ref: '#/components/headers/TotalCount'

responses

Тут находятся шаблоны стандартных ответов API. Они определяют HTTP-ответы со ссылками на схемы данных.

responses:
    ValidationError:
      description: Ошибка валидации
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError'
    NotFound:
      description: Ресурс не найден
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

ValidationError — ответ для ошибок валидации с деталями по каждому полю. NotFound — ответ для несуществующих ресурсов. Обратите внимание на то, что имена схем и ответов(responses) могут совпадать, за счет того что у них разные пути к конечным объектам. 

Response содержит:

  • description — описание ответа

  • content — тип контента (обычно JSON)

  • schema — ссылка на структуру данных в components/schemas

Пример использования:

paths:
  /posts:
    post:
      responses:
        '400':
          $ref: '#/components/responses/ValidationError'
        '404':
          $ref: '#/components/responses/NotFound'

Примеры JSON-ответов:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Неверный формат email"
  }
}
{
  "code": "VALIDATION_ERROR",
  "message": "Ошибка валидации входных данных",
  "errors": [
    {
      "field": "email",
      "code": "INVALID_FORMAT", 
      "message": "Неверный формат email"
    }
  ]
}

securitySchemes

Схемы аутентификации определяют способы защиты API. После объявления их можно применять ко всему API или отдельным эндпоинтам. Ниже представлен пример для BearerAuth (схема JWT-аутентификации через заголовок Authorization):

securitySchemes:
  BearerAuth:
    type: http
    scheme: bearer
    bearerFormat: JWT
    description: |
      JWT токен в заголовке Authorization.
      Пример: `Authorization: Bearer <token>`

SecurityScheme содержит:

  • type — тип аутентификации (http, apiKey, oauth2, openIdConnect),

  • scheme — схема HTTP-аутентификации (bearer, basic),

  • bearerFormat — формат токена (опционально),

  • description — описание использования.

Глобальное применение:

security:
  - BearerAuth: []

Применение к эндпоинту:

paths:
  /posts:
    post:
      security:
        - BearerAuth: []
      # ...
  /public:
    get:
      security: []  # Отключение аутентификации
      # ...

Разбиение спецификации OpenAPI на файлы

Монолитная спецификация OpenAPI быстро становится большой и сложной при росте API. Файл в несколько тысяч строк усложняет навигацию, код-ревью и командную работу. Модульная структура решает эти проблемы через разделение ответственности: каждый компонент хранится в отдельном файле и подключается через механизм ссылок $ref.

Корневой openapi.yaml содержит только метаинформацию и ссылки:

openapi: 3.0.3
info:
  title: Blog API
  version: 1.0.0

paths:
  /posts:
    $ref: './paths/posts.yaml'
  /posts/{postId}:
    $ref: './paths/posts.{postId}.yaml'

components:
  schemas:
    Post:
      $ref: './components/schemas/Post.yaml'

paths/posts.yaml описывает операции с коллекцией:

get:
  summary: Получить список статей
  responses:
    '200':
      content:
        application/json:
          schema:
            $ref: '../components/schemas/PostList.yaml'

components/schemas/Post.yaml определяет структуру данных:

type: object
required: [id, title, content]
properties:
  id: { type: integer }
  title: { type: string, maxLength: 200 }
  content: { type: string }

В результате вместо одного большого файла мы получаем модульную структуру с интуитивно понятными названиями. Пример организации файлов:

Механизм $ref поддерживает относительные пути от текущего файла. При ссылке из paths/ на компоненты используется префикс ../components/. Внутри одной директории можно ссылаться напрямую: ./User.yaml. Полный пример разбиения монолитного файла можете посмотреть на гитхабе

Валидация файлов спецификации 

Для проверки OpenAPI-документации используются два инструмента с разными задачами. Для проверки синтаксиса используется yq. Redocly CLI проверяет файл на соответствие спецификации OpenAPI. Оба инструмента легко интегрируются в CI/CD-процессы.

Установка инструментов:

sudo snap install yq
npm install -g @redocly/cli

Сначала проверим корректность YAML-файла. Утилита yq позволяет найти синтаксические ошибки. Для проверки нужно выполнить следующую команду:

yq e '.' docs/openapi/openapi.yaml >/dev/null && echo "OK"

При успешной проверке команда выведет OK. В случае ошибки будет показано сообщение с указанием проблемной строки.

После проверки синтаксиса мы должны удостовериться, что содержимое файла соответствует стандарту OpenAPI и не содержит логических ошибок. Для этого применяется инструмент Redocly CLI. Пример команды для валидации:

redocly lint docs/openapi/openapi.yaml

При наличии ошибок Redocly покажет детальное описание проблем с указанием файлов и путей.

Общие выводы

OpenAPI 3.0 представляет собой стандарт документирования REST API, обеспечивающий единый контракт между фронтендом и бэкендом. Спецификация описывает все аспекты API: эндпоинты, параметры, модели данных, методы аутентификации и форматы ответов.

Автор alex_name_m


НЛО прилетело и оставило здесь промокод для читателей нашего блога:
— 15% на заказ любого VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.

Комментарии (1)


  1. ivvi
    09.12.2025 18:31

    OpenAPI — это открытая спецификация для описания REST API.

    Ну не только REST API. Как будто в мире есть только рест, и любой апи на протоколе хттп является рестом...

    OpenAPI прекрасно подходит и для не-RESTful API, например, для RPC HTTP API или Action-oriented (оно же Operation-centric) HTTP API. Читал, что в версии 4.0 собираются даже поддержку gRPC и асинхронщины прикрутить.

    Нет никаких проблем описать в опенапи эндпоинт типа /doSomethingStrange. REST тут не при чем.

    В остальном спасибо, конечно, но непонятно, к чему и почему это "пошаговое руководство". Просто краткий пересказ общедоступной спеки.