OpenAPI во фронтенде или магия автоматизации

от автора

Привет! Меня зовут Ларионова Екатерина, я фронтенд-разработчик в компании AXENIX.

В современной разработке программного обеспечения согласованность между документацией, дизайном API и его реализацией играет ключевую роль. Эффективно решить эту задачу помогает подход API-First, при котором проектирование интерфейсов становится отправной точкой всего процесса. Одним из основных инструментов, поддерживающих этот подход, является спецификация OpenAPI — мощный инструмент для описания RESTful API, который позволяет не только формализовать поведение сервисов, но и автоматизировать множество сопутствующих задач.

Мы все чаще сталкиваемся с парадоксом: с одной стороны, растут требования к скорости вывода продукта на рынок, с другой — увеличивается сложность приложений. При этом, разработчики тратят большое количество времени на рутинные задачи, такие как интеграция с API и написание boilerplate-кода. Именно здесь на помощь приходит автоматизация рутинных задач во фронтенде на основе OpenAPI-спецификаций и она может очень сильно упростить нам, фронтендерам, жизнь!

OpenAPI как рабочий инструмент

OpenAPI выходит за рамки простого описания API, становясь ключевым элементом в процессе разработки. Вот основные преимущества в использовании OpenAPI-спецификации:

  1. Автогенерация API-клиента — исключает рутинное написание повторяющегося кода за счёт автоматической генерации клиентов, типов и моков.

  2. Мок-серверы для разработки — позволяют фронтенду начать работу до готовности бэкенда, экономя время и упрощая параллельную разработку.

  3. Типизация и исключение ошибок — автоматическая генерация типов для TypeScript предотвращает опечатки и несоответствия данных.

  4. Упрощённое тестирование — генерация моков и стабов для тестов ускоряет проверку логики приложения.

  5. Надёжность и согласованность. Документация = источник истины — все компоненты (клиент, сервер, тесты) синхронизированы с описанием API, что снижает риск расхождений. Чёткий API-контракт минимизирует ошибки взаимодействия между командами.

Генерация клиентского кода из OpenAPI-спецификации

Автоматическая генерация клиентского кода из OpenAPI-спецификации — мощный инструмент в арсенале современного разработчика. Давайте разберёмся, как это работает на практике и как можно интегрировать этот процесс в ваш проект.

Подготовка спецификации

Перед началом работы нам понадобится сама OpenAPI-спецификация, которую обычно предоставляет аналитик. Фронтенд-разработчики могут затем работать с ней следующими способами:

  1. Локальный файл

  2. Swagger UI — через URL документации вашего API

  3. Git-репозиторий — например, из корпоративного GitLab

Лучше всего хранить OpenAPI-спецификацию в Git-репозитории — это обеспечивает версионность, контроль изменений и доступ для всей команды. Вот ряд плюсов:

  1. Сохранение истории правок — если API меняется, фронтендеры могут сравнить старую и новую версии спецификации через git diff.

  2. Синхронизация — все разработчики работают с актуальной версией, а не с локальными копиями.

  3. CI/CD интеграция — можно генерировать из спецификации код при каждом обновлении репозитория.

В данной статье мы рассмотрим самый простой способ работы с OpenAPI-спецификацией — использование локального файла. Этот вариант идеально подходит для быстрого старта т.к. не требует настройки Git или доступа к серверу документации.

Поместите файл спецификации schema.yaml в ваш проект. В рамках данной статьи для примера будет использоваться папка /openapi-schemas в корне проекта.

ваш_проект/ ├── openapi-schemas/   # Папка из примеров │   └── schema.yaml    # Основной файл спецификации ├── src/               # Исходный код проекта └── ...                # Остальные файлы 

Теперь вы можете ссылаться на этот файл в инструментах разработки.

Настройка инструментов генерации

Для генерации кода мы будем использовать OpenAPI Generator — один из самых популярных инструментов в этой области. Он позволяет автоматически создавать клиентские и серверные SDK, документацию и другую логику, связанную с API, на основе OpenAPI-спецификации.

Перед использованием OpenAPI Generator важно знать главное техническое требование: у вас должна быть установлена Java. Скачать ее можно с официального сайта Oracle.

Установите CLI-версию генератора как dev-зависимость в ваш проект с помощью команды:

npm install @openapitools/openapi-generator-cli --save-dev

Конфигурация генератора

