Я уже показывала, как получить спецификацию 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
Ближайшая дата курса
9 декабря, 2024
Продолжительность
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 руб.
А подробнее познакомиться со всеми рассмотренными темами, а также другими основами архитектуры и интеграции информационных систем вам помогут курсы Школы прикладного бизнес-анализа в нашем лицензированном учебном центре обучения и повышения квалификации системных и бизнес-аналитиков в Москве: