2026-04-30 19:32:10 +03:00
---
2026-05-08 19:34:39 +03:00
title: Автогенерация REST-клиента
description: Генерация REST-клиента из OpenAPI-спецификации.
2026-04-30 19:32:10 +03:00
keywords: [rest, openapi, api-codegen, автогенерация, generated, npx]
---
2026-05-08 19:34:39 +03:00
# Автогенерация REST-клиента
Генерация REST-клиента из OpenAPI-спецификации.
## Когда использовать
2026-04-30 19:32:10 +03:00
Автогенерация используется, когда у API есть актуальная OpenAPI-спецификация. Генератор создаёт TypeScript-клиент, типы и методы API, а разработчик вручную добавляет настройку клиента и GET-хуки.
## Пример API
В примерах используется Swagger Petstore:
```text
https://petstore3.swagger.io/api/v3/openapi.json
```
Имена модуля:
```text
2026-05-08 08:21:34 +03:00
src/infra/pet-store-api/
2026-04-30 19:32:10 +03:00
petStoreApi
pet-store-api.generated.ts
```
## Скрипт генерации
`@gromlab/api-codegen` не устанавливается в `devDependencies` . Используем `npx @gromlab/api-codegen@latest` , чтобы запускать свежую версию.
```json
{
"scripts": {
2026-05-08 08:21:34 +03:00
"codegen:pet-store-api": "npx @gromlab/api -codegen@latest -i https://petstore3.swagger.io/api/v3/openapi.json -o src/infra/pet-store-api/generated -n pet-store-api.generated"
2026-04-30 19:32:10 +03:00
}
}
```
Параметры:
- `-i` — путь к OpenAPI-спецификации: URL или локальный файл.
- `-o` — директория для сгенерированного файла.
- `-n` — имя сгенерированного файла без `.ts` .
Ключ `--swr` не используется. GET-хуки REST-клиента пишутся вручную, чтобы сохранить проектный контракт: один GET-хук = один GET-метод, без бизнес-логики и композиции.
## Генерация
```bash
npm run codegen:pet-store-api
```
Ожидаемый результат:
```text
2026-05-08 08:21:34 +03:00
src/infra/pet-store-api/generated/
2026-04-30 19:32:10 +03:00
└── pet-store-api.generated.ts
```
Сгенерированный файл не правится руками и коммитится в репозиторий.
## Проверка методов
После генерации откройте `generated/pet-store-api.generated.ts` и проверьте фактические имена методов.
Для Petstore нужны GET-операции вида:
```ts
2026-05-08 19:34:39 +03:00
petStoreApi.pet.findPetsByStatus({ status: StatusEnum.Available })
petStoreApi.pet.getPetById({ petId: 10 })
2026-04-30 19:32:10 +03:00
```
Точные сигнатуры зависят от OpenAPI-схемы и версии генератора. В рабочих задачах всегда сверяйтесь с generated-файлом.
2026-05-08 19:34:39 +03:00
## Алгоритм для агента
После генерации агент должен действовать по шагам:
1. Открыть `generated/{service-name}.generated.ts` .
2. Найти фактические имена GET-методов клиента.
3. Для каждого нужного GET-метода найти generated-тип параметров и тип ответа.
4. Создать или обновить `client.ts` только для настройки транспорта и экспорта инстанса клиента.
5. Создать GET-хуки только для реально нужных GET-методов, не для всех методов API на всякий случай.
6. Для каждого GET-хука создать key-функцию формата `[serviceName, endpoint]` .
7. В key-функции вернуть `null` , если обязательные параметры не готовы.
8. В хуке принять `params?: GeneratedParams | null` и `config?: SWRConfiguration<Data>` .
9. В fetcher вызвать generated-метод клиента с `params as GeneratedParams` .
10. Экспортировать хук и key-функцию из `hooks/index.ts` .
11. Экспортировать наружу только нужные generated-типы, generated enum, DTO и `hooks` через корневой `index.ts` .
Что агент не должен делать:
- Н е использовать ключ `--swr` генератора.
- Н е править `generated/*.generated.ts` руками.
- Н е добавлять GET-хуки для POST, PUT, PATCH, DELETE.
- Н е добавлять бизнес-флаги, тосты, редиректы и UI-состояние в GET-хук.
- Н е создавать словари enum-маппинга внутри GET-хука.
- Н е объявлять DTO и response-типы в файле хука.
- Н е вызывать `useSWR` условно.
- Н е добавлять `throw` в fetcher для неготовых params.
2026-04-30 19:32:10 +03:00
## `client.ts`
Сгенерированный код не должен напрямую использоваться из приложения. Сначала создаётся настроенный инстанс клиента.
```ts
2026-05-08 08:21:34 +03:00
// src/infra/pet-store-api/client.ts
2026-04-30 19:32:10 +03:00
import { Api, HttpClient } from './generated/pet-store-api.generated'
2026-05-08 19:34:39 +03:00
const baseUrl = process.env.NEXT_PUBLIC_PET_STORE_API_BASE_URL
if (!baseUrl) {
throw new Error('NEXT_PUBLIC_PET_STORE_API_BASE_URL is required')
}
2026-04-30 19:32:10 +03:00
const httpClient = new HttpClient({
2026-05-08 19:34:39 +03:00
baseUrl,
2026-04-30 19:32:10 +03:00
baseApiParams: {
secure: false,
headers: {
'Content-Type': 'application/json',
},
},
})
export const petStoreApi = new Api(httpClient)
```
2026-05-08 19:34:39 +03:00
Локальное значение `NEXT_PUBLIC_PET_STORE_API_BASE_URL` задаётся в `.env.local` . Н е добавляйте fallback вроде `?? 'http://localhost:8080/api/v3'` или `?? ''` : если env-переменная не задана, клиент должен падать с явной ошибкой конфигурации.
2026-04-30 19:32:10 +03:00
`client.ts` не содержит расширения типов, `declare module` и `Extended` -типы. Он только настраивает транспорт и экспортирует инстанс клиента.
2026-05-08 19:34:39 +03:00
## GET-хуки
GET-хуки пишутся вручную после проверки generated-методов.
Пример для generated-метода `petStoreApi.pet.getPetById({ petId })` :
```ts
// src/infra/pet-store-api/hooks/use-get-pet-detail.hook.ts
import type { SWRConfiguration } from 'swr'
import useSWR from 'swr'
import { petStoreApi } from '../client'
import type { GetPetByIdParams, Pet } from '../generated/pet-store-api.generated'
export const getPetDetailKey = (params?: GetPetByIdParams | null) => {
if (!params?.petId) {
return null
}
return ['pet-store-api', `/pet/${params.petId}` ] as const
}
/**
* Получает детальную карточку питомца с кешированием результата.
*/
export const useGetPetDetail = (
params?: GetPetByIdParams | null,
config?: SWRConfiguration< Pet > ,
) => {
const key = getPetDetailKey(params)
const fetcher = () => petStoreApi.pet.getPetById(params as GetPetByIdParams)
return useSWR< Pet > (key, fetcher, config)
}
```
Подробный контракт key-функций, `params` , `config` и запретов описан в разделе [GET-хуки REST-клиента ](./hooks.md ).
2026-04-30 19:32:10 +03:00
## Расширение сгенерированных типов
Сгенерированный файл не правится руками. Если OpenAPI-спецификация неполная или генератор дал слишком общий тип (`object` , `unknown` , отсутствующее поле), расширения живут в `types/` .
```text
2026-05-08 08:21:34 +03:00
src/infra/biocad-less-api/
2026-04-30 19:32:10 +03:00
├── generated/
│ └── biocad-less-api.generated.ts
├── types/
│ ├── term.ts
│ └── index.ts
├── client.ts
└── index.ts
```
Пример расширения generated-типа:
```ts
2026-05-08 08:21:34 +03:00
// src/infra/biocad-less-api/types/term.ts
2026-04-30 19:32:10 +03:00
import type { TermRecordItem } from '../generated/biocad-less-api.generated'
declare module '../generated/biocad-less-api.generated' {
interface TermRecordItem {
media?: {
file?: string
title?: string
url?: string
}
}
}
export type TermRecordItemExtended = Omit<
TermRecordItem,
'categories' | 'tags' | 'fields'
> & {
categories?: Array< {
_id?: string
id?: string
slug?: string
name?: string
}>
tags?: Array< {
_id?: string
id?: string
slug?: string
name?: string
}>
fields?: Record< string , unknown >
}
```
```ts
2026-05-08 08:21:34 +03:00
// src/infra/biocad-less-api/types/index.ts
2026-04-30 19:32:10 +03:00
export type { TermRecordItemExtended } from './term'
```
`declare module` используется для добавления отсутствующих полей в generated-интерфейс. `Extended` -тип используется, когда нужно переопределить неточные поля, не трогая generated-файл.
## Публичный API
```ts
2026-05-08 08:21:34 +03:00
// src/infra/pet-store-api/index.ts
2026-04-30 19:32:10 +03:00
export { petStoreApi } from './client'
2026-05-08 19:34:39 +03:00
export type {
FindPetsByStatusParams,
GetPetByIdParams,
Pet,
} from './generated/pet-store-api.generated'
export { PetStatusEnum, StatusEnum } from './generated/pet-store-api.generated'
2026-04-30 19:32:10 +03:00
export * from './hooks'
```
2026-05-08 08:21:34 +03:00
Наружу импортируют только из `infra/pet-store-api` , не из `generated/` .
2026-04-30 19:32:10 +03:00
Если у модуля есть расширенные типы, они тоже реэкспортируются через `index.ts` :
```ts
2026-05-08 08:21:34 +03:00
// src/infra/biocad-less-api/index.ts
2026-04-30 19:32:10 +03:00
export type { TermRecordItemExtended } from './types'
```
## Регенерация
При изменении OpenAPI-схемы:
```bash
npm run codegen:pet-store-api
```
Что меняется:
- `generated/pet-store-api.generated.ts` — перезаписывается генератором.
- `client.ts` , `hooks/` , `types/` , `index.ts` — не трогаются автоматически.
Если после регенерации поменялись сигнатуры методов или типы, это исправляется в ручном коде модуля.
## Следующий шаг
2026-05-08 19:34:39 +03:00
После генерации и настройки `client.ts` проверьте [использование REST-клиента ](../usage.md ) или добавьте [GET-хук REST-клиента ](./hooks.md ) для Client Components.