Создайте в корне проекта файл openapitools.json с базовой конфигурацией:

{   "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",   "spaces": 2,   "generator-cli": {     "version": "7.13.0",     "generators": {       "api-axfood": {         "generatorName": "typescript-axios",         "output": "./src/shared/api/api-axfood",         "inputSpec": "./openapi-schemas/schema.yaml"       }     }   } } 

При необходимости добавьте дополнительные настройки для кастомизации в поле additionalProperties:

{   "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",   "spaces": 2,   "generator-cli": {     "version": "7.13.0",     "generators": {       "api-axfood": {         "generatorName": "typescript-axios",         "output": "./src/shared/api/api-axfood",         "inputSpec": "./openapi-schemas/schema.yaml",         "additionalProperties": {           "apiPackage": "api",           "modelPackage": "models",           "withSeparateModelsAndApi": true,           "withInterfaces": true,           "supportsES6": true         }       }     }   } } 

Ключевые параметры:
generatorName: используемый генератор (typescript-axios, typescript-angular, typescript-fetch и др.)
output: путь для сгенерированных файлов
inputSpec: путь к OpenAPI-спецификации
additionalProperties: дополнительные настройки генерации

Популярные дополнительные свойства:
withSeparateModelsAndApi: флаг разделения API и моделей по папкам. По дефолту модели и API генерируются в один большой файл
apiPackage/modelPackage: название папок для файлов API и моделей
withInterfaces: генерация интерфейсов
supportsES6: использование ES6-синтаксиса

С полным списком параметров вы можете ознакомиться в официальной документации для генератора typescript-axios.

Интеграция в процесс разработки

Для удобства добавьте команду в раздел scripts файла package.json:

"scripts": {   "api:generate": "openapi-generator-cli generate" } 

Теперь генерация кода выполняется одной командой: npm run api:generate

Проверка результатов

После выполнения команды откройте папку ./src/shared/api/api-axfood. Убедитесь, что:
•Контроллеры находятся в папке /api
•Модели — в папке /models

Создание API-клиента

Для работы со сгенерированным API создайте клиентский файл. Например, ./src/shared/api/client.ts:

import { Configuration, DefaultApi as AxFoodApi } from './api-axfood';  const apiConfig = new Configuration({     basePath: '', });  export const apiAxFood = new AxFoodApi(apiConfig); 

Далее объект apiAxFood можно будет использовать в вашем проекте для доступа к методам API.


Генерация моков для API

Я достаточно часто сталкивалась с ситуацией, когда API ещё не было готово, но фронтенд уже нужно было разрабатывать. В таких случаях на помощь приходят моки — имитации реальных API-ответов. Далее мы рассмотрим, как автоматизировать процесс создания моков на основе OpenAPI-спецификации

Для генерации ответов будем использовать библиотеку msw-auto-mock, которая является расширением библиотеки MSW (Mock Service Worker).

Установите необходимые библиотеки, выполнив следующую команду:
npm install --dev msw msw-auto-mock @faker-js/faker

После установки инициализируйте MSW в нашем проекте:
msw init public/ --save

Эта команда создаст необходимые файлы для работы Service Worker в указанной директории public/.

Генерация моков

Основная магия происходит при выполнении следующей команды. С помощью нее будут сгенерированы моки по нашей спецификации:
msw-auto-mock ./openapi-schemas/schema.yaml -o ./mock --typescript

Параметры:
./openapi-schemas/schema.yaml — путь к файлу спецификации
-o ./mock — директория для выходных файлов
--typescript — генерация TypeScript-кода

Интеграция моков в приложение

Для подключения сгенерированных моков достаточно добавить следующие строки кода в точку входа вашего приложения (обычно main.ts или index.ts):

import { worker } from "../mock/browser";  await worker.start(); 

Вот и все! Всего три команды и пара строк кода — и моки, сгенерированные по OpenAPI-спецификации, готовы к использованию.


Генерация UI-прототипов по OpenAPI с помощью ИИ

В качестве эксперимента я решила проверить, насколько современные ИИ-инструменты способны генерировать рабочие интерфейсы на основе OpenAPI-спецификаций. Для быстрого прототипирования этот метод показал себя неожиданно полезным, однако требовал небольшие доработки и ручную адаптацию. Важно понимать, что это скорее любопытная альтернатива традиционному подходу, а не готовое решение для production.

