Skip to content

Configuration Reference ​

createClient vs HttpClientFactory ​

Both APIs create and cache HttpClient instances. Choose based on your needs:

createClientHttpClientFactory.create
API styleSingle options objectThree positional arguments
Preset support✅ preset: 'resilient-api'❌
ErgonomicsFlat config, easy to readExplicit separation of concerns
Shared cache✅ same cache✅ same cache
Recommended forNew projects, preset usersAdvanced use, explicit control
typescript
import { createClient } from 'super-http'

const api = createClient({
  baseURL: 'https://api.example.com',
  preset: 'resilient-api',            // preset applies circuit breaker + retry + bulkhead
  headers: { 'X-Service': 'checkout' },
  pool: { maxSockets: 150 },          // override one pool setting
})
typescript
import { HttpClientFactory } from 'super-http'

const api = HttpClientFactory.create(
  'https://api.example.com',
  { headers: { 'X-Service': 'checkout' } },   // http config
  { maxSockets: 150, timeout: 15_000 },         // pool config
)

// add resilience manually
api
  .circuitBreak({ failureThreshold: 10, successThreshold: 3, timeoutMs: 10_000 })
  .retry(3, new ExponentialJitterRetryStrategy(100, 10_000))
  .bulkhead({ maxConcurrent: 50, maxQueue: 200 })

Both share the same cache. The following two calls return the same instance:

typescript
const a = createClient({ baseURL: 'https://api.example.com' })
const b = HttpClientFactory.create('https://api.example.com')
console.log(a === b) // true

PoolConfig ​

Passed as pool in createClient, or as the third argument in HttpClientFactory.create.

OptionTypeDefaultDescription
maxSocketsnumber200Max concurrent sockets per host (≥ 1)
maxFreeSocketsnumber50Max idle keep-alive sockets
keepAlivebooleantrueEnable TCP keep-alive
keepAliveMsecsnumber1000Keep-alive probe interval (ms)
timeoutnumber30000Response timeout (ms)
socketTimeoutMsnumber= timeoutSocket inactivity timeout on the agent
maxContentLengthnumber33554432Max response body accepted (bytes)
maxBodyLengthnumber33554432Max request body sent (bytes)
typescript
createClient('https://api.example.com', {}, {
  maxSockets: 200,
  maxFreeSockets: 50,
  keepAlive: true,
  keepAliveMsecs: 2_000,
  timeout: 15_000,
  socketTimeoutMs: 15_000,
})

timeout is the axios response timeout. socketTimeoutMs reaches the agent and bounds socket inactivity — that is what catches a connection silently dropped by a NAT or firewall. Body limits default to 32 MiB, where axios itself is unlimited.


.deadline(ms) ​

Total time budget for every request: queue waits, all attempts and all backoff combined. See Deadlines & Cancellation.

typescript
client.deadline(2_000)

.retry(retries, strategy, options?) ​

ParameterTypeDescription
retriesnumberMax retry attempts (≥ 0)
strategyRetryStrategy | numberDelay strategy or fixed ms
optionsnumber[] | RetryOptionsStatus codes to add, or an options object
typescript
client.retry(3, 500, [429, 503])                      // add these statuses
client.retry(3, 500, { retryNonIdempotent: true })    // allow POST/PATCH retries
RetryOptionsTypeDefaultDescription
retryOnnumber[]—Extra statuses, on top of the network-error rules
retryNonIdempotentbooleanfalseRetry POST/PATCH on ambiguous errors

Ambiguous errors (ECONNRESET, ETIMEDOUT, ECONNABORTED, EPIPE, 5xx) are retried only for idempotent methods unless retryNonIdempotent is set. See Retry Strategies.

Strategies:

ClassDelay pattern
FixedRetryStrategy(ms)Constant
ExponentialRetryStrategy(init, max, factor?)Doubles each attempt
ExponentialJitterRetryStrategy(init, max, factor?) ⭐Random in [0, cap] — recommended
RetryAfterStrategy(init?, max?, factor?)From Retry-After header, jitter fallback

.circuitBreak(config) ​

OptionTypeDescription
failureThresholdnumberConsecutive counted failures before the circuit opens (≥ 1)
successThresholdnumberSuccesses to close from half-open (≥ 1)
timeoutMsnumberOpen duration before probing (ms)
shouldTrip(error) => booleanWhich errors count. Defaults to network errors and 5xx only

.bulkhead(config) ​

