...

Пишем спецификацию OpenAPI для интернет-магазина в Swagger: практический пример

OpenAPI спецификация примеры курсы обучение REST API Swagger, Swagger REST API примеры курсы обучение, ликбез по Swagger и SwaggerHub для аналитика, тестирование REST API интеграция информационных системы примеры, REST Swagger JSON YAML примеры курсы обучение, интеграция информационных систем REST API простыми словами для начинающих примеры курсы обучение, интеграция информационных систем простыми словами для начинающих примеры курсы обучение, основы интеграции информационных систем для бизнес-аналитика, интеграция информационных систем основы введение, краткий ликбез по интеграции информационных систем, обучение системных и бизнес-аналитиков, курсы системного и бизнес-анализа, Школа прикладного бизнес-анализа Учебный Центр Коммерсант

Я уже показывала, как получить спецификацию 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.

UML use case примеры курсы обучение
UML-диаграмма вариантов использования проектируемого REST-приложения

Эта диаграмма создана с помощью следующего скрипта 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).

Swagger SwaggerHub, OpenAPI, спецификация REST API
Создание нового проекта в SwaggerHub

Заготовка спецификации сформируется автоматически в формате YAML и все, что нужно сделать – это исправить ее по своему проекту. Для этого надо внести своих акторов, свои HTTP-методы и структуры данных.

OpenAPI Swagger SwaggerHub примеры курсы обучение, спецификация REST API
Разработка спецификации OpenAPI в редакторе Swagger

В случае моего кейса пример 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.

OpenAPI Swagger SwaggerHub примеры курсы обучение, спецификация REST API
Редактор Swagger

Поскольку при создании проекта я задала для него публичную видимость, сгенерированная документация доступна по ссылке https://app.swaggerhub.com/apis-docs/VICHIGOVAANNA/Internet-shop/1.0.0

Надеюсь, что это небольшое руководство поможет аналитикам, которые только начинают знакомиться с REST API и Swagger, лучше понять их устройство и принципы работы. Более сложную версию этой документации OpenAPI со схемой безопасности на базе JWT-токена аутентификации пользователей, а также пошаговый алгоритм разработки спецификации я привожу в новой статье. А о том, какие ошибки чаще всего встречаются при разработке спецификации OpenAPI и как их избежать, читайте  здесь.

Основы архитектуры и интеграции информационных систем

Код курса
OAIS
Ближайшая дата курса
20 января, 2025
Продолжительность
16 ак.часов
Стоимость обучения
36 000 руб.

А подробнее познакомиться со всеми рассмотренными темами, а также другими основами архитектуры и интеграции информационных систем вам помогут курсы Школы прикладного бизнес-анализа в нашем лицензированном учебном центре обучения и повышения квалификации системных и бизнес-аналитиков в Москве:

Я даю свое согласие на обработку персональных данных и соглашаюсь с политикой конфиденциальности.

Добавить комментарий