Skip to content

Introduction

HTTP Client Toolkit is a modular TypeScript library for building resilient HTTP clients. It provides pluggable caching, request deduplication, and rate limiting — with swappable storage backends so you can choose the right persistence layer for your environment.

Composable

Every concern — cache, dedupe, rate limit — is a standalone store. Use only what you need, or compose them all together.

Swappable Backends

Switch between in-memory, SQLite, and DynamoDB without changing your application code. Each implements the same interface.

Adaptive Rate Limiting

Priority-aware rate limiter that monitors user activity and dynamically shifts capacity between user and background pools.

Type Safe

Strict TypeScript with generics, Zod runtime validation, and full IntelliSense support.

The core HttpClient orchestrates three pluggable concerns in a pipeline:

client.get(url)
┌───────┐ ┌────────┐ ┌────────────┐ ┌─────────────┐ ┌───────┐ ┌──────────────┐
│ Cache │ → │ Dedupe │ → │ Rate Limit │ → │ Req Intercpt│ → │ Fetch │ → │ Res Intercpt │
└───────┘ └────────┘ └────────────┘ └─────────────┘ └───────┘ └──────────────┘
↑ │
└───────────── Transform → Validate → Store result ───────────────────────┘
  1. Cache — Return a cached response if available
  2. Dedupe — If an identical request is already in-flight, wait for its result instead of making a duplicate call
  3. Rate Limit — Wait or throw if the rate limit is exceeded
  4. Request Interceptor — Modify the outgoing request (e.g. inject auth headers)
  5. Fetch — Execute the HTTP request via fetchFn (or globalThis.fetch)
  6. Response Interceptor — Inspect or modify the raw Response before parsing
  7. Transform & Validate — Apply responseTransformer then responseHandler
  8. Store — Cache the result, record the rate limit hit, and resolve any deduplicated waiters

Each layer is optional. A cache-only client or a rate-limit-only client works just as well.

@http-client-toolkit/core

HTTP client engine, store interfaces (CacheStore, DedupeStore, RateLimitStore), error types, and the hashRequest utility.

@http-client-toolkit/store-memory

In-memory stores with LRU eviction, TTL support, and adaptive rate limiting. Zero external dependencies.

@http-client-toolkit/store-sqlite

SQLite-backed stores via better-sqlite3 and Drizzle ORM. Data survives process restarts.

@http-client-toolkit/store-dynamodb

DynamoDB stores for serverless and multi-instance environments. Uses native TTL — no cleanup timers needed.

// Cache-only client
const client = new HttpClient({ cache: new InMemoryCacheStore() });
// Rate-limited client with no caching
const client = new HttpClient({
rateLimit: new InMemoryRateLimitStore({
defaultConfig: { limit: 100, windowMs: 60_000 },
}),
});
// Full stack
const client = new HttpClient({
cache: new SQLiteCacheStore({ database: './app.db' }),
dedupe: new SQLiteDedupeStore({ database: './app.db' }),
rateLimit: new SqliteAdaptiveRateLimitStore({ database: './app.db' }),
});
// User-initiated request — gets higher rate limit allocation
const data = await client.get(url, { priority: 'user' });
// Background/automated request — lower priority
const data = await client.get(url, { priority: 'background' });

The client respects Retry-After, RateLimit-Remaining, X-RateLimit-*, and structured RateLimit headers out of the box.