Для кого эта статья
В основном для аналитиков, которые впервые сталкиваются с необходимостью описания запросов в Swagger, но может быть полезна всем, кто хочет разобраться или ищет подсказку как описывать запросы в этом формате.
Плюсы
Если вы в первый раз решили использовать OpenAPI/Swagger, то может показаться, что это слишком сложно в плане синтаксиса, но плюсы перевешивают. Давайте их обозначим:
-
Для большого количества методов с повторяющимися элементами OpenAPI позволяет в итоге ускорить описание
-
OpenAPI дает более широкие возможности описания запросов и их элементов, чем любая таблица в Confluence.
-
Swagger можно использовать при тестировании.
-
Из готового документа можно сгенерировать сервер и клиент.
Я часто встречал мнение, что OpenAPI/Swagger подходит только для генерации из кода, и что синтаксис для написания руками перегружен для большинства джунов-аналитиков. Но, на мой взгляд, это не так: этот формат, древовидный и хорошо задокументированный, изучать чуть сложнее, чем json.
Концепция
Документ YAML OpenAPI представляет собой дерево с набором ветвей. Есть несколько базовых ветвей, таких как запросы или компоненты. Они в свою очередь также могут содержать дополнительные ветви, содержащие описание операций, параметры запросов и схемы ответов.
Важно, что можно ссылаться на существующие объекты с помощью указания путей до них через $ref, например: «#/components/schemas/AllOfExampleGet». И это одно из ключевых преимуществ: какие-то элементы могут использоваться повторно.
Чтобы начать описывать запросы, достаточно освоить два основных раздела: запросы и компоненты.
Компоненты
Начнем с компонентов, основных кирпичиков, позволяющий вынести за пределы конкретных запросов однотипные описания. Вынос описания в отдельные компоненты дает ряд преимуществ:
-
уменьшает копипаст и длину кода;
-
позволяет одновременно редактировать сразу несколько запросов через их общий компонент.
В компоненты можно вынести:
-
schemas: определяет структур данных (JSON Schema), которые могут использоваться в теле запросов и ответов;
-
responses: определяет возможные ответы;
-
parameters: определяет параметры запросов;
-
examples: примеры данных;
-
requestBodies: определяет тело запросов;
-
headers: определяют заголовки;
-
securitySchemes: определяет схему безопасности, такие как API ключи, токены и др.;
-
links: определяет связь между запросами для перехода между ресурсами;
-
callbacks: определяет обратные вызовы, которые описывают, как ваш API будет уведомлять клиента.
Чаще всего используются schemas и responses. Schemas позволяет описать повторяющиеся ответы и тела запросов, а responses − вынести описание ошибок (200 ответы тоже можно вынести, но чаще всего они отличаются от запроса к запросу). Headers, securitySchemes, parameters − вторые по частоте использования в документации, которую я видел.
Schemas
Schemas позволяет управлять шаблонными структурами данных. Схема содержит в себе отдельные классы, которые содержат в себе описание входящих в них элементов. Например:
Category: type: object properties: id: type: integer format: int64 example: 1 name: type: string example: Dogs xml: name: category
Это класс Category с типом объекта, у которого есть свойства: id, name. Для последних также указан тип, формат и пример значения.
Type указывает на то, какие еще параметры ожидаются для этого элемента. Type может принимать следующие значения:
Type может принимать следующие значения:
-
«string» (строка): для текстовых данных;
-
«number» (число): для числовых данных, включая как целые числа, так и числа с плавающей точкой;
-
«integer» (целое число): для целочисленных данных;
-
«boolean» (булев тип): для логических значений true или false;
-
«object» (объект): для структурированных данных, например, объектов JSON;
-
«array» (массив): для упорядоченного списка элементов;
-
«null» (пусто): для отсутствующего значения.
В случае, если это не object или array, данный элемент будет обычным параметром со значением. Заполнение класса такого типа не будет отличаться от заполнения любого другого параметра. Поэтому важнее рассмотреть object и array, которые используются чаще всего.
Object и array позволяют задавать сложные структуры, как это было показано выше для Category. При создании массива нужно дополнительно указать элемент разметки – items. Например, так:
type: array items: type: object properties: name: type: string age: type: integer email: type: string format: email
Список элементов
Значения, которые можно установить для каждого из используемых элементов:
Значения элементов:
-
title: имя свойства;
-
description: рредоставляет подробное описание свойства;
-
default: задает значение по умолчанию для свойства, если оно не предоставлено;
-
maximum и minimum: указывает максимальное и минимальное значение числового свойства;
-
exclusiveMaximum и exclusiveMinimum: указывает, являются ли максимальное и минимальное значения исключительными или включительными;
-
maxLength и minLength: указывает максимальную и минимальную длину строкового свойства;
-
pattern: применяет валидацию строки на основе регулярного выражения;
-
format: указывает формат данных. Общие форматы включают «email», «date», «uri» и т. д.
-
string (строка):
-
format: date-time — строка с датой и временем в формате RFC 3339.
-
format: date — строка с датой в формате YYYY-MM-DD.
-
format: password — строка, предназначенная для пароля.
-
-
number (число):
-
format: float — десятичное число с плавающей точкой (32 бита).
-
format: double — десятичное число с плавающей точкой (64 бита).
-
format: int32 — 32-битное целое число.
-
format: int64 — 64-битное целое число.
-
-
integer (целое число):
-
format: int32 — 32-битное целое число.
-
format: int64 — 64-битное целое число.
-
-
boolean (булев тип):
-
array (массив):
-
items — определение типа элементов массива.
-
object (объект):
-
properties — определение свойств объекта.
-
null (пусто):
-
-
nullable: позволяет свойству принимать значение null.
-
readOnly и writeOnly: указывает, является ли свойство доступным только для чтения или только для записи.
-
example: предоставляет примерное значение для свойства.
-
enum: указывает список допустимых значений для свойства.
-
items: описывает свойства элементов в массиве.
-
uniqueItems: указывает, должны ли элементы в массиве быть уникальными.
$ref: предоставляет ссылку на внешнее определение.
Этот список я рекомендую запомнить лучше всего, так как он позволяет наиболее точно описать требования к элементам класса.
Запросы
В запросе можно указать следующий набор свойств:
-
summary: краткое описание операции;
-
description: подробное описание операции;
-
tags: список тегов, к которым относится операция;
-
parameters: список параметров, необходимых для выполнения операции;
-
responses: список возможных ответов от сервера;
-
requestBody: описание тела запроса.
С summary все просто, оно отображается рядом с названием метода в свернутом виде. С description все чуть сложнее, в него можно засунуть не просто текстовое описание, markdown. Например, такой:
description: >- Метод отвечает за получение данных о пользователе * Если пользователь не найден, нужно вернуть ошибку * Если пользователь удален, нужно вернуть ошибку
Поэтому можно описывать какие-то важные вещи прямо в описании запроса.
Tags позволяют разметить, в какой блок должен быть помещен запрос. Например, вы делаете запросы про информацию о магазине. Укажите у них одинаковый тег, и они будут сгруппированы в одном блоке. Опционально описание тегов можно задать в отдельном разделе описания всей документации.
parameters имеет следующую структуру:
/users/{userId}: get: parameters: - name: userId in: path required: true description: "ID of the user" allowEmptyValue: true schema: type: integer
Параметры могут быть указаны для path, query, header и cookie. Вместо schema может быть указан content для передачи сложного json’а.
Для запросов, которые поддерживают тело запроса, указывается requestBody. Все просто: указываем обязательность, описание, тип и схему контента. Также можно указать сразу на компонент из requestBodies (на практике чаще всего используется схема, так как тело запроса редко остается неизменным).
С responses тоже все относительно понятно: это список ответов на запросы, стандартные ошибки удобно вынести в компоненты и переиспользовать.Конструкции
Конструкции anyOf, oneOf, allOf
С anyOf, oneOf и вы можете указать, например, несколько вариантов тела запроса, которые он может принимать. Встречал довольно редко.
А вот allOf − это суперудобная вещь: с ее помощью можно объединить несколько данных в одну сущность. И это позволяет, например, сложить несколько компонентов в один. Чуть ниже будет пример.
Лайфхаки
allOf
Если есть набор запросов на одну сущность, например, книги, удобнее всего описывать schemas в порядке увеличения элементов через их объединение с помощью конструкции allOf. Например, у нас есть GET-запрос, который возвращает имя и возраст пользователя. Позже у нас появляется потребность сделать POST-запрос, который добавляет еще один параметр в запросе – address. Это можно сделать через создание нового класса и объединения в нем AllOfExampleGet с новым параметром – address.
AllOfExampleGet: type: object properties: name: type: string age: type: integer AllOfExamplePost: type: object allOf: - $ref: "#/components/schemas/AllOfExampleGet" properties: address: type: integer required: - name
Required-поля
В примере выше можно заметить, что обязательность name была добавлена в новой схеме. И это суперудобно! Можно копипастить один и тот же класс в другие, расставляя новые требования к обязательности полей. Обязательность полей
Обязательность можно указать для конкретной схемы. Например, у есть запрос на запись и возврат, и на post запрос мы хотим сделать обязательными ряд полей.
ChatGPT
ChatGPT хорошо переводит описания таблиц в компоненты: удобно скопировать из приложения управлением базами (DBeaver/DataGrip) содержание таблицы и попросить сформировать компоненты. Это сильно сокращает время на запросы, которые просто вытаскивают или засовывают данные из таблиц и в них.
С чего начинать описание
Я рекомендую начинать описание с компонентов, если уже есть понимание, какие запросы планируется реализовать. Это позволит сразу описать повторяющиеся элементы и сократит размер кода.
Description
Я рекомендую добавлять в описание запросов всю информацию, которая туда может только влезть. Указывать ссылку на Сonfluence, где описывается сценарий, прописывать неочевидную логику того, как у вас проверяются поля, в какую таблицу делается запись.
Инструменты
Лично мне удобнее писать в IDE. Прикладываю ссылки на VS Code. Но онлайн-эдитор тоже удобный. И там, и там подсвечиваются ошибки с довольно точным указанием на исправление.
-
https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml
-
https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi
Шаблоны
Подсмотреть, как описывается тот или иной элемент можно в шаблоне на https://editor.swagger.io/.
Также я сделал отдельный шаблон, который может помочь при копипасте похожих элементов + в качестве небольшой подсказки: https://github.com/AlexUra/swagger-openapi-example/blob/main/example.yml
P.S. Еще у меня канал есть
ссылка на оригинал статьи https://habr.com/ru/articles/776538/
Добавить комментарий