Swagger Codegen

Генерируем типы и http-клиент

Павел Гонзалес

- 9+ лет в разработке

- Переписал часть OZON

- Запустил Академику

- Code expert в skillbox

- <3 фронтенд

Contract First Principle

Глеб Михеев
Contract-first principle в работе c API
Паша Коршиков
Сравнение подходов разработки: implementation-first vs contract-first

История

История

  1. Надо было запускать новый проект и писать много кода руками
  2. Определить контракты с бекендерами и сразу их использовать
  3. Быстро поддерживать изменения на бекенде
  4. Лень

Проблемы

Проблемы

  1. Руками описывать все модели, которые приходят с бекенда
  2. Переписывать уже написанное, когда обновляется бэк
  3. Руками писать все запросы к серверу и поддерживать их
  4. Бэк может обновиться, а мы об этом можем не узнать

Решение

Решение

Swagger Codegen

Swagger Codegen

Инструмент, который генерирует вам код на основне swagger.yaml файла

Как использовать?

Установка

            
              brew install swagger-codegen
            
          

Генерация

            
              "scripts": {
                "prepare": "husky install",
                "build": "nuxt build",
                "dev": "nuxt dev",
                "start": "node .output/server/index.mjs",
                ...
              }
					  
          

Генерация

            
              "scripts": {
                "prepare": "husky install",
                "build": "nuxt build",
                "dev": "nuxt dev",
                "start": "node .output/server/index.mjs",
                "generate:api:petstore": "swagger-codegen generate
                  -i https://petstore3.swagger.io/api/v3/openapi.yaml
                  -l typescript-axios
                  -o ./swagger/petstore
                  -t ./swagger/generator
                  --additional-properties modelPropertyNaming=original",
              }
            
          

Что получаем на выходе?

Использование

Использование

            
              // src/api/pets.ts
              import { PetApi } from '@/swagger/petstore/api'

              export default () => {
                const { $axios } = useNuxtApp()
                const petApi = new PetApi(undefined, `${API_URL}/api`, $axios)

                return {
                  get(...params: Parameters<typeof petApi.getPetById>) {
                    return petApi.getPetById(...params).then((res) => {
                      return mapData(res.data.data)
                    })
                  },
                }
              }
            
          

Проблемы

Проблемы

1. Закрытый под паролем путь до yaml файла

2. Бекендеры не всегда пишут валидный или отражающий реальность сваггер 😿

3. Готовый шаблон не всегда генерирует что нам нужно

1. Закрытый под паролем путь до yaml файла

- Просить открыть swagger.yaml без пароля

- Настроить авторизаццию при запросе yaml файла

Проблемы

1. Закрытый под паролем путь до yaml файла

2. Бекендеры не всегда пишут валидный или отражающий реальность сваггер 😿

3. Готовый шаблон не всегда генерирует что нам нужно

2. Бекендеры не всегда пишут валидный или отражающий реальность сваггер 😿

- Попросите бекендров поставить расширение в IDE для Open API или Swagger.

- Попросите держать swagger.yaml в актуальном состоянии

            
              /v1/companies/list:
                get:
                  summary: "Роут для получения компаний"
                  tags:
                    - companies
                  parameters:
                    - name: ids
                      in: query
                      schema:
                        type: array
                        minItems: 0
                        items:
                          type: number
            
          
            
              /v1/companies/list:
                get:
                  summary: "Роут для получения компаний"
                  operationId: getCompaniesList
                  tags:
                    - companies
                  parameters:
                    - name: ids
                      in: query
                      schema:
                        type: array
                        minItems: 0
                        items:
                          type: number
            
          
            
              /v1/companies/list:
                get:
                  summary: "Роут для получения компаний"
                  operationId: getCompaniesList
                  tags:
                    - companies
                  parameters:
                    - name: ids[]
                      in: query
                      schema:
                        type: array
                        minItems: 0
                        items:
                          type: number
            
          
            
              responses:
                "200":
                  description: "Успешный ответ, содержащий данные о компаниях"
                  content:
                    application/json:
                      schema:
                        type: object
                        properties:
                          data:
                            type: object
                            additionalProperties:
                              type: object
                              properties:
                                id:
                                  type: integer
                                slug:
                                  type: string
                                name:
                                  type: string
                                abbreviation:
                                  type: string
                                  nullable: true
                                logo:
                                  type: string
                                  nullable: true
            
          
            
              responses:
                "200":
                  description: "Успешный ответ, содержащий данные о компаниях"
                  content:
                    application/json:
                      schema:
                        type: object
                        properties:
                          data:
                            $ref: "#/components/schemas/CompaniesList"
            
          
            
              /v1/companies/list:
                get:
                  summary: "Роут для получения компаний"
                  operationId: getCompaniesList
                  tags:
                    - companies
                  parameters:
                    - name: ids[]
                      in: query
                      schema:
                        type: array
                        minItems: 0
                        items:
                          type: number
                  responses:
                    "200":
                      description: "Успешный ответ, содержащий данные о компаниях"
                      content:
                        application/json:
                          schema:
                            type: object
                            properties:
                              data:
                                $ref: "#/components/schemas/CompaniesList"
            
          

2. Бекендеры не всегда пишут валидный или отражающий реальность сваггер 😿

- Попросите бекендров поставить расширение в IDE для Open API или Swagger.

- Попросите держать swagger.yaml в актуальном состоянии

Проблемы

1. Закрытый под паролем путь до yaml файла

2. Бекендеры не всегда пишут валидный или отражающий реальность сваггер 😿

3. Готовый шаблон не всегда генерирует что нам нужно

3. Готовый шаблон не всегда генерирует что нам нужно

Переопределяем шаблоны и передаем флагом

-t ./swagger/generator

3. Готовый шаблон не всегда генерирует что нам нужно

Переопределяем шаблоны и передаем флагом

 -t ./swagger/generator

Проблемы

1. Закрытый под паролем путь до yaml файла

2. Бекендеры не всегда пишут валидный или отражающий реальность сваггер 😿

3. Готовый шаблон не всегда генерирует что нам нужно

Резюме

🛠️ Просите бекендеров писать operationId и выносить модели в отдельные именованные компоненты

🚂 Откройте путь до yaml файла без пароля

📚 Переопределяйте шаблон генерации, если есть проблемы в автогенном коде

🗑️ Удаляйте папку со старым кодом перед запуском генерации

🏆 Кайфуйте

Итог

Увеличиваем скорость разработки

Меньше дергаем бекендеров

Можем приступать к написанию сервиса моков

Ссылка на ссылки