<!-- Generated from src/SKILL.md. Do not edit manually. -->
# REST Client
## Работа с REST-клиентом
### Базовые Правила
- REST-клиент сервиса оформляй как отдельный `infra/` module с именем `{name}-rest-api`: `pet-store-rest-api`, `billing-rest-api`, `maps-rest-api`.
- Генерация внутри клиента живёт в `{name}-rest-api/generated`. Generated-клиент, выносимый в npm-пакет или пакет монорепозитория, называется `{name}-rest-api-sdk`.
- Внешний код импортирует клиент, типы, enum и GET-хуки только через корневой `index.ts` REST-модуля.
-`client.ts` экспортирует только настроенный транспортный `*HttpClient`: `petStoreHttpClient`, `billingHttpClient`, `mapsHttpClient`.
-`rest-api.ts` экспортирует полный bound API-клиент `*RestApi`, собранный через `createApiClient(*HttpClient, operationsTree)`.
-Не размещай в `client.ts` DTO, `declare module`, `Extended`-типы, GET-хуки и бизнес-логику.
- GET-хуки не импортируют полный `*RestApi`; они импортируют точечную operation и вызывают её через общий `*HttpClient`.
-`hooks/index.ts` содержит `'use client'`; отдельные `use-get-*.hook.ts` остаются обычными файлами без директивы.
- Если OpenAPI нет, ручные operations пиши через `@gromlab/api-codegen@5.1.0+`с тем же контрактом, что у generated SDK: `operation(http, params/body, requestParams?)`.
-Не создавай собственные `fetch`-классы, `methods/*Methods(client)` и ручные `get/post` wrappers для нового ручного клиента.
-Не правь файлы в `generated/` руками. Расширения типов, DTO и именованные response-типы держи в `types/` REST-модуля.
- UI/components не импортируют SDK-пакет, `generated/`, `operations/`, `operationsTree` и транспорт напрямую.
- SDK operations напрямую импортируются только внутри `infra/*-rest-api` и boundary-файлов минимальных clients в `compositions` или `features`.
- Для прямого REST-вызова в server code, submit-функции или сервисе используй именованный API-объект клиента из публичного API REST-модуля или минимальный composition client.
- Для GET-данных в Client Component сначала используй готовый `useGet*` hook REST-модуля.
- GET-хуки являются прозрачными SWR-обёртками над GET operation и живут в `hooks/` этого REST-модуля.
-Не выноси SWR keys, fetcher, DTO mapping, API errors и транспортные детали в UI-компоненты.
- Если в коде появляется бизнес-смысл вроде `isAuth`, `canEdit`, `hasAccess` или `hasPets`, это уже не REST-клиент, а`business/`.
### Full Client vs Minimal Client
- Full client живёт только в `infra/{name}-rest-api/rest-api.ts`.
- Full client собирается из всего generated дерева: `createApiClient(nameHttpClient, operationsTree)`.
- Full client экспортируется через `infra/{name}-rest-api/index.ts` как `nameRestApi`.
- Minimal client допустим только в feature/composition boundary-файле, где нужен ограниченный набор операций для конкретного бизнес-сценария.
- Minimal client собирается из selected operations: `createApiClient(nameHttpClient, { ...только нужные операции... })`.
- GET-hook не использует bound client вообще: он вызывает `operation(nameHttpClient, params, requestParams?)`.
-`operationsTree` не импортируется в GET-хуки и minimal clients.
- Для ручного клиента `operationsTree` пишется вручную в `infra/{name}-rest-api/operations-tree.ts`.
### Рабочий Алгоритм
1. Найди REST-модуль сервиса в `infra/` и работай через его публичный API.
2. Проверь корневой `index.ts`: внешний код не должен импортировать из `generated/`, `hooks/`, `types/` или `errors/` напрямую.
3. Если нужен прямой REST-вызов в server code, submit-функции или сервисе, используй полный `*RestApi` из `infra/{name}-rest-api`.
4. Если данные нужны в Client Component и запрос является GET, сначала ищи готовый `useGet*` hook.
5. Если GET-хука нет, добавь его рядом с клиентом в `hooks/` по контракту раздела `GET-хуки REST-клиента`.
6. Если feature/composition нужен компактный клиент с небольшим набором операций, создай minimal client в boundary-файле этой composition.
7. Если нужно изменить тип ответа или дополнить generated-тип, не меняй generated-файл; добавь тип или расширение в `types/`.
8. Если REST-клиента ещё нет или нужно подключить новый внешний API, открой конкретный локальный setup-материал ниже.
9. После изменений проверь публичные экспорты, отсутствие SDK imports в UI/components и то, что SWR-механика не утекла в компоненты.
### Создание И Настройка Клиента
Создание нового REST-клиента - редкий сценарий. Не открывай setup-материалы, если задача сводится к использованию существующего клиента, GET-хука или публичного API.
- [Настройка REST-клиента](./reference/canons/setup.md) - состав REST-клиента, структура модуля и базовая настройка.
- [Автогенерация из OpenAPI](./reference/canons/auto.md) - генерация split-клиента через `@gromlab/api-codegen`.
- [Кастомизация HTTP-клиента](./reference/canons/http-client.md) - опции и хуки `HttpClient`: авторизация, refresh token, транспорт.
- [SDK-пакет REST-клиента](./reference/canons/sdk.md) - вынос generated-клиента в npm-пакет или пакет монорепозитория `{name}-rest-api-sdk`.
- [Ручное создание](./reference/canons/manual.md) - ручной REST-клиент, если OpenAPI нет или он неполный.
### Включённые Разделы
- [Использование REST-клиента](#использование-rest-клиента) - прямой вызов готового клиента.
- [GET-хуки REST-клиента](#get-хуки-rest-клиента) - контракт `useGet*`, key-функций и SWR-обёрток.
## Использование REST-клиента
Как выбрать правильную точку вызова REST API.
### Прямой вызов полного API
Для server code, submit-функции, adapter или сервиса импортируйте полный API-клиент из публичного API REST-модуля.
```ts
import { petStoreRestApi } from 'infra/pet-store-rest-api'
export const getPet = async (petId: number) => {
return petStoreRestApi.pet.getPetById({ petId })
}
```
Внешний код не импортирует SDK-пакет, `generated/`, `operations/`, `operationsTree`, `client.ts` или `rest-api.ts` напрямую.
### Minimal Client В Composition Boundary
Если business composition нужен компактный клиент из нескольких операций, собирайте его в boundary-файле этой composition.
Minimal client не экспортируется из общего `infra/{name}-rest-api`. Он принадлежит конкретному feature/composition boundary и содержит только операции этого сценария.
### GET В Client Components
Client Components используют только готовые `useGet*` hooks REST-модуля.
```tsx
import { useGetPetDetail } from 'infra/pet-store-rest-api'
return ['pet-store-rest-api', `/pet/findByStatus${getPetListQuery(params)}`] as const
}
/**
* Получает список питомцев по статусу.
*/
export const useGetPetList = (
params?: FindPetsByStatusParams | null,
config?: SWRConfiguration<Pet[]>,
) => {
const key = getPetListKey(params)
const fetcher = () => findPetsByStatus(
petStoreHttpClient,
params as FindPetsByStatusParams,
)
return useSWR<Pet[]>(key, fetcher, config)
}
```
`params as FindPetsByStatusParams` допустим только в fetcher: готовность параметров проверена в key-функции, а при `key = null` SWR не вызывает fetcher.
import { getStoreInventory } from '../generated/operations/get-store-inventory'
import type { SWRConfiguration } from 'swr'
import useSWR from 'swr'
import { petStoreHttpClient } from '../client'
import type { StoreInventory } from '../types'
export const getStoreInventoryKey = () => {
return ['pet-store-rest-api', '/store/inventory'] as const
}
/**
* Получает инвентарь магазина.
*/
export const useGetStoreInventory = (
config?: SWRConfiguration<StoreInventory>,
) => {
return useSWR<StoreInventory>(
getStoreInventoryKey(),
() => getStoreInventory(petStoreHttpClient),
config,
)
}
```
Если generated operation возвращает безымянный тип вроде `Record<string, number>`, а тип нужен наружу, вынесите его в `types/`.
### Пример С Request Params
Если operation зависит от разовых headers или дополнительных query-параметров, соберите `requestParams` внутри fetcher. Key-функция должна учитывать параметры, которые меняют результат запроса.