-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
keyboard_arrow_right keyboard_arrow_down
-
-
keyboard_arrow_right keyboard_arrow_down
- YCLIENTS
- Маркетплейс интеграций
- Плагинизация
- Руководство по созданию Frontend плагина
- HTTP клиент для работы с API YCLIENTS
HTTP клиент для работы с API YCLIENTS
Современный и гибкий HTTP-клиент для TypeScript/JavaScript приложений с поддержкой интерцепторов, повторных попыток и отмены запросов.
Основные возможности
- Типобезопасность — полная поддержка TypeScript.
- Повторные попытки — автоматические retry с экспоненциальной задержкой.
- Интерцепторы — перехват и модификация запросов/ответов.
- Отмена запросов — поддержка AbortController.
- Фабрика клиентов — простое создание клиентов разных типов.
- Модульность — легко расширяемая архитектура.
Быстрый старт
import { HttpClientFactory } from '@yclients/api/http';
// Создание клиента
const httpClient = HttpClientFactory.create('fetch', {
baseURL: 'https://api.example.com',
timeout: 10000,
retry: {
count: 3,
delay: 1000,
},
});
// Простой GET запрос
const response = await httpClient.get<User[]>('/users');
console.log(response.data);
Конфигурация
IHttpClientConfig
interface IHttpClientConfig {
baseURL?: string; // Базовый URL для всех запросов
defaultHeaders?: Record<string, string>; // Заголовки по умолчанию
timeout?: number; // Таймаут в миллисекундах
retry?: IHttpRetryConfig; // Конфигурация повторных попыток
}
IHttpRetryConfig
interface IHttpRetryConfig {
count: number; // Количество повторных попыток
delay: number; // Задержка между попытками в миллисекундах
}
Повторные попытки (Retry)
HTTP клиент автоматически повторяет запросы при ошибках с экспоненциальной задержкой:
const config = {
retry: {
count: 3, // 3 повторные попытки
delay: 1000, // Базовая задержка 1 секунда
},
};
// Задержки будут: 1000ms, 2000ms, 4000ms
Методы API
Основные HTTP методы
// GET запрос
const users = await httpClient.get<User[]>('/users');
// POST запрос
const newUser = await httpClient.post<User>('/users', {
name: 'John Doe',
email: 'john@example.com',
});
// PUT запрос
const updatedUser = await httpClient.put<User>('/users/1', {
name: 'Jane Doe',
email: 'jane@example.com',
});
// PATCH запрос
const patchedUser = await httpClient.patch<User>('/users/1', {
name: 'Jane Doe',
});
// DELETE запрос
await httpClient.delete('/users/1');
Универсальный метод request
const response = await httpClient.request<User>({
method: 'POST',
url: '/users',
headers: {
Authorization: 'Bearer token',
},
body: { name: 'John' },
timeout: 5000,
});
Интерцепторы
Интерцепторы позволяют перехватывать и модифицировать запросы, ответы и ошибки.
Добавление интерцептора
const authInterceptor: IHttpInterceptor = {
onRequest: (request) => {
// Добавляем токен авторизации
request.headers = {
...request.headers,
Authorization: `Bearer ${getToken()}`,
};
return request;
},
onResponse: (response) => {
// Логируем успешные ответы
console.log(`✅ ${response.status}: ${response.statusText}`);
return response;
},
onError: (error) => {
// Обрабатываем ошибки авторизации
if (error.status === 401) {
refreshToken();
}
return error;
},
};
httpClient.addInterceptor(authInterceptor);
Удаление интерцептора
httpClient.removeInterceptor(authInterceptor); httpClient.clearInterceptors(); // Удалить все интерцепторы
Опции запросов
IHttpRequestOptions
interface IHttpRequestOptions {
retry?: IHttpRetryConfig; // Переопределить retry настройки для конкретного запроса
}
Примеры использования опций
// Запрос с кастомными retry настройками
const response = await httpClient.get(
'/api/data',
{},
{
retry: {
count: 5,
delay: 2000,
},
},
);
// Запрос с отменой
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
try {
const response = await httpClient.get('/api/slow', {
signal: controller.signal,
});
} catch (error) {
if (error.name === 'AbortError') {
console.log('Запрос был отменен');
}
}
Фабрика клиентов
Создание клиента определенного типа
// Fetch клиент (по умолчанию)
const fetchClient = HttpClientFactory.create('fetch', config);
// Axios клиент (когда будет реализован)
const axiosClient = HttpClientFactory.create('axios', config);
Автоматический выбор клиента
// Автоматически выберет доступный клиент const client = HttpClientFactory.createAuto(config);
Клиент с fallback
// Попробует axios, если не получится - использует fetch
const client = HttpClientFactory.createWithFallback('axios', 'fetch', config);
Создание новых клиентов
// Создать новый клиент с дополнительной конфигурацией
const apiClient = httpClient.create({
baseURL: 'https://api.example.com',
timeout: 5000,
});
// Новый клиент наследует все интерцепторы и настройки
const adminClient = httpClient.create({
baseURL: 'https://admin.example.com',
defaultHeaders: {
'X-Admin-Token': 'admin-token',
},
});
Обработка ошибок
try {
const response = await httpClient.get('/api/data');
} catch (error) {
if (error instanceof Error) {
console.error('Ошибка запроса:', error.message);
// Проверка статуса ошибки
if ('status' in error) {
switch (error.status) {
case 401:
console.log('Не авторизован');
break;
case 404:
console.log('Ресурс не найден');
break;
case 500:
console.log('Ошибка сервера');
break;
}
}
}
}
Примеры использования
Сервис для работы с API
class UserService {
constructor(private httpClient: IHttpClient) {}
async getUsers(): Promise<User[]> {
const response = await this.httpClient.get<User[]>('/users');
return response.data;
}
async createUser(userData: CreateUserRequest): Promise<User> {
const response = await this.httpClient.post<User>('/users', userData);
return response.data;
}
async updateUser(id: string, userData: UpdateUserRequest): Promise<User> {
const response = await this.httpClient.put<User>(`/users/${id}`, userData);
return response.data;
}
async deleteUser(id: string): Promise<void> {
await this.httpClient.delete(`/users/${id}`);
}
}
// Использование
const userService = new UserService(httpClient);
const users = await userService.getUsers();
Интерцептор для логирования
const loggingInterceptor: IHttpInterceptor = {
onRequest: (request) => {
console.log(`🚀 ${request.method} ${request.url}`, {
headers: request.headers,
body: request.body,
});
return request;
},
onResponse: (response) => {
console.log(`✅ ${response.status} ${response.statusText}`, {
data: response.data,
headers: response.headers,
});
return response;
},
onError: (error) => {
console.error(`❌ Request failed:`, error);
return error;
},
};
httpClient.addInterceptor(loggingInterceptor);
Интерцептор для авторизации
const authInterceptor: IHttpInterceptor = {
onRequest: async (request) => {
const token = await getAuthToken();
if (token) {
request.headers = {
...request.headers,
Authorization: `Bearer ${token}`,
};
}
return request;
},
onError: async (error) => {
if (error.status === 401) {
// Попытка обновить токен
const newToken = await refreshAuthToken();
if (newToken) {
// Повторить запрос с новым токеном
return retryRequest(error.config, newToken);
}
}
return error;
},
};
Архитектура
IHttpClient (интерфейс)
↓
AbstractHttpClient (абстрактный класс)
↓
FetchHttpClient (конкретная реализация)
↓
HttpClientFactory (фабрика)
Вспомогательные классы
HttpRequest
Класс для подготовки HTTP запросов. Инкапсулирует логику подготовки тела запроса и заголовков.
import { HttpRequest } from '@yclients/api/http';
const request = {
url: 'https://api.example.com/users',
method: 'POST',
body: { name: 'John', email: 'john@example.com' },
};
const httpRequest = new HttpRequest(request);
const fetchInit = httpRequest.toFetchInit();
// Использование с fetch
const response = await fetch(httpRequest.url, fetchInit);
Особенности:
- Автоматическая сериализация объектов в JSON.
- Правильная обработка FormData и URLSearchParams.
- Автоматическое управление заголовками Content-Type.
HttpResponse
Класс для обработки HTTP ответов. Инкапсулирует логику обработки различных типов контента.
import { HttpResponse } from '@yclients/api/http';
// Получаем Response от fetch
const response = await fetch('https://api.example.com/users');
// Преобразуем в IHttpResponse
const httpResponse = await HttpResponse.fromResponse<User[]>(response);
console.log(httpResponse.status); // 200
console.log(httpResponse.data); // массив пользователей
Особенности:
- Автоматическое определение типа контента.
- Поддержка JSON, текстовых и бинарных ответов.
- Преобразование заголовков в удобный формат.
Расширение функциональности
Для добавления новых возможностей можно:
- Расширить интерфейс
IHttpClient - Наследоваться от
AbstractHttpClient - Добавить новые интерцепторы.
- Создать специализированные клиенты.
Основные изменения:
- Используйте
HttpClientFactoryдля создания клиентов. - Добавьте интерцепторы для расширенной функциональности.
- Используйте опции запросов для тонкой настройки.
- Обрабатывайте ошибки через try-catch.