fix: ослаблена валидация content-type при загрузке спецификации по URL
- убрана строгая проверка content-type (ломала GitHub raw и другие серверы) - вместо неё парсинг JSON с понятной ошибкой при невалидном ответе - обновлён README: только npx, добавлен флаг --swr - версия 1.0.7
This commit is contained in:
88
README.md
88
README.md
@@ -1,42 +1,39 @@
|
|||||||
# API CodeGen
|
# @gromlab/api-codegen
|
||||||
|
|
||||||
CLI утилита для генерации TypeScript API клиента из OpenAPI спецификации.
|
CLI утилита для генерации TypeScript API клиента из OpenAPI спецификации.
|
||||||
|
|
||||||
## Установка
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bun install
|
|
||||||
```
|
|
||||||
|
|
||||||
## Использование
|
## Использование
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
api-codegen -u <URL> -i <INPUT> -o <OUTPUT> [-n <NAME>]
|
npx @gromlab/api-codegen -i <INPUT> -o <OUTPUT> [-n <NAME>] [--swr]
|
||||||
```
|
```
|
||||||
|
|
||||||
**Аргументы:**
|
**Аргументы:**
|
||||||
- `-u, --url <url>` - Базовый URL API
|
- `-i, --input <path>` - Путь к OpenAPI файлу (локальный файл или URL)
|
||||||
- `-i, --input <path>` - Путь к OpenAPI файлу (локальный или URL)
|
|
||||||
- `-o, --output <path>` - Директория для сохранения файлов
|
- `-o, --output <path>` - Директория для сохранения файлов
|
||||||
- `-n, --name <name>` - Имя сгенерированного файла (опционально)
|
- `-n, --name <name>` - Имя сгенерированного файла (опционально, по умолчанию из `spec.info.title`)
|
||||||
|
- `--swr` - Генерировать SWR хуки для React
|
||||||
|
|
||||||
**Примеры:**
|
**Примеры:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Локальный файл
|
# Локальный файл
|
||||||
api-codegen -u https://api.example.com -i ./openapi.json -o ./src/api
|
npx @gromlab/api-codegen -i ./openapi.json -o ./src/api
|
||||||
|
|
||||||
# URL на спецификацию
|
# URL на спецификацию
|
||||||
api-codegen -u https://api.example.com -i https://petstore.swagger.io/v2/swagger.json -o ./src/api
|
npx @gromlab/api-codegen -i https://httpbin.org/spec.json -o ./src/api
|
||||||
|
|
||||||
# С кастомным именем файла
|
# С кастомным именем файла
|
||||||
api-codegen -u https://api.example.com -i ./openapi.json -o ./src/api -n MyApiClient
|
npx @gromlab/api-codegen -i ./openapi.json -o ./src/api -n MyApi
|
||||||
|
|
||||||
|
# С генерацией SWR хуков
|
||||||
|
npx @gromlab/api-codegen -i ./openapi.json -o ./src/api --swr
|
||||||
```
|
```
|
||||||
|
|
||||||
## Пример использования
|
## Пример использования сгенерированного кода
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Api, HttpClient } from './src/api/Api';
|
import { Api, HttpClient } from './src/api/MyApi';
|
||||||
|
|
||||||
const httpClient = new HttpClient();
|
const httpClient = new HttpClient();
|
||||||
httpClient.setSecurityData({ token: 'jwt-token' });
|
httpClient.setSecurityData({ token: 'jwt-token' });
|
||||||
@@ -48,12 +45,6 @@ const user = await api.auth.getProfile();
|
|||||||
|
|
||||||
// POST запрос
|
// POST запрос
|
||||||
const result = await api.auth.login({ email, password });
|
const result = await api.auth.login({ email, password });
|
||||||
|
|
||||||
// React + SWR
|
|
||||||
function Profile() {
|
|
||||||
const { data } = useSWR('/auth/me', () => api.auth.getProfile());
|
|
||||||
return <div>{data?.email}</div>;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Разработка
|
## Разработка
|
||||||
@@ -65,49 +56,24 @@ bun run build
|
|||||||
|
|
||||||
### Тестирование
|
### Тестирование
|
||||||
|
|
||||||
Проект использует комплексную систему тестирования с максимальным покрытием (~72 тестовых кейса).
|
|
||||||
|
|
||||||
**Запуск всех тестов:**
|
|
||||||
```bash
|
```bash
|
||||||
|
# Все тесты
|
||||||
bun test
|
bun test
|
||||||
|
|
||||||
|
# Юнит тесты
|
||||||
|
bun run test:unit
|
||||||
|
|
||||||
|
# Интеграционные тесты
|
||||||
|
bun run test:integration
|
||||||
|
|
||||||
|
# Watch режим
|
||||||
|
bun run test:watch
|
||||||
|
|
||||||
|
# С coverage
|
||||||
|
bun run test:coverage
|
||||||
```
|
```
|
||||||
|
|
||||||
**Только юнит тесты:**
|
Подробная документация по тестированию в [`tests/README.md`](tests/README.md).
|
||||||
```bash
|
|
||||||
bun test:unit
|
|
||||||
```
|
|
||||||
|
|
||||||
**Только интеграционные тесты:**
|
|
||||||
```bash
|
|
||||||
bun test:integration
|
|
||||||
```
|
|
||||||
|
|
||||||
**Watch режим:**
|
|
||||||
```bash
|
|
||||||
bun test:watch
|
|
||||||
```
|
|
||||||
|
|
||||||
**С coverage:**
|
|
||||||
```bash
|
|
||||||
bun test:coverage
|
|
||||||
```
|
|
||||||
|
|
||||||
Подробная документация по тестированию доступна в [`tests/README.md`](tests/README.md).
|
|
||||||
|
|
||||||
### Структура тестов
|
|
||||||
|
|
||||||
- **Юнит тесты** - CLI, генератор, утилиты, валидация
|
|
||||||
- **Интеграционные тесты** - E2E генерация, сгенерированный клиент
|
|
||||||
- **Тестовые фикстуры** - 7 OpenAPI спецификаций для различных сценариев
|
|
||||||
- **Mock сервер** - для тестирования HTTP запросов
|
|
||||||
|
|
||||||
**Покрываемые сценарии:**
|
|
||||||
- ✅ CLI команды и обработка ошибок
|
|
||||||
- ✅ Генерация TypeScript кода
|
|
||||||
- ✅ Компиляция сгенерированного кода
|
|
||||||
- ✅ HTTP запросы с mock сервером
|
|
||||||
- ✅ Аутентификация (Bearer tokens)
|
|
||||||
- ✅ Edge cases (Unicode, большие спецификации)
|
|
||||||
|
|
||||||
## Лицензия
|
## Лицензия
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@gromlab/api-codegen",
|
"name": "@gromlab/api-codegen",
|
||||||
"version": "1.0.5",
|
"version": "1.0.7",
|
||||||
"description": "CLI tool to generate TypeScript API client from OpenAPI specification",
|
"description": "CLI tool to generate TypeScript API client from OpenAPI specification",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -33,7 +33,20 @@ export async function generate(config: GeneratorConfig): Promise<void> {
|
|||||||
url = config.inputPath;
|
url = config.inputPath;
|
||||||
// Загружаем спецификацию для получения info.title
|
// Загружаем спецификацию для получения info.title
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
spec = await response.json();
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to fetch OpenAPI spec from ${url}: ${response.status} ${response.statusText}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const text = await response.text();
|
||||||
|
try {
|
||||||
|
spec = JSON.parse(text);
|
||||||
|
} catch {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to parse OpenAPI spec from ${url} as JSON. ` +
|
||||||
|
`Response starts with: "${text.slice(0, 50)}..."`
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
inputPath = resolve(config.inputPath);
|
inputPath = resolve(config.inputPath);
|
||||||
spec = await readJsonFile<any>(inputPath);
|
spec = await readJsonFile<any>(inputPath);
|
||||||
|
|||||||
Reference in New Issue
Block a user