Skip to content

REST Client ​

createRestClient():

ts
createRestClient(config: HttpConfig): RestClient

Creates a full-featured HTTP client built on top of axios: retry, response caching, rate limiting, circuit breaker, auth provider, request tracing, idempotency keys, and an offline queue — all opt-in via HttpConfig.

Methods ​

get(url, config?) ​

GET request.

post(url, data?, config?) ​

POST request.

put(url, data?, config?) ​

PUT request.

patch(url, data?, config?) ​

PATCH request.

delete(url, config?) ​

DELETE request.

request(url, config?) ​

Generic request.

cancellableRequest(key, url, config?) ​

Request cancellable by key.

cancelRequest(key) ​

Cancel a request previously made with cancellableRequest(key, ...).

clearCache() ​

Clear this client's entire response cache. async.

invalidateCache(matcher) ​

Clear only cache entries whose URL matches matcher (substring, RegExp, or (info) => boolean). Returns Promise<number> — the number of entries removed. See Targeted cache invalidation below.

getCircuitBreakerState() ​

Promise<"closed" | "open" | "half-open" | null> — null if circuitBreaker isn't configured. Resolves synchronously (no real async work) unless circuitBreaker.store is set.

getQueuedRequests() ​

Promise<QueuedRequest[]> — requests awaiting the next offline-queue flush (empty if offlineQueue isn't configured).

flushQueue() ​

Manually attempt to send everything queued (also happens automatically on reconnect). No-op if offlineQueue isn't configured.

Options ​

HttpConfig — every field is optional unless noted.

baseURL ​

string

Base URL for all requests.

timeout ​

number

Request timeout in ms.

headers ​

Record<string, string>

Default headers sent with every request.

withCredentials ​

boolean

Include cookies on cross-origin requests.

retry ​

RetryConfig

Retry with exponential backoff. See RequestExecutor — the class that actually implements retry for both createRestClient() and standalone use.

FieldDescription
attemptsNumber of retry attempts
delayMsBase delay between retries in ms
backoffMultiplierExponential backoff multiplier
retriableStatusHTTP status codes eligible for retry (e.g. [429, 500, 503])
maxRetryAfterMsMax wait from Retry-After header in ms (default: 60000)
jitterStrategyBackoff jitter algorithm — see Jitter strategies

cache ​

CacheConfig

Response caching for GET requests.

FieldDescription
enabledEnable response caching
ttlMsCache TTL in ms
strategy"strict" (default) or "stale-while-revalidate"
staleMsExtra time after ttlMs a stale response may still be served (SWR strategy)
storeCustom CacheStore backend — see Custom cache backend below

rateLimit ​

RateLimitConfig

Concurrency + requests-per-interval limiting.

FieldDescription
maxConcurrentMax simultaneous requests
maxRequestsPerIntervalMax requests per time window
intervalMsTime window size in ms
storeCustom RateLimiterStore backend — see Distributed rate limiting
keyBucket name when using a shared store (default: random per-instance id — without an explicit key, a store has no sharing effect)
leaseMsAuto-expiry (ms) for a store-backed concurrency slot if its holder crashes without releasing (default: 30000)
onRateLimitHeadersCallback with every response's raw headers — see Proactive throttling

metrics ​

MetricsConfig

FieldDescription
onRequestStartCallback on request start
onRequestEndCallback on request end (includes duration and bytes)

auth ​

AuthConfig

Bearer-token injection with automatic 401 refresh. See Auth Provider for the full behavior and an example.

FieldDescription
getTokenAsync function returning a Bearer token (called before every request, unless tokenTtlMs is set)
onUnauthorizedOptional async callback on 401 — refresh the token here; request is retried once
tokenTtlMsCache getToken()'s result for this many ms instead of calling it before every request; invalidated automatically on 401

sanitizeHeaders ​

boolean · default: true

Mask sensitive headers in metrics callbacks (secure by default). See Log Sanitization.

sensitiveHeaders ​

string[]

Additional headers to mask, extending DEFAULT_SENSITIVE_HEADERS.

adapter ​

HttpAdapter

Custom HTTP adapter (e.g. native fetch) — replaces the built-in axios transport. See HTTP Adapter.

circuitBreaker ​

CircuitBreakerConfig

See Circuit breaker.

FieldDescription
failureThresholdConsecutive failures before the circuit opens
openMsHow long the circuit stays open before probing again
successThresholdSuccessful probes needed to fully close (optional)
isFailurePredicate deciding whether an error counts as a failure (optional)
storeCustom CircuitBreakerStore for shared state across instances (optional)
keyShared bucket name when using store (optional)

tracing ​

TracingConfig

See Request tracing.

FieldDescription
generateTraceparentAdd a W3C traceparent header to every request (default: false)
providerTracingProvider hook creating a span per request

idempotencyHeaderName ​

string · default: "Idempotency-Key"

Header name used for RestRequestConfig.idempotencyKey. See Idempotency keys.

autoIdempotencyKey ​

boolean · default: false

Have RequestExecutor auto-generate an idempotency key per logical request. See Idempotency keys.

offlineQueue ​

OfflineQueueConfig

See Offline queue.

FieldDescription
enabledTurn on the offline queue
persistAdapterSave/load pair for queued requests
isOnlineFunction reporting current connectivity (default: navigator.onLine)
onOnlineChangeSubscribe to connectivity changes (default: the browser's "online" event)
shouldQueueWhich requests get queued (default: mutating methods — POST/PUT/PATCH/DELETE)
maxQueueSizeCap on queued requests
onFlushSuccessCallback when a queued request is successfully replayed
onFlushErrorCallback when a queued request fails permanently

Per-request cache override ​

js
const res = await client.get('/data', {
  useCache: true,
  cacheTtlMs: 30000,
  cacheKey: 'my-custom-key',
})

File uploads & progress ​

RestRequestConfig extends axios's own AxiosRequestConfig, so data can be a FormData/Blob/ArrayBuffer and onUploadProgress/onDownloadProgress are already typed and wired through — no extra configuration needed on the default (axios) transport:

js
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'),
})

