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-атак и ботов.
Подробнее о сервисе в документации.