Перейти к основному содержимому

@mineflow/api-client

@mineflow/api-client — слой L0 в многослойной архитектуре SDK (ADR-0042). Это единственный файл src/openapi.ts с TypeScript-типами всего REST API MineFlow, сгенерированный из OpenAPI-спеки инструментом openapi-typescript. Пакет zero-runtime: в нём нет ни одной строки исполняемого кода — только interface/type/enum, которые стираются на компиляции. В бандл фронтенда из него не попадает ничего.

Источник истины — live-спека бэка (apps/api/openapi.json, экспортируется из NestJS). Типы попадают в SDK только кодгеном, поэтому они не могут разойтись с реальным API: переименование поля или эндпоинта на бэке ломает типизацию на следующей регенерации, а CI-гейт валит тот же PR. Это краеугольный камень anti-drift гарантии — подробнее в рецепте «Кодген и anti-drift».

Вы почти никогда не импортируете этот пакет напрямую

Типы из @mineflow/api-client потребляет @mineflow/client-core: он строит поверх них типизированный openapi-fetch-клиент (createRestClient<paths>(...)). Прикладной фронтенд работает с хуками @mineflow/client-react и Zod-схемами @mineflow/api-zod, а не с сырыми типами путей. Импорт api-client нужен лишь когда вы хотите вытащить точный тип DTO или ответа эндпоинта вручную.

Установка

pnpm add @mineflow/api-client

В монорепо MineFlow пакет резолвится как workspace:* и обычно подтягивается транзитивно через @mineflow/client-core. Прямых peer-зависимостей у пакета нет — это чистые типы, нужен лишь TypeScript в вашем проекте.

примечание

Если вы ставите полный фронтенд-набор, отдельно добавлять api-client не требуется — он приедет с client-core. Канонический набор пакетов и peer-зависимостей — в обзоре client-core.

Использование

Типичный путь — через client-core

В 95% случаев типы потребляются неявно: вы создаёте клиент один раз, а paths обеспечивают автодополнение URL, параметров и тел запросов.

import { createRestClient } from '@mineflow/client-core';

// fetchImpl уже несёт Authorization (см. client-core)
const client = createRestClient('https://api.mineflow.local', fetchImpl);

// путь, метод, query и тело — всё типизировано из paths
const { data, error } = await client.GET('/api/v1/eam/assets', {
params: { query: { status: 'operational', limit: 50 } },
});
warning
Пути уже содержат /api/v1

Ключи в paths — это полные URL вида /api/v1/eam/assets, а не /eam/assets. Поэтому baseUrl клиента — это origin API (https://api.mineflow.local), без какого-либо суффикса пути. Не добавляйте /api/v1 к baseUrl — получите дубль.

Прямой импорт типов

Когда нужно типизировать переменную, проп компонента или вспомогательную функцию точным контрактом бэка, импортируйте components (DTO-схемы) или paths (формы запросов/ответов):

import type { components, paths } from '@mineflow/api-client';

// DTO из спеки
type Asset = components['schemas']['AssetResponseDto_Output'];

// тело ответа конкретного эндпоинта
type ListAssetsResponse =
paths['/api/v1/eam/assets']['get']['responses']['200']['content']['application/json'];

// query-параметры конкретного эндпоинта
type ListAssetsQuery =
paths['/api/v1/eam/assets']['get']['parameters']['query'];
Для форм берите Zod, а не сырые типы

Если вам нужен тип входного DTO для валидации формы, не выводите его вручную из components['schemas'][...]. Используйте рантайм-схему из @mineflow/api-zod (zCreateAssetDto) и z.infer<> — она генерируется из той же спеки и даёт и тип, и валидацию. Сырые типы api-client хороши для ответов и редких ручных случаев.

Ключевые экспорты

Пакет реэкспортирует всё из сгенерированного src/openapi.ts. Верхнеуровневые символы:

ЭкспортЧто это
pathsКарта всех URL → методы → параметры/тела/ответы. Это то, чем параметризуется openapi-fetch (createClient<paths>).
componentsПереиспользуемые компоненты спеки; components['schemas'][...] — все DTO (AssetResponseDto_Output, CreateAssetDto, GlobalSagaStatusDto_Output, …).
operationsКарта по operationId (например OrganizationsController_list_v1) → её параметры/ответы. Альтернатива адресации через paths.
webhooksRecord<string, never> — вебхуки в спеке не объявлены.
$defsRecord<string, never> — зарезервировано генератором, пусто.
PathsApiV1* (enum'ы)Сгенерированные с флагом --enum рантайм-энумы для значений query/path-параметров отдельных эндпоинтов, напр. PathsApiV1EamAssetsGetParametersQueryStatus.
Именование enum'ов длинное и эндпоинт-специфичное by design

Энумы вроде PathsApiV1EamAssetsGetParametersQueryStatus генерируются автоматически по позиции параметра в спеке. Для статусов сущностей в UI предпочитайте status-энумы и FSM-машины из @mineflow/api-schemas — они стабильнее по имени и привязаны к доменной логике.

Подводные камни

Файл сгенерирован — не редактируйте руками

packages/api-client/src/openapi.ts начинается с баннера AUTO-GENERATED. Не редактировать вручную. Любая ручная правка будет затёрта при следующей регенерации. Меняется он только через изменение API на бэке и повторный кодген.

warning
Имена DTO в components['schemas'] следуют за бэком

Если NestJS-контроллер переименует DTO, ключ в components['schemas'] изменится, и ваш type Asset = components['schemas']['AssetResponseDto_Output'] перестанет компилироваться. Это ожидаемое поведение anti-drift — чините на стороне обращения, не подменяйте локальным типом.

Регенерация

Типы пересобираются корневым скриптом:

pnpm openapi:client

Этот скрипт делает три шага: экспортирует свежую OpenAPI из NestJS (pnpm openapi:exportapps/api/openapi.json), запускает openapi-typescript (tools/scripts/gen-api-client.ts, флаги --enum --alphabetize) и регенерирует доменные хуки (pnpm gen:hooks). Запускайте его после любого изменения REST-контракта на бэке — и коммитьте получившийся openapi.ts вместе с изменениями API.

подсказка

Если CI падает на дрейфе типов — почти всегда это значит, что openapi.ts не пересобрали после правки контроллера. Прогоните pnpm openapi:client локально и закоммитьте дифф.

React Native

Отдельной настройки пакет не требует. Это чистые типы — они работают одинаково на web и в React Native, в бандл ничего не добавляют и платформо-специфичных зависимостей не имеют. Платформенные адаптеры (fetch-polyfill, токен-провайдер) живут в @mineflow/client-core и @mineflow/auth-native; общие особенности RN-интеграции — в рецепте React Native.

Ссылки