If you use a custom adapter (see HTTP Adapter) instead of the built-in axios transport, onUploadProgress/onDownloadProgress are still passed through to your adapter's config object as-is, but the adapter is responsible for actually calling them — fetch has no native upload-progress event, so a fetch-based adapter needs a ReadableStream reader (or XMLHttpRequest) to implement it. See examples/file-upload.ts.

Targeted cache invalidation ​

clearCache() wipes the entire response cache. To invalidate only the entries affected by a mutation (e.g. after a POST/PUT/DELETE), use invalidateCache() instead — it accepts a substring, a RegExp, or a predicate over { method, url }, and resolves to how many entries were removed. Both methods are async (so a custom cache.store can be backed by a real network call):

js
await client.post('/users/1/orders', newOrder)

await client.invalidateCache('/users/1') // substring match on the cached URL
await client.invalidateCache(/^https:\/\/api\.example\.com\/users\/\d+$/)
await client.invalidateCache(({ method, url }) => method === 'GET' && url.includes('/orders'))

Custom cache backend (CacheStore) ​

By default, cache.enabled: true caches responses in an in-memory TtlCache scoped to that one client instance — fine for a browser SPA, but each server process has its own cold cache in a multi-instance deployment. Pass cache.store to use any backend implementing CacheStore instead — Redis, for example, so cached responses are shared across every instance:

ts
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 are optional — without them, the
  // 'stale-while-revalidate' strategy and invalidateCache() gracefully
  // degrade (see CacheStore's JSDoc) instead of throwing.
}

const client = createRestClient({
  baseURL: 'https://api.example.com',
  cache: { enabled: true, ttlMs: 60_000, store: redisStore },
})

See examples/redis-cache-store.ts for the full annotated version.

Full example ​

js
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 () => {
      /* refresh token here */
    },
  },
  sanitizeHeaders: true,
})

const res = await client.get('/users/1')
console.log(res.data)

// PATCH support
await client.patch('/users/1', { name: 'Alice' })

// Cancellable request
const req = client.cancellableRequest('my-key', '/search', {
  params: { q: 'foo' },
})
// Cancel it any time:
client.cancelRequest('my-key')