2026-04-01 19:21:34 +03:00
# @gromlab/api-codegen
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
CLI для генерации typed TypeScript REST SDK из OpenAPI спецификации.
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
Генератор рассчитан на сценарий, где REST API можно вынести в отдельный npm-пакет, а приложения будут собирать из него свои API-клиенты: полный клиент, частичный клиент или точечные вызовы отдельных операций.
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
## Главная Идея
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
По умолчанию `@gromlab/api-codegen` генерирует split-клиент.
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
Каждый endpoint становится отдельной typed operation-функцией. Это позволяет импортировать только нужные методы и не тащить весь API в bundle приложения.
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
Если нужен полный клиент, используйте `operationsTree` .
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
Если нужен клиент только под конкретный экран, модуль или приложение, соберите дерево операций вручную.
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
Если нужен максимально точечный вызов, импортируйте одну operation напрямую.
2026-04-01 19:21:34 +03:00
2026-06-30 10:46:15 +03:00
## Быстрый Старт
2026-06-30 07:59:52 +03:00
2026-06-30 10:46:15 +03:00
```bash
npx @gromlab/api -codegen -i ./openapi.json -o ./src/generated
2026-06-30 07:59:52 +03:00
```
2026-06-30 10:46:15 +03:00
Для генерации из URL:
2026-06-30 07:59:52 +03:00
2026-06-30 10:46:15 +03:00
```bash
npx @gromlab/api -codegen -i https://api.example.com/openapi.json -o ./src/generated
2025-10-26 22:30:58 +03:00
```
2026-06-30 10:46:15 +03:00
По умолчанию будет создан split-клиент.
## Что Генерируется
2026-06-30 07:59:52 +03:00
```text
generated/
├── create-api-client.ts
├── data-contracts.ts
├── http-client.ts
├── index.ts
2026-06-30 10:46:15 +03:00
├── operations-tree.ts
2026-06-30 07:59:52 +03:00
└── operations/
├── index.ts
├── get-users.ts
└── create-user.ts
```
2026-06-30 10:46:15 +03:00
Основные части:
2026-06-30 07:59:52 +03:00
2026-06-30 10:46:15 +03:00
- `http-client.ts` - fetch-based HTTP клиент, настройки авторизации, headers, baseUrl и transport customization.
- `data-contracts.ts` - TypeScript типы из OpenAPI schemas.
- `operations/*.ts` - отдельная typed function на каждый endpoint.
- `operations/index.ts` - barrel export всех операций.
- `operations-tree.ts` - дерево всех операций для сборки полного API клиента.
- `create-api-client.ts` - helper, который привязывает дерево операций к конкретному HTTP клиенту.
- `index.ts` - основная входная точка generated SDK.
2026-06-30 07:59:52 +03:00
2026-06-30 10:46:15 +03:00
## Полный Клиент
2026-06-30 07:59:52 +03:00
2026-06-30 10:46:15 +03:00
Если приложению нужен весь API, используйте `operationsTree` .
2025-10-26 22:30:58 +03:00
```typescript
2026-06-30 10:46:15 +03:00
import { createApiClient, HttpClient, operationsTree } from './generated';
// 1. Инициализация HTTP-клиента: baseUrl, headers, авторизация и transport-настройки.
const http = new HttpClient({
baseUrl: 'https://api.example.com',
});
2026-06-30 07:59:52 +03:00
2026-06-30 10:46:15 +03:00
// 2. Создание API-клиента: привязываем все сгенерированные операции к HTTP-клиенту.
const api = createApiClient(http, operationsTree);
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
// 3. Использование API-клиента: вызываем методы из дерева операций.
2026-06-30 07:59:52 +03:00
const users = await api.users.getAll({});
2026-06-30 10:46:15 +03:00
const createdUser = await api.users.create({ email, password });
2026-06-30 07:59:52 +03:00
```
2026-06-30 10:46:15 +03:00
`operationsTree` намеренно лежит в отдельном файле и экспортируется отдельно. Импортируя е г о , вы явно выбираете полный клиент с о всеми операциями.
## Частичный Клиент
Если приложению нужна только часть API, соберите клиент вручную.
2026-06-30 07:59:52 +03:00
```typescript
import { createApiClient, HttpClient } from './generated';
2026-06-30 10:46:15 +03:00
import {
v1AdminPharmaciesCreate,
v1AdminPharmaciesList,
v1AdminPharmaciesProfileUpdate,
} from './generated/operations';
2026-06-30 07:59:52 +03:00
const http = new HttpClient({
baseUrl: 'https://api.example.com',
2026-06-30 10:46:15 +03:00
});
const api = createApiClient(http, {
pharmaciesAdmin: {
list: v1AdminPharmaciesList,
create: v1AdminPharmaciesCreate,
updateProfile: v1AdminPharmaciesProfileUpdate,
},
});
const pharmacies = await api.pharmaciesAdmin.list({});
const createdPharmacy = await api.pharmaciesAdmin.create(payload);
await api.pharmaciesAdmin.updateProfile({ id }, payload);
```
Так можно собрать отдельный клиент для админки, публичного сайта, мобильного приложения или отдельного feature-модуля.
`operations/index.ts` реэкспортит все operation-функции, поэтому можно делать named imports из `./generated/operations` . В ESM-сборке такой импорт остается tree-shaking friendly: в клиенте используются только явно выбранные операции.
Если OpenAPI большой и полный SDK занимает десятки тысяч строк, приложение не обязано тянуть весь набор методов в свой чанк. Можно собрать минимально рабочий API-клиент под конкретный сценарий.
Если нужен максимально строгий контроль над тем, какой файл попадет в bundle, импортируйте operation напрямую из е е файла:
```typescript
import { v1AdminPharmaciesList } from './generated/operations/v1-admin-pharmacies-list';
```
## Точечный Вызов Operation
Если по какой-то причине нужно вызвать только одну операцию, можно не собирать API-клиент через `createApiClient` и вызвать operation напрямую.
```typescript
import { HttpClient } from './generated/http-client';
import { v1AdminPharmaciesList } from './generated/operations/v1-admin-pharmacies-list';
const http = new HttpClient({
baseUrl: 'https://api.example.com',
});
const pharmacies = await v1AdminPharmaciesList(http, {});
```
Это полезно для разовых сценариев: health-check, bootstrap-запроса, утилитного скрипта или кода, где полноценный объект `api` не нужен.
## Кастомный HTTP Клиент
`HttpClient` создается отдельно и передается в generated operations. Это позволяет централизованно настраивать авторизацию, headers, baseUrl и transport behavior.
```typescript
import { HttpClient } from './generated';
type SecurityData = {
token: string;
};
const http = new HttpClient< SecurityData > ({
baseUrl: 'https://api.example.com',
baseApiParams: {
headers: {
'X-App-Version': '1.0.0',
},
},
securityWorker: (securityData) => {
2026-06-30 07:59:52 +03:00
if (!securityData?.token) {
return undefined;
}
return {
headers: {
Authorization: `Bearer ${securityData.token}` ,
},
};
},
});
2026-06-30 10:46:15 +03:00
http.setSecurityData({ token: 'jwt-token' });
```
Для отдельного вызова можно передать дополнительные request params последним аргументом operation.
```typescript
await api.users.getAll(
{},
{
headers: {
'X-Request-Id': requestId,
},
2026-06-30 07:59:52 +03:00
},
2026-06-30 10:46:15 +03:00
);
```
## API Как npm-Пакет
Типичный workflow:
1. Backend публикует OpenAPI спецификацию.
2. Отдельный пакет генерирует typed REST SDK в `src/generated` .
3. Пакет экспортирует generated entrypoint.
4. Приложения импортируют SDK и собирают нужные API-клиенты.
Пример структуры пакета:
```text
packages/my-api/
├── package.json
└── src/
├── generated/
└── index.ts
```
`src/index.ts` :
```typescript
export * from './generated';
```
Использование в приложении:
```typescript
import { createApiClient, HttpClient, operationsTree } from '@company/my -api';
const http = new HttpClient({
baseUrl: 'https://api.example.com',
2026-06-30 07:59:52 +03:00
});
2026-06-30 10:46:15 +03:00
export const api = createApiClient(http, operationsTree);
2026-06-30 07:59:52 +03:00
```
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
Если приложение хочет выбрать только часть API:
2025-10-26 22:30:58 +03:00
2026-06-30 07:59:52 +03:00
```typescript
2026-06-30 10:46:15 +03:00
import { createApiClient, HttpClient } from '@company/my -api';
import {
v1AdminPharmaciesList,
v1AdminPharmaciesProfileUpdate,
} from '@company/my -api/operations';
export const api = createApiClient(new HttpClient(), {
pharmaciesAdmin: {
list: v1AdminPharmaciesList,
updateProfile: v1AdminPharmaciesProfileUpdate,
},
});
```
## Режимы Генерации
### split
Режим по умолчанию.
2025-10-26 22:30:58 +03:00
2026-06-30 10:46:15 +03:00
```bash
api-codegen -i ./openapi.json -o ./src/generated
2025-10-26 22:30:58 +03:00
```
2026-06-30 10:46:15 +03:00
Эквивалентно:
```bash
api-codegen -i ./openapi.json -o ./src/generated --mode split
```
2025-10-28 09:58:44 +03:00
2026-06-30 10:46:15 +03:00
Используйте этот режим для новых проектов, npm SDK пакетов и приложений, где важны модульность и tree-shaking.
### single
Legacy-режим, который генерирует один монолитный TypeScript файл.
2026-06-30 07:59:52 +03:00
2025-10-28 09:58:44 +03:00
```bash
2026-06-30 10:46:15 +03:00
api-codegen -i ./openapi.json -o ./src/generated --mode single -n MyApi
```
Результат:
```text
generated/
└── MyApi.ts
2025-10-28 09:58:44 +03:00
```
2026-06-30 10:46:15 +03:00
Используйте `single` , если проект уже завязан на старый монолитный generated-клиент.
## CLI
2025-10-28 09:58:44 +03:00
```bash
2026-06-30 10:46:15 +03:00
api-codegen -i < input > -o < output > [--mode split|single] [-n < name > ]
2025-10-28 09:58:44 +03:00
```
2026-06-30 10:46:15 +03:00
Аргументы:
- `-i, --input <path>` - путь к OpenAPI файлу или URL.
- `-o, --output <path>` - директория для generated файлов.
- `--mode <mode>` - режим генерации: `split` или `single` . По умолчанию `split` .
- `-n, --name <name>` - имя файла для `single` режима без расширения `.ts` .
- `--single-file` - устаревший алиас для `--mode single` .
## Примеры Команд
Split из локального файла:
```bash
api-codegen -i ./openapi.json -o ./src/generated
```
Split из URL:
```bash
api-codegen -i https://api.example.com/openapi.json -o ./src/generated
```
Legacy single файл:
```bash
api-codegen -i ./openapi.json -o ./src/generated --mode single -n MyApi
```
2025-10-28 09:58:44 +03:00
2025-10-26 22:30:58 +03:00
## Лицензия
MIT