Я уже показывала, как получить спецификацию OpenAPI из программного кода с помощью Python-библиотеки FastAPI. Сегодня вернемся из роли разработчика в роль аналитика и составим спецификацию OpenAPI вручную на примере REST-приложения интернет-магазина, используя редактор Swagger в сервисе SwaggerHub.
Постановка задачи и проектирование REST API
Напомню, фреймворк Swagger от компании SmartBear позволяет формировать спецификацию OpenAPI 3 и интерактивно ее просматривать в визуальном веб-GUI. Спецификация OpenAPI описывает поддерживаемые REST-приложением HTTP-методы и структуры используемых данных, включая их. Редактор Swagger поддерживает работу с форматами JSON И YAML, проверяет валидность созданной спецификации и предоставляет GUI для тестирования HTTP-методов, объявленных в спецификации.
Чтобы продемонстрировать, как это работает, воспользуемся фреймворком Swagger в сервисе SwaggerHub. А в качестве примера возьмем интернет-магазин. Все пользователи (покупатель и мендежер) могут просматривать каталог товаров и поставщиков, искать товары и поставщиков определенных характеристик с применением различных фильтров, просмотреть детали конкретного товара и поставщика. Также менеджеру доступны функции добавления нового товара и поставщика, изменения этих объектов и их удаление.
Для визуализации возможностей системы интернет-магазина для пользователей составим UML-диаграмму Use Case.
Эта диаграмма создана с помощью следующего скрипта PlantUML:
@startuml skinparam packageStyle rectangle actor Пользователь actor Менеджер actor Покупатель Пользователь <|--- Покупатель Менеджер -|> Пользователь rectangle Интернет_магазин { Пользователь ---> (Посмотреть товар) (Найти товар) <.. (Посмотреть товар) : include (Просмотреть каталог товаров) <. (Найти товар) : include Пользователь -> (Посмотреть поставщика) (Найти поставщика) <.. (Посмотреть поставщика) : include (Найти поставщика) ..> (Посмотреть список поставщиков) : include Менеджер -> (Добавить поставщика) Менеджер ---> (Изменить поставщика) Менеджер -> (Удалить поставщика) (Изменить поставщика) ..> (Посмотреть поставщика) : extend (Удалить поставщика) ..> (Посмотреть поставщика) : extend Менеджер --> (Добавить товар) (Изменить товар) ...> (Посмотреть товар) : extend (Удалить товар) ...> (Посмотреть товар) : extend Менеджер -> (Изменить товар) Менеджер -> (Удалить товар) } @enduml
DDD, ООП и UML для аналитика
Код курса
BUML
Ближайшая дата курса
31 марта, 2025
Продолжительность
16 ак.часов
Стоимость обучения
36 000 руб.
Теперь начнем проектировать REST API системы интернет магазина. Сперва сопоставим варианты использования (ВИ) системы с маршрутами и конечными точками. Напомню, маршрут (Route) — это URL-адрес, который направляет запрос к определенным конечным точкам с помощью HTTP-методов. Маршрут может иметь несколько конечных точек. Конечная точка (Endpoint) — это непосредственно обращение к маршруту конкретным HTTP-методом, чтобы выполнить определенную задачу и вернуть данные с сервера клиенту. Сделаем сопоставление ВИ с маршрутами и конечными точками в таблице.
Актор | Use Case (ВИ) | Маршрут | Конечная точка (HTTP-метод) |
Пользователь (Менеджер, Покупатель) | UC-1. Посмотреть каталог товаров | /product | GET |
UC-2. Найти товар | /product | GET с параметрами фильтрации | |
Менеджер | UC-3. Добавить товар | /product | POST |
Пользователь (Менеджер, Покупатель) | UC-4. Посмотреть товар | /product/{id} | GET |
Менеджер | UC-6. Изменить товар | /product/{id} | PUT |
Менеджер | UC-5. Удалить товар | /product/{id} | DELETE |
Пользователь (Менеджер, Покупатель) | UC-7. Посмотреть список поставщиков | /provider | GET |
UC-8. Найти поставщика | /provider | GET с параметрами фильтрации | |
Менеджер | UC-10. Добавить поставщика | /provider | POST |
Пользователь (Менеджер, Покупатель) | UC-9. Посмотреть поставщика | /provider/{id} | GET |
Менеджер | UC-11. Изменить поставщика | /provider/{id} | PUT |
Менеджер | UC-12. Удалить поставщика | /provider/{id} | DELETE |
Наконец, составим структуру данных, которая будет отражать сведения о товаре (Product) и поставщике (Provider). Сперва определимся с полями этих сущностей и их типами данных:
Сущность | Поле | Смысл поля | Тип данных |
Product (Товар) | id | Идентификатор товара | integer |
name | Название товара | string | |
category | Категория товара | string | |
provider | Поставщик товара | object | |
price | Стоимость товара | number | |
quantity | Количество единиц товара | integer | |
Provider (Поставщик) | id | Идентификатор поставщика | integer |
name | Название поставщика | string | |
INN | ИНН поставщика | string | |
site | Сайт поставщика | string | |
phone | Телефон поставщика | string | |
address | Адрес поставщика | string |
Теперь предварительное проектирование REST API выполнено, можно переходить к формированию спецификации, что и рассмотрим далее.
Основы архитектуры и интеграции информационных систем
Код курса
OAIS
Ближайшая дата курса
20 января, 2025
Продолжительность
16 ак.часов
Стоимость обучения
36 000 руб.
Разработка спецификации OpenAPI
Формировать спецификацию будем с помощью редактора Swagger в веб-сервисе SwaggerHub, который доступен для бесплатного использования, но требует предварительной регистрации. Можно войти через сторонние сервисы, например, через Githib. После входа необходимо создать новый проект, выбрав наиболее подходящий шаблон (Template). В большинстве случае подойдет простой API (Simple API).
Заготовка спецификации сформируется автоматически в формате YAML и все, что нужно сделать – это исправить ее по своему проекту. Для этого надо внести своих акторов, свои HTTP-методы и структуры данных.
В случае моего кейса пример JSON-структуры данных, которая отражает сведения о товаре, выглядит так:
{ "id": 1, "name": "яблоки", "category": "еда", "provider": { "id": 1, "name": "ООО Ромашка", "INN": "1234567890", "site": "https://www.ooo-camomile.com", "phone": "7-495-123-45-67", "address": "г. Москва, ул. Ленина, 123" }, "price": 145, "quantity": 10 }
А пример структуры данных, которая отражает сведения о поставщике, также представленный в формате JSON, будет таким:
{ "id": 1, "name": "ООО Ромашка", "INN": "1234567890", "site": "https://www.ooo-camomile.com", "phone": "7-495-123-45-67", "address": "г. Москва, ул. Ленина, 123" }
Теперь составим саму спецификацию OpenAPI в формате YAML, который немного отличается от JSON, о чем я подробнее писала здесь. Итоговая спецификация выглядит следующим образом:
openapi: 3.0.0 servers: # Added by API Auto Mocking Plugin - description: SwaggerHub API Auto Mocking url: https://virtserver.swaggerhub.com/VICHIGOVAANNA/Internet-shop/1.0.0 info: description: 'Типичный интернет-магазин - демо-кейс Анны Вичуговой' version: "1.0.0" title: 'API интернет-магазина' contact: email: anna@mail.com tags: - name: manager description: 'Менеджер' - name: customer description: 'Покупатель' paths: /product: get: tags: - manager - customer summary: 'Посмотреть каталог товаров' operationId: viewProductCatalog description: 'Параметры фильтрации товаров в каталоге для поиска' parameters: - in: query name: name description: 'название товара для поиска' required: false schema: type: string - in: query name: category description: 'категория товара для поиска' required: false schema: type: string - in: query name: provider description: 'поставщик товара для поиска' required: false schema: type: string - in: query name: min_price description: 'минимальная цена товара для поиска' schema: type: integer format: int32 minimum: 0 maximum: 100500 - in: query name: max_price description: 'максимальная цена товара для поиска' schema: type: integer format: int32 minimum: 0 maximum: 10005000 responses: '200': description: 'результаты поиска по запросу' content: application/json: schema: type: array items: $ref: '#/components/schemas/Product' '400': description: 'не верные параметры фильтрации' post: tags: - manager summary: 'Добавить товар' operationId: addProduct description: 'Добавить новый товар в каталог' responses: '201': description: 'товар добавлен' content: application/json: schema: type: object properties: id: type: integer example: 1 product: $ref: '#/components/schemas/Product' '400': description: 'некорректный ввод' '409': description: 'такой товар уже есть' requestBody: content: application/json: schema: $ref: '#/components/schemas/Product' description: 'Новый товар для добавления в каталог' /provider: get: tags: - manager - customer summary: 'Посмотреть список поставщиков' operationId: viewProviderCatalog description: 'Параметры фильтрации поставщиков в каталоге для поиска' parameters: - in: query name: name description: 'название поставщика для поиска' required: false schema: type: string - in: query name: INN description: 'ИНН поставщика для поиска' required: false schema: type: string - in: query name: phone description: 'телефон поставщика для поиска' required: false schema: type: string - in: query name: address description: 'адрес поставщика для поиска' required: false schema: type: string responses: '200': description: 'результаты поиска по запросу' content: application/json: schema: type: array items: $ref: '#/components/schemas/Provider' '400': description: 'не верные параметры фильтрации' post: tags: - manager summary: 'Добавить поставщика' operationId: addProvider description: 'Добавление нового поставщика в каталог' responses: '201': description: 'поставщик добавлен' content: application/json: schema: type: object properties: id: type: integer example: 1 product: $ref: '#/components/schemas/Provider' '400': description: 'некорректный ввод' '409': description: 'такой поставщик уже есть' requestBody: content: application/json: schema: $ref: '#/components/schemas/Provider' description: 'Новый поставщик для добавления в каталог' /product/{id}: get: tags: - manager - customer summary: 'Посмотреть товар' operationId: viewProduct description: 'Просмотр данных о конкретном товаре по его ID' parameters: - in: path name: id description: ID required: true schema: type: integer format: int64 example: 1 responses: '200': description: 'Товар найден' content: application/json: schema: $ref: '#/components/schemas/Product' '404': description: 'Товар не найден' put: tags: - manager summary: 'Изменить товар' operationId: updateProduct description: 'Изменение параметров товара' parameters: - name: id in: path description: 'ID товара, параметры которого нужно изменить' required: true schema: type: integer example: 1 responses: '200': description: 'параметры товара изменены успешно' '400': description: 'некорректный ввод' '404': description: 'товар не найден' requestBody: content: application/json: schema: $ref: '#/components/schemas/Product' description: 'Измененные параметры товара' delete: tags: - manager summary: 'Удалить товар' operationId: deleteProduct description: 'Удаление товара по его идентификатору' parameters: - name: id in: path description: 'Идентификатор товара для удаления' required: true schema: type: integer example: 1 responses: '200': description: 'товар успешно удален' '404': description: 'товар не найден' '500': description: 'внутренняя ошибка сервера' /provider/{id}: get: tags: - manager - customer summary: 'Посмотреть поставщика' operationId: viewProvider description: 'Просмотр информации о конкретном поставщике по его ID' parameters: - in: path name: id description: Идентификатор поставщика required: true schema: type: integer format: int64 example: 1 responses: '200': description: 'Поставщик найден' content: application/json: schema: $ref: '#/components/schemas/Provider' '404': description: 'Поставщик не найден' put: tags: - manager summary: 'Изменить поставщика' operationId: updateProvider description: 'Изменение поставщика по его идентификатору' parameters: - name: id in: path description: 'ID поставщика, параметры которого нужно изменить' required: true schema: type: integer example: 1 responses: '200': description: 'параметры поставщика изменены успешно' '400': description: 'некорректный ввод' '404': description: 'товар не найден' requestBody: content: application/json: schema: $ref: '#/components/schemas/Provider' description: 'Измененные параметры поставщика' delete: tags: - manager summary: 'Удалить поставщика' operationId: deleteProvider description: 'Удаление поставщика по его идентификатору' parameters: - name: id in: path description: 'Идентификатор поставщика для удаления' required: true schema: type: integer example: 1 responses: '200': description: 'поставщика успешно удален' '404': description: 'поставщика не найден' '500': description: 'внутренняя ошибка сервера' components: schemas: Product: type: object required: - name - category - provider - price - quantity properties: id: type: integer example: 1 name: type: string example: 'яблоки' category: type: string example: 'еда' provider: $ref: '#/components/schemas/Provider' price: type: number example: 145.00 quantity: type: integer example: 10 Provider: required: - name - INN - phone - address properties: id: type: integer example: 1 name: type: string example: 'ООО Ромашка' INN: type: string example: 1234567890 site: type: string format: url example: 'https://www.ooo-camomile.com' phone: type: string example: 7-495-123-45-67 address: type: string example: 'г. Москва, ул. Ленина, 123'
Помимо ранее показанных маршрутов и конечных точек с HTTP-методами со структурами данных и примерами их наполнения, в этой спецификации также показаны HTTP-ответы на запросы, подробнее о которых я писала здесь. Редактор Swagger сразу отображает UI для тестирования описанного REST API.
Поскольку при создании проекта я задала для него публичную видимость, сгенерированная документация доступна по ссылке https://app.swaggerhub.com/apis-docs/VICHIGOVAANNA/Internet-shop/1.0.0
Надеюсь, что это небольшое руководство поможет аналитикам, которые только начинают знакомиться с REST API и Swagger, лучше понять их устройство и принципы работы. Более сложную версию этой документации OpenAPI со схемой безопасности на базе JWT-токена аутентификации пользователей, а также пошаговый алгоритм разработки спецификации я привожу в новой статье. А о том, какие ошибки чаще всего встречаются при разработке спецификации OpenAPI и как их избежать, читайте здесь.
Основы архитектуры и интеграции информационных систем
Код курса
OAIS
Ближайшая дата курса
20 января, 2025
Продолжительность
16 ак.часов
Стоимость обучения
36 000 руб.
А подробнее познакомиться со всеми рассмотренными темами, а также другими основами архитектуры и интеграции информационных систем вам помогут курсы Школы прикладного бизнес-анализа в нашем лицензированном учебном центре обучения и повышения квалификации системных и бизнес-аналитиков в Москве: