Skip to content

Rest Pipeline JS

v2.1.5СетьVanilla JSVueReact

Гибкий модульный оркестратор пайплайнов для REST API — повторные попытки с backoff, кэширование, ограничение частоты запросов, потоковые данные, система плагинов, интеграции с Vue/React.

Rest Pipeline JS
Начать знакомство →
npm install rest-pipeline-js@latest
01 — Назначение

Когда это пригодится

Простой fetch с обработкой ошибок работает, пока в проекте не понадобились retry, кэш, лимиты запросов и обновление токена одновременно — rest-pipeline-js собирает всё это в один настраиваемый пайплайн вместо россыпи разрозненного кода на каждый случай.

Оформление заказа не должно задвоиться

Покупатель дважды нажимает «Оплатить» из-за медленной сети — идемпотентные ключи гарантируют, что повторный запрос не создаст второй заказ, а офлайн-очередь довозит операцию, если соединение обрывается совсем.

Дашборд собирается из зависимых запросов

Первый запрос отдаёт список объектов, второй — метрики по каждому, третий — сравнение с прошлым периодом, и результат каждого шага определяет параметры следующего. Вся эта цепочка описывается одним пайплайном, где каждый шаг сам получает нужные данные от предыдущего — вместо запросов, вложенных друг в друга, и ручной передачи результатов между ними.

Бронирование услуги — несколько связанных проверок

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

Ответ сервера не проходит валидацию

Схема валидации (Zod, Yup или Valibot) ловит некорректный ответ до того, как он попадёт в остальной код, а сам процесс получает шанс подставить значение по умолчанию вместо аварийного завершения целиком.

02 — Фичи

Коротко о главном

Мощный HTTP‑клиент с продвинутыми возможностями

Мощный HTTP‑клиент с продвинутыми возможностями

Создавайте клиенты с повторными попытками (экспоненциальная задержка, Retry‑After, jitter), кэшированием (TTL, stale‑while‑revalidate, инвалидация), ограничением частоты (локальным и распределённым), автоматической аутентификацией с обновлением токена, защитой от сбоев (circuit breaker), отменой запросов по ключу, идемпотентностью и офлайн‑очередью мутирующих операций.

Оркестратор пайплайнов с последовательными и параллельными этапами

Оркестратор пайплайнов с последовательными и параллельными этапами

Стройте гибкие пайплайны из последовательных и параллельных групп этапов с условиями, хуками before/after/errorHandler, общим контекстом (sharedData), паузой и возобновлением, экспортом/импортом состояния, перезапуском отдельных шагов и вложенными подпайплайнами. Управляйте выполнением с помощью AbortSignal и метрик.

Потоковые этапы и WebSocket

Потоковые этапы и WebSocket

Используйте stream-этапы для обработки SSE и любых AsyncIterable с получением чанков в реальном времени (onChunk) и поддержкой отмены. WebSocket-этапы обеспечивают постоянное соединение с колбэками onOpen/onMessage/onClose/onError, автоматическим закрытием по условию, таймаутами и интеграцией с сигналом отмены.

Готовая интеграция с Vue 3 и React 19+

Готовая интеграция с Vue 3 и React 19+

Vue-композаблы и React-хуки (usePipelineRun, usePipelineProgress) позволяют запускать пайплайны и отслеживать прогресс в компонентах. Все хуки SSR-безопасны. Плагины, глобальные middleware, метрики и трассировка (W3C traceparent, OpenTelemetry) легко подключаются без изменения логики этапов.

Отказоустойчивость, тестирование и адаптация

Отказоустойчивость, тестирование и адаптация

Офлайн‑очередь, идемпотентные ключи и восстановление шагов через recoverStep обеспечивают надёжность. Валидация схем (Zod, Yup, Valibot) и кастомные HTTP-адаптеры (fetch, edge) адаптируют библиотеку под любую среду. Встроенный mock-адаптер упрощает тестирование без реального бекенда.

Пагинация и fluent-конструктор пайплайнов

Пагинация и fluent-конструктор пайплайнов

Готовые хелперы paginate, paginateAll и flattenPages избавляют от ручного написания циклов пагинации — от курсорной до offset, включая автоматическую остановку по условию. Пайплайны можно строить и через fluent-API createPipeline().pipe().step(), где TypeScript выводит тип данных автоматически.

03 — Быстрый пример

Как это работает

Клиент с ретраями, кэшем и авторизацией

Один раз настраиваем REST-клиент — дальше он сам обрабатывает повторные попытки, кэш и обновление токена.

client.ts
import { createRestClient } from 'rest-pipeline-js'

const client = createRestClient({
  baseURL: 'https://api.example.com',
  retry: { attempts: 2, delayMs: 500, backoffMultiplier: 2 },
  cache: { enabled: true, ttlMs: 60000 },
  auth: {
    getToken: async () => localStorage.getItem('token') ?? '',
    onUnauthorized: async () => {
      // refresh the token here
    },
  },
})

const user = await client.get('/users/1')

Пайплайн поверх клиента

Собираем шаги в пайплайн — каждый получает результат предыдущего через sharedData.

pipeline.ts
import { PipelineOrchestrator } from 'rest-pipeline-js'

const orchestrator = new PipelineOrchestrator({
  config: {
    stages: [
      {
        key: 'fetchUser',
        request: ({ sharedData }) => client.get(`/users/${sharedData.userId}`),
      },
      {
        key: 'processData',
        request: ({ prev }) => ({ ...prev.data, processed: true }),
      },
    ],
  },
  sharedData: { userId: 42 },
})

const result = await orchestrator.run()
console.log(result.success, result.stageResults)

Автоматический выключатель при падении бэкенда

После нескольких неудач подряд клиент перестаёт бить по упавшему API и сразу отклоняет запросы локально — а затем сам пробует восстановиться пробным запросом.

circuit-breaker.ts
import { createRestClient, CircuitOpenError } from 'rest-pipeline-js'

const client = createRestClient({
  baseURL: 'https://api.example.com',
  circuitBreaker: {
    failureThreshold: 5, // open after 5 consecutive failures
    openMs: 30_000, // stay open for 30s before probing again
    isFailure: (error) => error.status === undefined || error.status >= 500, // ignore 4xx
  },
})

try {
  await client.get('/flaky-endpoint')
} catch (err) {
  if (err instanceof CircuitOpenError) {
    // rejected locally — no network call was made
  }
}