OptionTypeDefaultDescription
maxConcurrentnumber—Max in-flight requests (≥ 1)
maxQueuenumber50Max queued requests
queueTimeoutMsnumber10000Reject queued after this ms. Infinity waits indefinitely

.rateLimit(config) ​

OptionTypeDefaultDescription
permitLimitnumber—Max requests per window (≥ 1)
windowMsnumber—Window size in ms (≥ 1)
queueRequestsbooleanfalseQueue excess instead of rejecting
queueTimeoutMsnumber10000Max wait for a queued token. Infinity waits indefinitely
maxQueuenumber1000Max requests allowed to wait for a token

.fallback(fn) ​

typescript
client.fallback((error: unknown) => fallbackValue)
client.fallback(async (error: unknown) => await alternativeSource())

.dedup(options?) ​

Coalesces identical concurrent requests. Only GET and HEAD by default, and the request body is part of the key.

OptionTypeDefaultDescription
methodsstring[]['GET','HEAD']Methods eligible for coalescing
typescript
client.dedup()
client.dedup({ methods: ['GET', 'HEAD', 'POST'] })  // opt in deliberately

.correlate(options?) ​

Attaches a per-request id to every resilience event and sends it upstream.

OptionTypeDefaultDescription
headerstring'x-request-id'Header carrying the id
generate() => stringcrypto.randomUUIDId generator

.state() ​

Current state of every configured component — see Observability.


.close() ​

Destroys both agents' sockets and clears plugin timers. Call it on shutdown.


.use(plugin) ​

typescript
import { LoggerPlugin, MetricsReporterPlugin } from 'super-http'

client.use(LoggerPlugin({ prefix: '[my-service]', level: 'info' }))
client.use(MetricsReporterPlugin({ intervalMs: 60_000 }))

Per-request policy ​

Any resilience setting can be overridden for a single request via policy:

typescript
// Disable retry for a payment (non-idempotent)
await api.post('/charges', payload, {
  policy: { retry: false, timeout: 10_000 },
})

// Silent fallback for non-critical endpoint
await api.get('/recommendations', {
  policy: { timeout: 300, fallback: () => [] },
})

// Stricter circuit breaker on one endpoint
await api.get('/inventory', {
  policy: {
    circuitBreaker: { failureThreshold: 2, successThreshold: 1, timeoutMs: 3_000 },
  },
})
policy fieldTypeDescription
timeoutnumberOverride the per-attempt timeout (ms)
deadlineMsnumberTotal budget for this call: queue waits + attempts + backoff
signalAbortSignalCancel the whole call, including queue waits and backoff
retry{ attempts, delayMs?, retryOn?, retryNonIdempotent? } | falseOverride retry, or false to disable
circuitBreakerPartial<CircuitBreakerConfig> | falseOverride CB config, or false to bypass
fallback(error) => TOverride fallback for this request

A policy.circuitBreaker override gets its own breaker instance, with its own failure counter — it does not reconfigure the client's.


.on(events) ​

HookEvent typeFired when
onRequestAxiosRequestConfigBefore each HTTP request
onResponseAxiosResponseOn successful response
onErrorunknownOn final failure
onRetryRetryEventBefore each retry attempt
onCircuitStateChangeCircuitStateChangeEventOn circuit state transition
onBulkheadRejectBulkheadRejectEventBulkhead queue full
onFallbackFallbackEventFallback handler invoked
onRateLimitRejectRateLimitRejectEventRate limit token unavailable

Handlers accumulate: two on() calls for the same hook register both, and all run. With correlate() enabled, every event carries a requestId.


.metrics() / .resetMetrics() ​

typescript
const m = client.metrics()
// { requests, success, failed, retries, circuitBreakerTrips,
//   bulkheadRejects, rateLimitRejects, fallbacks,
//   avgLatency, p50Latency, p95Latency, p99Latency, uptime }

client.resetMetrics() // clear all counters

HttpClientFactory.clear() ​

Clears all cached singleton instances (shared between createClient and HttpClientFactory.create).

typescript
import { HttpClientFactory } from 'super-http'

afterEach(() => HttpClientFactory.clear()) // tests

HTTP methods ​

MethodSignature
getget<T>(url, config?)
postpost<T>(url, data?, config?)
putput<T>(url, data?, config?)
patchpatch<T>(url, data?, config?)
deletedelete<T>(url, config?)
requestrequest<T>(axiosConfig)

Released under the MIT License.