REST-клиент
createRestClient():
createRestClient(config: HttpConfig): RestClientСоздаёт полнофункциональный HTTP-клиент поверх axios: повторы, кэширование ответов, ограничение частоты запросов, circuit breaker, провайдер аутентификации, трассировка запросов, ключи идемпотентности и очередь офлайн-запросов — всё опционально через HttpConfig.
Методы
get(url, config?)
GET-запрос.
post(url, data?, config?)
POST-запрос.
put(url, data?, config?)
PUT-запрос.
patch(url, data?, config?)
PATCH-запрос.
delete(url, config?)
DELETE-запрос.
request(url, config?)
Универсальный запрос.
cancellableRequest(key, url, config?)
Запрос, отменяемый по key.
cancelRequest(key)
Отменить запрос, ранее сделанный через cancellableRequest(key, ...).
clearCache()
Очистить весь кэш ответов клиента. async.
invalidateCache(matcher)
Очистить только те записи кэша, чей URL совпадает с matcher (подстрока, RegExp или (info) => boolean). Возвращает Promise<number> — количество удалённых записей. См. Точечная инвалидация кэша ниже.
getCircuitBreakerState()
Promise<"closed" | "open" | "half-open" | null> — null, если circuitBreaker не настроен. Резолвится синхронно (без реальной асинхронной работы), если не задан circuitBreaker.store.
getQueuedRequests()
Promise<QueuedRequest[]> — запросы, ожидающие следующего сброса офлайн-очереди (пусто, если offlineQueue не настроен).
flushQueue()
Вручную попытаться отправить всё, что в очереди (также происходит автоматически при восстановлении связи). No-op, если offlineQueue не настроен.
Опции
HttpConfig — все поля опциональны, если не указано иное.
baseURL
string
Базовый URL для всех запросов.
timeout
number
Таймаут запроса в мс.
headers
Record<string, string>
Заголовки по умолчанию для каждого запроса.
withCredentials
boolean
Включать cookies на кросс-доменных запросах.
retry
RetryConfig
Повторные попытки с экспоненциальным backoff. См. RequestExecutor — класс, который на самом деле реализует повторы и для createRestClient(), и для отдельного использования.
| Поле | Описание |
|---|---|
attempts | Количество повторных попыток |
delayMs | Базовая задержка между попытками в мс |
backoffMultiplier | Множитель экспоненциального backoff |
retriableStatus | HTTP-коды статуса, при которых допустим повтор (например, [429, 500, 503]) |
maxRetryAfterMs | Максимальное время ожидания по заголовку Retry-After в мс (по умолчанию: 60000) |
jitterStrategy | Алгоритм jitter для backoff — см. Стратегии jitter |
cache
CacheConfig
Кэширование ответов для GET-запросов.
| Поле | Описание |
|---|---|
enabled | Включить кэширование ответов |
ttlMs | TTL кэша в мс |
strategy | "strict" (по умолчанию) или "stale-while-revalidate" |
staleMs | Дополнительное время после ttlMs, в течение которого может отдаваться устаревший ответ (SWR) |
store | Кастомный backend CacheStore — см. Пользовательский backend кэша ниже |
rateLimit
RateLimitConfig
Ограничение частоты по конкурентности и запросам за интервал.
| Поле | Описание |
|---|---|
maxConcurrent | Максимум одновременных запросов |
maxRequestsPerInterval | Максимум запросов за временное окно |
intervalMs | Размер временного окна в мс |
store | Кастомный backend RateLimiterStore — см. Распределённое ограничение частоты запросов |
key | Имя бакета при использовании общего store (по умолчанию: случайный id для каждого инстанса — без явного key у store нет эффекта общего использования) |
leaseMs | Автоматическое истечение (мс) для слота конкурентности на базе store, если его владелец упал без освобождения (по умолчанию: 30000) |
onRateLimitHeaders | Коллбэк с сырыми заголовками каждого ответа — см. Проактивное ограничение скорости |
metrics
MetricsConfig
| Поле | Описание |
|---|---|
onRequestStart | Коллбэк при старте запроса |
onRequestEnd | Коллбэк по завершении запроса (включает длительность и количество байт) |
auth
AuthConfig
Вставка Bearer-токена с автоматическим обновлением по 401. См. Провайдер аутентификации за полным описанием поведения и примером.
| Поле | Описание |
|---|---|
getToken | Асинхронная функция, возвращающая Bearer-токен (вызывается перед каждым запросом, если не задан tokenTtlMs) |
onUnauthorized | Опциональный асинхронный коллбэк на 401 — здесь обновляйте токен; запрос повторяется один раз |
tokenTtlMs | Кэшировать результат getToken() на это количество мс вместо вызова перед каждым запросом; сбрасывается автоматически при 401 |
sanitizeHeaders
boolean · default: true
Маскировать чувствительные заголовки в коллбэках метрик (безопасно по умолчанию). См. Санитизация логов.
sensitiveHeaders
string[]
Дополнительные заголовки для маскирования, расширяет DEFAULT_SENSITIVE_HEADERS.
adapter
HttpAdapter
Кастомный HTTP-адаптер (например, нативный fetch) — заменяет встроенный транспорт axios. См. HTTP-адаптер.
circuitBreaker
CircuitBreakerConfig
См. Circuit breaker.
| Поле | Описание |
|---|---|
failureThreshold | Количество последовательных провалов до открытия цепи |
openMs | Сколько цепь остаётся открытой перед следующей пробой |
successThreshold | Сколько успешных проб нужно для полного закрытия (опционально) |
isFailure | Предикат, решающий, считать ли ошибку провалом (опционально) |
store | Кастомный CircuitBreakerStore для общего состояния между инстансами (опционально) |
key | Имя общего бакета при использовании store (опционально) |
tracing
TracingConfig
См. Трассировка запросов.
| Поле | Описание |
|---|---|
generateTraceparent | Добавлять заголовок W3C traceparent к каждому запросу (по умолчанию: false) |
provider | Хук TracingProvider, создающий span на каждый запрос |
idempotencyHeaderName
string · default: "Idempotency-Key"
Имя заголовка, используемое для RestRequestConfig.idempotencyKey. См. Ключи идемпотентности.
autoIdempotencyKey
boolean · default: false
Заставить RequestExecutor автоматически генерировать ключ идемпотентности на логический запрос. См. Ключи идемпотентности.
offlineQueue
OfflineQueueConfig
| Поле | Описание |
|---|---|
enabled | Включить офлайн-очередь |
persistAdapter | Пара save/load для запросов в очереди |
isOnline | Функция, сообщающая текущую связность (по умолчанию: navigator.onLine) |
onOnlineChange | Подписка на изменения связности (по умолчанию: браузерное событие "online") |
shouldQueue | Какие запросы ставятся в очередь (по умолчанию: изменяющие методы — POST/PUT/PATCH/DELETE) |
maxQueueSize | Ограничение размера очереди |
onFlushSuccess | Коллбэк при успешном повторе запроса из очереди |
onFlushError | Коллбэк при окончательном провале запроса из очереди |
Переопределение кэша для отдельного запроса
const res = await client.get('/data', {
useCache: true,
cacheTtlMs: 30000,
cacheKey: 'my-custom-key',
})Загрузка файлов и прогресс
RestRequestConfig расширяет собственный AxiosRequestConfig из axios, поэтому data может быть FormData/Blob/ArrayBuffer, а onUploadProgress/onDownloadProgress уже типизированы и подключены — никакой дополнительной настройки для транспорта по умолчанию (axios) не требуется:
const formData = new FormData()
formData.append('file', fileInput.files[0])
await client.post('/upload', formData, {
onUploadProgress: (event) => {
const percent = event.total ? Math.round((event.loaded / event.total) * 100) : 0
console.log(`Uploaded ${percent}%`)
},
})
await client.get('/large-report.csv', {
responseType: 'blob',
onDownloadProgress: (event) => console.log(event.loaded, 'bytes received'),
})При использовании кастомного adapter (см. HTTP-адаптер) вместо встроенного транспорта axios onUploadProgress/onDownloadProgress всё равно передаются в объект config вашего адаптера как есть, но за их фактический вызов отвечает сам адаптер — у fetch нет нативного события прогресса загрузки, поэтому адаптеру на fetch для этого понадобится читатель ReadableStream (либо XMLHttpRequest). См. examples/file-upload.ts.
Точечная инвалидация кэша
clearCache() стирает весь кэш ответов целиком. Чтобы инвалидировать только записи, затронутые мутацией (например, после POST/PUT/DELETE), используйте вместо этого invalidateCache() — она принимает подстроку, RegExp или предикат над { method, url } и возвращает количество удалённых записей. Оба метода async (чтобы кастомный cache.store мог быть на реальном сетевом вызове):
await client.post('/users/1/orders', newOrder)
await client.invalidateCache('/users/1') // совпадение по подстроке в кэшированном URL
await client.invalidateCache(/^https:\/\/api\.example\.com\/users\/\d+$/)
await client.invalidateCache(({ method, url }) => method === 'GET' && url.includes('/orders'))Пользовательский backend кэша (CacheStore)
По умолчанию cache.enabled: true кэширует ответы в in-memory TtlCache, привязанном к конкретному экземпляру клиента — нормально для браузерного SPA, но в развёртывании с несколькими инстансами у каждого серверного процесса свой холодный кэш. Передайте cache.store, чтобы использовать любой backend, реализующий CacheStore — например, Redis, чтобы кэшированные ответы были общими для всех инстансов:
import { createRestClient, type CacheStore, type ApiResponse } from 'rest-pipeline-js'
const redisStore: CacheStore<ApiResponse<unknown>> = {
async get(key) {
const raw = await redis.get(key)
return raw ? JSON.parse(raw) : undefined
},
async set(key, value, ttlMs) {
await redis.set(key, JSON.stringify(value), 'PX', ttlMs)
},
async delete(key) {
await redis.del(key)
},
async clear() {
await redis.flushdb()
},
// getStale/deleteWhere опциональны — без них стратегия
// 'stale-while-revalidate' и invalidateCache() корректно
// деградируют (см. JSDoc для CacheStore) вместо выброса исключения.
}
const client = createRestClient({
baseURL: 'https://api.example.com',
cache: { enabled: true, ttlMs: 60_000, store: redisStore },
})Полную аннотированную версию см. в examples/redis-cache-store.ts.
Полный пример
import { createRestClient } from 'rest-pipeline-js'
const client = createRestClient({
baseURL: 'https://api.example.com',
timeout: 5000,
retry: {
attempts: 2,
delayMs: 500,
backoffMultiplier: 2,
retriableStatus: [429, 500, 503],
},
cache: { enabled: true, ttlMs: 60000 },
rateLimit: { maxConcurrent: 3, maxRequestsPerInterval: 10, intervalMs: 1000 },
auth: {
getToken: async () => localStorage.getItem('token') ?? '',
onUnauthorized: async () => {
/* здесь обновляем токен */
},
},
sanitizeHeaders: true,
})
const res = await client.get('/users/1')
console.log(res.data)
// Поддержка PATCH
await client.patch('/users/1', { name: 'Alice' })
// Отменяемый запрос
const req = client.cancellableRequest('my-key', '/search', {
params: { q: 'foo' },
})
// Отменить в любой момент:
client.cancelRequest('my-key')