OpenAPI
OpenAPI — это открытый стандарт или спецификация для машиночитаемого описания HTTP API, таких как REST-API. С помощью спецификации описываются эндпоинты (URL, по которому можно получить доступ к функциональности API), методы, параметры, заголовки, cookies и другие аспекты работы современных API.
До середины 2010-х годов каждый разработчик или компания самостоятельно определяли, как документировать свои API. Это приводило к огромному количеству ошибок и трате времени на внедрение очередного микросервиса. Для решения этой проблемы в 2010 году началась разработка стандартизированного описания API, которое позже получило название Swagger.
В 2015 году Swagger был передан организации OpenAPI Initiative, а вскоре спецификация стала называться OpenAPI. Сегодня без нее невозможно представить разработку большинства крупных проектов — без единого машиночитаемого формата интеграция множества внешних и внутренних сервисов стала бы крайне сложной задачей.
Создание стандарта также привело к появлению Design-First подхода в разработке API, при котором вы еще до написания кода описываете каждый элемент API таким образом, чтобы его могли понять и люди, и компьютеры. Это требует временных затрат на этапе проектирования, но в долгосрочной перспективе снижает количество ошибок и избавляет от необходимости переписывать код.
Структура OpenAPI
Спецификация описывается в формате JSON или YAML и представляет собой файл (или несколько — для больших проектов), который содержит множество элементов. Кратко рассмотрим основные секции спецификации OpenAPI:
openapi— первая и обязательная секция с версией спецификации, по которой инструменты проверяют совместимость.info— метаданные API. Своего рода «паспорт» документа. Для публичных или партнерских API рекомендуется подробно заполнять ключdescription, чтобы разработчикам и ИИ-агентам было понятнее.servers— список серверов, на которые направляются запросы к API. Разделены по назначению, например, тестовый и рабочий.paths— доступные эндпоинты и методы, которые через них вызываются. Каждой HTTP-операции должен быть присвоен путь. Подробнее см. раздел HTTP-методы.components— многократно используемые компоненты, которые встречаются в разных частях спецификации. Подробнее см. раздел Описание переиспользуемых объектов.webhooks— список входящих вебхуков. Описывает, какие запросы типаPOSTAPI отправляет клиенту при возникновении заданных событий, например уведомления об отправке заказа.security— требования авторизации для операций. Подробнее см. раздел Безопасность и аутентификация.tags— секция группировки эндпоинтов операций для облегчения навигации. Удобна для больших API, в которых операции можно сгруппировать по типу, напримерusers,payments.externalDocs— ссылки на дополнительную документацию. При необходимости также можно добавлять ссылки к конкретным эндпоинтам для уточняющей информации.
Упрощенный пример структуры
openapi: 3.1.0
info:
title: Книжный магазин
description: Простой API для работы с книгами
version: 1.0.0
servers:
- url: https://api.bookshop.example.com/v1
paths:
post:
summary: Добавить новую книгу
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BookCreate'
responses:
'201':
description: Книга создана
content:
application/json:
schema:
$ref: '#/components/schemas/Book'
/books/{id}:
get:
summary: Получить одну книгу по ID
parameters:
- name: id
in: path
required: true
schema:
type: integer
description: ID книги
responses:
'200':
description: Найденная книга
content:
application/json:
schema:
$ref: '#/components/schemas/Book'
'404':
description: Книга не найдена
components:
schemas:
Book:
type: object
properties:
id:
type: integer
title:
type: string
author:
type: string
year:
type: integer
price:
type: number
BookCreate:
type: object
required: [title, author]
properties:
title:
type: string
author:
type: string
year:
type: integer
price:
type: number
HTTP-методы
HTTP-методы описываются внутри секции paths и задают конкретный путь и объект операции. OpenAPI поддерживает следующие методы:
get— получение ресурса или списка ресурсов;post— создание ресурса, запуск действия или отправка формы;put— полное обновление ресурса или создание нового, если его нет;patch— частичное обновление ресурса;delete— удаление ресурсов;head— получение заголовков (метаданных) ресурса без его содержимого;options— получение списка поддерживаемых опций и CORS-политик;trace— получение полного HTTP-запроса обратно, чтобы клиент мог проверить, не изменился ли запрос по пути;query(появился в OpenAPI 3.2) — выполнение сложных поисковых или фильтрующих операций.
Также в секции path определяется все, что ожидается получить в теле каждого запроса (блок requestBody), и как это должно быть валидировано (блок schema).
Описание переиспользуемых объектов
При описании API часто возникает ситуация, когда нужно многократно описывать один и тот же объект. В OpenAPI есть специальная секция components, в которой можно описать все часто повторяющиеся структуры данных (schemas), а потом просто ссылаться на них. Пример схемы для объекта User:
components:
schemas:
User:
type: object
properties:
id:
type: integer
name:
type: string
Имея такую схему, можно сослаться на нее в другой части спецификации с помощью ссылки: $ref: '#/components/schemas/User'.
Для создания составных типов объектов можно использовать ключи allOf, oneOf и anyOf. Разберем их особенности:
-
allOf— объект сочетает все перечисленные схемы. Например, рольAdminнаследует все права ролиEditorи добавляет свои (возможность блокировать пользователей):Admin: allOf: - $ref: '#/components/schemas/Editor' - type: object properties: canBanUsers: type: boolean -
oneOf— объект должен иметь свойства только одной из перечисленных схем. Например, пользователь должен иметь рольAdmin,EditorилиViewer:User: oneOf: - $ref: '#/components/schemas/Admin' - $ref: '#/components/schemas/Editor' - $ref: '#/components/schemas/Viewer' -
anyOf— значение должно соответствовать хотя бы одной из перечисленных схем. Например, контактная информация может бытьemail,phoneили сочетать оба способа:Contact: anyOf: - type: object properties: email: { type: string, format: email } required: [email] - type: object properties: phone: { type: string, pattern: '^\+?[1-9]\d{1,14}$' } required: [phone]
Безопасность и аутентификация
Основные вещи, связанные с безопасностью в OpenAPI, описываются в двух местах:
-
components/securitySchemes— описание способов защиты (API-ключи, HTTP-аутентификация, OpenID Connect и другие). На объекты из этого блока также можно ссылаться через$refв других частях спецификации. Например, опишем метод аутентификации по API-ключу, который нужно передать в заголовкеX-API-Key:components: securitySchemes: api_key: type: apiKey name: X-API-Key in: header -
security— привязка способов защиты к конкретным методам, ко всему эндпоинту или ко всей спецификации.Чтобы назначить способ защиты на всю спецификацию, поместите
securityв корневую часть:security: - api_key: []Чтобы назначить способ защиты на конкретный метод или путь, поместите
securityв блокpaths. Например, на получение списка пользователей:paths: /users: get: security: - api_key: []
В публичных API часто есть методы или эндпоинты, для которых защита не требуется. В таком случае можно передать в security пустой массив. Например, отключим защиту на эндпоинте /login:
/login:
post:
security: []
Сравнение версий
С переходом со Swagger 2.0 на OpenAPI 3.0 и выше в спецификации произошли значительные изменения. Документация стала намного логичнее и понятнее, а функциональность API заметно расширилась. Рассмотрим основные изменения:
| Аспект | Swagger 2.0 | OpenAPI 3.0+ |
|---|---|---|
| Адреса серверов | Блоки host, basePath, schemes |
Секция servers |
| Тело HTTP-запроса | Описывается в параметрах объектов | Блок requestBody в описании запроса |
| Повторяющиеся компоненты | Блоки definitions, securityDefinitions, parameters, responses |
Секция components |
| Безопасность | Ограниченные схемы | Поддержка всех популярных методов |
| Поддержка примеров | Один пример на поле или схему | Множество примеров с описаниями |
| Составные типы объектов | Нет | Да (ключи allOf, oneOf и anyOf) |
Кроме того, в OpenAPI 3.0+ появились дополнительные блоки и свойства:
components.callbacks— поддержка асинхронных уведомлений;webhooks— поддержка вебхуков;components.links— возвращение в ответе дополнительных ссылок для пользователя;in: cookie— поддержка cookie в параметрах;.parameters.style— определяет, как значение параметра должно быть сериализовано;.parameters.explode— определяет, нужно ли разбивать сериализованный параметр на логические компоненты.
Переход со Swagger 2.0 на OpenAPI 3.0+
Swagger 2.0 значительно уступает более поздним версиям спецификации, поэтому переход рекомендуется для любых API. Вы можете использовать автоконвертер (например, swagger2openapi
- Заголовок
swagger: "2.0"меняется наopenapi: <версия_спецификации>(например,openapi: 3.2.0). - Содержимое
host,basePath,schemesпереносится в секциюservers. - Все переиспользуемые объекты переносятся в
components.schemas. - Методы защиты из
securityDefinitionsпереносятся вcomponents.securitySchemes. - Параметры
parametersпереносятся в блокrequestBody. - При необходимости постепенно внедряются новые функции (
examples,links,callbacksи другие).
Инструменты и экосистема
Так как OpenAPI-спецификация является стандартом для большинства API, вокруг нее возникла обширная экосистема, в которой можно найти все необходимые инструменты. Рассмотрим основные задачи, которые возникают при разработке API, и инструменты, которые помогут их решить:
| Задача | Примеры инструментов |
|---|---|
| Генерация SDK | |
| Красивая документация | |
| Средство проверки документации | |
| Тестирование | |
| Полноценная API-платформа |
Ограничения и альтернативы
OpenAPI Specification — это доминирующий стандарт для описания REST API, однако для других задач он может быть менее эффективен, предполагать использование дополнительных решений или быть вовсе бесполезным. Рассмотрим виды API, с которыми могут возникнуть проблемы:
-
Асинхронные API: OpenAPI ориентирован на схему «запрос — ответ», но асинхронные API, такие как WebSocket, подразумевают непрерывный обмен сообщениями без четкой структуры. Спецификацию придется расширить, либо описание API получится неполным и интуитивно непонятным.
Альтернатива — AsyncAPI
— спецификация, которая ориентирована на события. -
gRPC:
- в OpenAPI нет полноценной поддержки многопоточности и нескольких языков;
- не позволяет получить высокую производительность, которая является одним из основных преимуществ gRPC;
- построен вокруг структурированных форматов сообщений (JSON Schema, XML), тогда как gRPC использует бинарный Protobuf.
Альтернатива — встроенные инструменты, такие как protoc, Buf, gRPC-Gateway, ConnectRPC.
-
GraphQL: OpenAPI не умеет работать с гибкими запросами, которые лежат в основе API, подобных GraphQL.
Альтернатива — GraphQL SDL
.
Работа с API в Yandex Cloud
Yandex Cloud предлагает Yandex API Gateway — полностью управляемый сервис для разработки, развертывания, управления и обеспечения безопасности API-шлюзов. Среди основных возможностей сервиса:
- создание и изменение OpenAPI-спецификаций;
- автоматическое масштабирование сервера при увеличении количества запросов;
- возможность использовать домены сервиса при обращении к API;
- создание канареечных релизов (доступных определенным пользователям);
- интеграция с другими сервисами Yandex Cloud без необходимости писать код;
- защита шлюзов от DDoS-атак и ботов.
Подробнее о сервисе см. в документации.