Можно использовать любой ИИ-инструмент для разработчиков.

Ключевой момент — формулировка задачи. Пример рабочего промпта:

Сгенерируй компоненты для прототипа на React и Antd по спецификации openapi.  Используй все параметры из спецификации.  Воспользуйся сгенерированными с помощью openapi-generator-cli typescript-axios моделями и контроллерами.  Сделай интерфейс адаптивным. 

Что мы конкретно указали:
•Технологический стек (React + Ant Design)
•Источник данных (OpenAPI + сгенерированные модели)
•Требования к адаптивности

И вот такой компонент у нас был сгенерирован.

import axios from 'axios'; import React, {useState} from 'react'; import {Form, Input, Select, Button, message} from 'antd'; import type {CreateOrderRequest, ModelError} from "../shared/api/api-axfood"; import {apiAxFood} from "../shared/api/client.ts";  const OrderForm: React.FC = () => {     const [form] = Form.useForm();     const [loading, setLoading] = useState(false);     const [messageApi, context] = message.useMessage();      const onFinish = async (values: CreateOrderRequest) => {         setLoading(true);         try {             const response = await apiAxFood.createOrder(values);             messageApi.success(`Заказ успешно оформлен! Номер заказа: ${response.data.orderId}`);             form.resetFields();         } catch (error) {             if (axios.isAxiosError<ModelError>(error)) {                 if (error.response && error.response.data) {                     const { code, message: errorMessage } = error.response.data;                     messageApi.error(`Ошибка (${code}): ${errorMessage}`);                 } else {                     messageApi.error('Произошла ошибка при оформлении заказа.');                 }             } else {                 messageApi.error('Неизвестная ошибка.');             }         } finally {             setLoading(false);         }     };      return (         <Form             form={form}             name="order_form"             layout="vertical"             onFinish={onFinish}             initialValues={{paymentMethod: 'картой'}}         >             {context}             <Form.Item                 label="Идентификатор корзины с товарами"                 name="cartId"                 rules={[{required: true, message: 'Пожалуйста, введите идентификатор корзины!'}]}             >                 <Input type="number"/>             </Form.Item>             <Form.Item                 label="Адрес доставки заказа"                 name="deliveryAddress"                 rules={[{required: true, message: 'Пожалуйста, введите адрес доставки!'}]}             >                 <Input.TextArea rows={4}/>             </Form.Item>             <Form.Item                 label="Способ оплаты"                 name="paymentMethod"                 rules={[{required: true, message: 'Пожалуйста, выберите способ оплаты!'}]}             >                 <Select>                     <Select.Option value="картой">Картой</Select.Option>                     <Select.Option value="наличными">Наличными</Select.Option>                 </Select>             </Form.Item>             <Form.Item>                 <Button type="primary" htmlType="submit" loading={loading}>                     Оформить заказ                 </Button>             </Form.Item>         </Form>     ); };  export default OrderForm; 

Итог

Впервые попробовав такой подход на реальном проекте, я заметила, что использование OpenAPI-спецификации действительно упрощает разработку на начальных этапах. Из неоспоримых преимуществ стоит отметить экономию времени – пара часов на настройку генератора экономит десятки часов разработки за счёт автоматической генерации типов для API и моков на основе спецификации. При этом значительно сокращается количество ошибок из-за строгой типизации. Кроме того, такой подход улучшает командное взаимодействие и уменьшает количество ошибок при интеграции, поскольку фронтенд- и бэкенд-разработчики начинают работать с единой спецификацией.

Однако, существуют и минусы. Например, плохо составленная OpenAPI-схема может привести к некорректно сгенерированным типам или неполным мокам. Также можно столкнуться с ограничениями самого генератора, особенно при работе со сложными сценариями или нестандартными форматами данных. В этом случае требуется ручная доработка и написание собственных шаблонов.

Все методы, описанные в статье, я разберу на бесплатном воркшопе «Работа с OpenAPI: от спецификации до готового решения». Присоединяйтесь, чтобы увидеть реальные примеры, задать вопросы и глубже погрузиться в тему. Подробности и регистрация по ссылке.

Как и любой инструмент, метод требует настройки под ваш проект. Но при грамотном внедрении он становится мощным конкурентным преимуществом для вашей команды. Стоит попробовать!


ссылка на оригинал статьи https://habr.com/ru/articles/926766/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *