На связи снова Архитектурный комитет компании SimbirSoft, и мы продолжаем наш цикл статей, посвященных Design API First. Ранее мы уже писали о том, что представляет собой этот подход, приводили пример спецификации для сервиса аутентификации и рассказывали, как мы интегрируем этот паттерн в наш конвейер разработки.
Сегодня мы немного отвлечемся от бэкенда и разберем автоматизацию одной из рутинных задач на стороне frontend-разработки, а именно — описание моделей интерфейсов для взаимодействия фронта с беком, также написание API-сервисов, в которых фиксируются endpoints, методы запросов и формат передачи данных (query-параметры, заголовки, тело).
Инструменты кодогенерации
В нашей компании активно применяется стандарт OpenAPI. Несмотря на свою объемность в сравнении с более молодыми форматами, он является проверенным и наиболее отлаженным. Для него существует множество инструментов для поддержания документации. Поэтому рассмотрим несколько популярных инструментов, позволяющих работать с этим стандартом:
-
swagger-typescript-api — генерирует модели и сервисы (Fetch или Axios), есть возможность написания своих шаблонов кодогенерации.
-
openapi-typescript очень легковесный инструмент, заточенный под фронтендера, с хорошей поддержкой и без лишних зависимостей. Раскладывает спецификацию на набор интерфейсов, далее либо применяем самостоятельно данный инструмент, либо пользуемся вспомогательными — openapi-fetch или openapi-typescript-fetch, которые примут в качестве дженерика полученные ранее интерфейсы. Клиентов для axios или angular под openapi-typescript, к сожалению, не существует.
-
openapi-typescript-codegen – инструмент, аналогичный предыдущему, но дающий чуть больше кастомизации для шаблонов, в том числе тут есть шаблоны клиентов под axios или angular.
-
openapitools/openapi-generator-cli — это по сути Node.js-обертка над Swagger Codegen, который поддерживается создателями Swagger и стандарта OpenApi. Невероятно мощный инструмент: может генерировать клиентов не только для frontend, но и для backend. Есть возможность передачи кастомных шаблонов, можно настроить кодогенерацию под конкретный формат клиентов (Fetch, Angular, RxJS и другие).
Из npm-трендов (Рис. 1) видно, что openapi-typescript догоняет по популярности openapitools/openapi-generator-cli. Почему так происходит?
Во-первых, последний инструмент в зависимостях имеет Java — frontend-разработчику приходится ставить JRE или запускать генерацию в докере. Для запуска в докере есть специальный флаг в конфиге генератора, поэтому писать докер-файл не нужно, все запускается «под капотом».
Во-вторых, openapi-typescript предоставляет лишь корректную конвертацию в интерфейсы ТS, дальше с ними можно сделать что угодно. В то время как последний инструмент генерит еще и клиентов, и, если они не подойдут, приходится изучать громоздкую документацию и перенастраивать шаблоны кодогенерации.
Разберем пример на основе openapi-typescript-codegen и спеки сервиса авторизации из первой статьи.
Выполняем команды:
$ npm i openapi-typescript-codegen $ npx openapi --input=spec.yml --output=api --client=fetch
И получаем следующую структуру:
. └── api/ ├── core/ ├── models/ ├── services/ └── index.ts
Директория core содержит базовые переиспользуемые модели, связанные непосредственно с кодогенертором. Папка models содержит все упомянутые в спеке модели, services содержит клиенты (URL для endpoints в связке с нужными моделями). Примеры моделей и сервиса приведены ниже.
Примеры моделей
export type Auth_Request_Model_AuthAccount = { /** * Email, привязанный к аккаунту пользователя */ userLogin: string; }; export type Auth_Response_Model_AbstractSuccessAccessAccount = { accessToken: string; /** * ID аккаунта пользователя */ accountId?: string; message: string; };
Пример сервиса
import type {Auth_Request_Model_AuthAccount} from "../models/Auth_Request_Model_AuthAccount"; import type {Auth_Response_Model_Account} from "../models/Auth_Response_Model_Account"; import type {Auth_Response_Model_WaitingAccessAccount} from "../models/Auth_Response_Model_WaitingAccessAccount"; import type {CancelablePromise} from "../core/CancelablePromise"; import {OpenAPI} from "../core/OpenAPI"; import {request as __request} from "../core/request"; export class AuthService { /** * Auth/R2. Метод получения доступа к аккаунту пользователя * Метод предназначен для аутентификации пользователя под указанным email, соответствующим аккаунту в БД * @param requestBody * @param acceptLanguage https://developer.mozilla.org/ru/docs/Web/HTTP/Headers/Accept-Language * @param correlationId * @param platform * @returns Auth_Response_Model_WaitingAccessAccount - Ожидается активация созданного аккаунта пользователя * - Ожидается подтверждение входа пользователя в свой аккаунт * - Ожидается подтверждение восстановления доступа пользователя к своему аккаунту * * @throws ApiError */ public static authAccount(requestBody: Auth_Request_Model_AuthAccount, acceptLanguage?: string, correlationId?: string, platform?: "MOBILE" | "WEB"): CancelablePromise<Auth_Response_Model_WaitingAccessAccount> { return __request(OpenAPI, { method: "POST", url: "/v1/signin", headers: { "Accept-Language": acceptLanguage, CorrelationID: correlationId, Platform: platform, }, body: requestBody, mediaType: "application/json;charset=UTF-8", errors: { 400: `Некорректные входные данные. Возвращается список атрибутов с ошибками`, 403: `Пользователю с текущими правами доступ отклонён`, 500: `Внутренняя ошибка сервера`, }, }); } /** * Auth/R3. Метод получения информации об аккаунте * Метод предназначен для получения информации из БД об аккаунте текущего пользователя * @param acceptLanguage https://developer.mozilla.org/ru/docs/Web/HTTP/Headers/Accept-Language * @param correlationId * @returns Auth_Response_Model_Account Сформирован ответ с информацией об аккаунте текущего пользователя * @throws ApiError */ public static getAccount(acceptLanguage?: string, correlationId?: string): CancelablePromise<Auth_Response_Model_Account> { return __request(OpenAPI, { method: "GET", url: "/v1/auth", headers: { "Accept-Language": acceptLanguage, CorrelationID: correlationId, }, errors: { 401: `Пользователь не был аутентифицирован`, 500: `Внутренняя ошибка сервера`, }, }); } }
Рассмотрим несколько вариантов реализации инфраструктуры.
Разработка в монорепозитории
Поскольку для кодогенерации нужна спецификация, которую никто не хранит в директории с кодом frontend, то одним из естественных решений для такой связности является использование монорепозитория. Это в каком-то плане классический подход (Рис. 2).
Backend и frontend разрабатываются вместе, что дает удобный доступ к спецификации. При этом не важно, что первично: спецификация или код — мы либо сразу генерируем модели, либо запускаем ещё промежуточную команду по экстракции спеки из кода.
Разработка в раздельных репозиториях
Кодогенерация моделей при хранении кода frontend и backend в раздельных репозиториях сильно зависит от выбранного воркфлоу на проекте.
1. С тестированием в общей ветке
Тестирование в общей ветке применяется достаточно часто. Тут сказывается ограниченность ресурсов располагаемых серверов, не всегда есть возможность раскатать множество инстансов бекенда с непустой базой для разработки и тестирования.
1.1. Для случаев, когда тестирование делается в общей ветке, можно дождаться, когда сборку backend накатят на стенд Dev, отчего спецификация перезальется, и frontend-специалист сможет ее спокойно скачать по известному URL (Рис. 3).
1.2. Если на проекте проектированию отдельных кусков функциональности уделяется должное внимание, происходит согласование форматов взаимодействия frontend и backend. И/или есть сильная потребность запускать разработку параллельно (вести разработку frontend вместе с backend, а не после оного), то вам может потребовать отдельный репозиторий для хранения спецификаций. Отличия от предыдущего варианта минимальны (Рис. 4) — тут backend генерирует и для себя клиентов.
1.3. Если спецификация лежит статично и не нуждается в какой-либо компиляции, то можно «сходить» в соседний репозиторий и забрать ее оттуда, не дожидаясь деплоя на стенд (Рис. 5). Для авторизации curl-a в gitlab или bitbacket используем Access Token, сгенерированный под конкретного человека, в Git не храним (добавляем в gitignore).
2. С тестированием отдельных веток на отдельных стендах
Если перед вливанием в общую ветку ведется отдельное тестирование на отдельном стенде, то все становится интересней и сложней. Подходы 1.1-1.3 можно переиспользовать (и в 90% случаев их хватает), но уже в отношении отдельных стендов. В зависимости от задачи надо только не забывать менять URL на спецификацию.
Как вариант, для особо сложных случаев можно кодогенерацию вынести в CI, клиенты будут артефактами сборки. В дальнейшем клиенты публикуются в корпоративном npm. Для версионирования используются «версия продукта» + «имя ветки» (например, @project-scope/api@1.2.3-task_123). Если пакета с таким номером задачи не существует, то ставим по дефолту последний пакет из общей ветки (например, @project-scope/api@1.2.3-dev). Отметим, что ставить пакеты нужно с флагом «no-save», так как от задачи к задаче будут появляться новые версии пакетов (Рис. 6).
Заключение
Итак, в этой статье мы разобрали несколько инструментов кодогенерации, которые могут полезны frontend-разработчику, описали типовые схемы реализации инфраструктуры. Конечно, выбор определенной схемы зависит от конкретных задач, но вывод все равно очевиден: если вы используете на проекте подход Design API First, то пользуйтесь кодогенераторами — это позволит автоматизировать небольшую работу в пределах одной задачи, но огромную в рамках всего проекта. Также поможет избавиться от ошибок из-за человеческого фактора при интеграции с backend.
При наличии удобного доступа к спецификации пользуйтесь подходами 1.1-1.3 — просто забирайте ее из соседней директории или curl-ом.
В противном случае можно присмотреться к npm как к очень удобной системе доставке кода. Например, на проектах с микросервисами и микрофронтами.
Пользуетесь ли вы подобной кодогенерацией? Как доставляете спецификацию или готовый код на фронт? Какие интересные кейсы вам попадались? Пишите в комментариях, будем рады обсудить это вместе.
Другие полезные материалы для разработчиков и архитекторов в IT публикуем в наших соцсетях — ВК и Telegram.
ссылка на оригинал статьи https://habr.com/ru/companies/simbirsoft/articles/751406/
Добавить комментарий