import {Meta} from '@storybook/addon-docs/blocks'

<Meta title='@dxtmisha/ru/functional-basic/# Api'/>

# Api

Класс `Api` — это основной инструмент для работы с HTTP-запросами. Он предоставляет простой интерфейс для стандартных методов и управляет глобальными настройками, такими как базовый URL, заголовки по умолчанию и хуки жизненного цикла.

### Основные возможности

Класс предоставляет полный набор инструментов для управления сетевым взаимодействием:
- **CRUD методы** — выполнение `GET`, `POST`, `PUT`, `PATCH`, `DELETE` запросов.
- **Глобальная конфигурация** — настройка базовых URL, заголовков и параметров.
- **Хуки жизненного цикла** — обработка событий до и после запроса (например, для Refresh Token).
- **Гидратация (SSR)** — передача данных от сервера к клиенту для предотвращения дублирования запросов.
- **Кэширование** — сохранение ответов в памяти или внешнем хранилище (LocalStorage).
- **Эмуляция ответов** — создание мок-данных для разработки и тестирования.
- **Управление загрузкой и ошибками** — интеграция с глобальными компонентами индикации и центрами ошибок.

## Базовое использование

Самый простой способ выполнить запрос — использовать статические методы `get`, `post`, `put`, или `delete`. Все методы поддерживают типизацию ответа через Generic.

```javascript
import { Api } from '@dxtmisha/functional-basic'

// Простой GET запрос с типизацией
const data = await Api.get<User[]>({ path: 'users' })

// POST запрос с отправкой данных в теле
const newUser = await Api.post<User>({
  path: 'users',
  request: { name: 'Иван Иванов', job: 'Разработчик' }
})
```

## Глобальная конфигурация

Вы можете настроить поведение API глобально, например, при инициализации приложения. Это избавит от необходимости указывать полные пути и общие заголовки в каждом вызове.

```javascript
// Установка базового URL для всех относительных путей
Api.setUrl('https://api.example.com/v1/')

// Добавление общих заголовков (например, токен авторизации)
Api.setHeaders({
  'Authorization': 'Bearer YOUR_TOKEN'
})

// Установка общих параметров, которые будут добавлены к каждому запросу
Api.setRequestDefault({
  app_version: '1.0.0'
})
```

## Хуки жизненного цикла

Библиотека позволяет внедрить глобальную логику, которая будет срабатывать для каждого запроса. Это удобно для динамического добавления токенов, логирования или централизованной обработки ошибок сервера.

### Хук подготовки (setPreparation)

Выполняется непосредственно перед отправкой запроса на сервер.

- **Параметры**: получает объект `apiFetch`, содержащий все настройки текущего запроса (путь, метод, данные и т.д.).
- **Применение**: проверка прав доступа, добавление динамических параметров в `apiFetch.request` или простое логирование начала операции.

```javascript
Api.setPreparation(async (apiFetch) => {
  // Можно изменить apiFetch перед отправкой
  console.log(`Запуск запроса: ${apiFetch.path}`)
})
```

### Хук завершения (setEnd)

Выполняется после того, как сервер вернул ответ, но до того, как данные попадут в ваш код.

- **Параметры**: получает нативный объект `Response` и объект настроек `apiFetch`.
- **Возвращает**: Promise с объектом `{ reset?: boolean, data?: any }`.
- **Флаг reset**: если вернуть `true`, библиотека прервет текущую цепочку и выполнит запрос заново. Это полезно для автоматического обновления истекшего токена (Refresh Token).
- **Поле data**: позволяет подменить или дополнить данные, которые вернет метод `Api.request`.

```javascript
Api.setEnd(async (response, apiFetch) => {
  // Например, обработка ошибки 401 (Unauthorized)
  if (response.status === 401) {
    const isRefreshed = await myAuthService.refreshToken()
    
    if (isRefreshed) {
      return { reset: true } // Повторить запрос с новым токеном
    }
  }
  
  return {} // Продолжить стандартную обработку
})
```

## Гидратация

Гидратация позволяет передавать данные, полученные при серверном рендеринге (SSR), на клиентскую сторону. Это предотвращает повторное выполнение одних и тех же запросов сразу после загрузки страницы.

1. **На сервере**: выполните нужные запросы и получите скрипт через `Api.getHydrationScript()`.
2. **В шаблоне**: вставьте полученную строку в HTML.
3. **На клиенте**: при инициализации `Api` данные будут автоматически загружены в менеджер ответов.

```javascript
// Пример на сервере (SSR)
await Api.get({ path: 'settings' });
const hydrationScript = Api.getHydrationScript(); // <script>...</script>
```

## Кэширование

Класс `Api` поддерживает автоматическое кэширование ответов. Вы можете использовать как встроенное хранилище в памяти, так и подключить внешнее (например, `LocalStorage`).

```javascript
import { ApiCache, DataStorage } from '@dxtmisha/functional-basic';

// Подключение внешнего хранилища (необязательно)
ApiCache.init(
  async (key) => DataStorage.get(key),
  async (key, value) => DataStorage.set(key, value)
);

// Использование в запросе
const data = await Api.get({
  path: 'catalog/list',
  cache: 3600 // Кэшировать на 1 час (в секундах)
});
```

## Эмуляция ответов

Встроенный менеджер `ApiResponse` (доступен через `Api.getResponse()`) позволяет перехватывать запросы и возвращать мок-данные. Это крайне полезно при разработке интерфейса, когда бэкенд еще не готов, или для написания тестов.

### Регистрация моков

Вы можете добавлять как статические ответы, так и динамические функции.

```javascript
const responseManager = Api.getResponse()

// 1. Статический ответ на GET запрос
responseManager.add({
  path: 'profile',
  method: 'GET',
  response: { id: 1, name: 'Admin' },
  lag: true // Имитация задержки сети (0-2 сек)
})

// 2. Динамический ответ на основе параметров запроса
responseManager.add({
  path: 'users/search',
  method: 'GET',
  response: (request) => {
    return {
      results: [`Результат для: ${request.query}`],
      count: 1
    }
  }
})

// 3. Перехват POST запроса с любым телом
responseManager.add({
  path: 'users/update',
  method: 'POST',
  request: '*any', // Игнорировать проверку тела запроса
  response: { success: true }
})
```

### Режим разработки

Для удобства отладки можно включить логирование эмуляции в консоль. В этом режиме менеджер будет предупреждать в консоли о каждом перехваченном запросе.

```javascript
Api.getResponse().setDevMode(true)
```

Эмулятор срабатывает **до** выполнения реального `fetch`. Если подходящий мок не найден, `Api` выполнит обычный сетевой запрос.
