@kokosro/ioredis-cache
v0.0.1
Published
A lightweight, TypeScript-first Redis caching library with time-based invalidation and custom encoder support.
Readme
@kokosro/ioredis-cache
A lightweight, TypeScript-first Redis caching library with time-based invalidation and custom encoder support.
Features
- ⚡ Simple, functional API with minimal configuration
- ⏱️ Time-based cache invalidation with customizable TTL
- 🎯 TypeScript-first with full type safety
- 🔌 Custom encoder/decoder support (JSON by default)
- 🔄 Force refresh capability for cache busting
- 📦 Zero dependencies (peer dependencies only)
Installation
npm install @kokosro/ioredis-cache ioredisor with yarn:
yarn add @kokosro/ioredis-cache ioredisPeer Dependencies
ioredis>= 5.0.0typescript>= 4.0.0 (if using TypeScript)
Quick Start
import { createCacheService } from "@kokosro/ioredis-cache";
import Redis from "ioredis";
type User = {
id: string;
name: string;
email: string;
};
// Create a cache service for User data
const getUserCache = createCacheService<User>({
connection: new Redis(),
fetch: async (userId: string) => {
// Your data fetching logic (e.g., database query, API call)
const user = await db.users.findById(userId);
return user;
},
cacheTimeSeconds: 60, // Cache for 60 seconds
});
// Use the cache
const user = await getUserCache("user-123");
// Force refresh the cache
const freshUser = await getUserCache("user-123", true);Configuration Options
The createCacheService function accepts an options object with the following properties:
CreateCacheServiceOptions
| Option | Type | Required | Default | Description |
| ------------------ | ------------------------------------------ | -------- | ---------------- | --------------------------------------------------------- |
| connection | Redis \| RedisOptions | No | new Redis() | Redis connection instance or connection options |
| fetch | (key: string) => Promise<T \| undefined> | Yes | - | Async function to fetch data when cache misses or expires |
| encoder | (data: T) => string | No | JSON.stringify | Function to encode data before storing in Redis |
| decoder | (data: string) => T | No | JSON.parse | Function to decode data retrieved from Redis |
| keyPrefix | string | No | 'cache' | Prefix for all Redis keys |
| keySeparator | string | No | ':' | Separator between prefix and key |
| cacheTimeSeconds | number | No | 15 | Time in seconds before cache is considered stale |
Note: encoder and decoder must be provided together. If you provide one, you must provide the other.
API Reference
createCacheService(options)
Creates a cache service instance.
Type Parameters:
T- The type of data being cached
Returns:
(key: string, forceRefresh?: boolean) => Promise<T | undefined>
Cache Service Function
The function returned by createCacheService:
(key: string, forceRefresh?: boolean) => Promise<T | undefined>;Parameters:
key- Unique identifier for the cached dataforceRefresh- Optional boolean to bypass cache and fetch fresh data (default:false)
Returns:
- Promise resolving to cached/fetched data or
undefinedif not found
Advanced Examples
Custom Redis Connection
import { createCacheService } from "@kokosro/ioredis-cache";
// Using connection options
const cache = createCacheService({
connection: {
host: "localhost",
port: 6379,
password: "your-password",
db: 2,
},
fetch: async (key) => fetchDataFromDB(key),
});
// Or reuse existing Redis connection
import Redis from "ioredis";
const redis = new Redis();
const cache2 = createCacheService({
connection: redis,
fetch: async (key) => fetchDataFromAPI(key),
});Custom Encoder/Decoder
import { createCacheService } from "@kokosro/ioredis-cache";
type BinaryData = Buffer;
const binaryCache = createCacheService<BinaryData>({
fetch: async (key) => fetchBinaryData(key),
encoder: (data) => data.toString("base64"),
decoder: (str) => Buffer.from(str, "base64"),
cacheTimeSeconds: 120,
});Custom Key Prefix and Separator
const userCache = createCacheService({
fetch: async (userId) => fetchUser(userId),
keyPrefix: "myapp:users",
keySeparator: "::",
cacheTimeSeconds: 300,
});
// Keys will be stored as: myapp:users::user-123Force Refresh Example
const productCache = createCacheService({
fetch: async (productId) => fetchProduct(productId),
cacheTimeSeconds: 3600, // 1 hour
});
// Normal cache lookup
const product = await productCache("prod-456");
// Force refresh after product update
await updateProduct("prod-456", newData);
const updatedProduct = await productCache("prod-456", true);Using Built-in JSON Encoder
import { createCacheService, jsonEncoder } from "@kokosro/ioredis-cache";
const cache = createCacheService({
fetch: async (key) => fetchData(key),
encoder: jsonEncoder.encode,
decoder: jsonEncoder.decode,
});How It Works
The library implements a two-layer caching strategy:
- Redis Storage: Data is stored in Redis with your specified key structure
- Timestamp Tracking: In-memory timestamps track when data was last fetched
Cache Flow
┌─────────────────┐
│ Cache Request │
└────────┬────────┘
│
▼
┌─────────────┐
│ Check Redis │
└──────┬──────┘
│
├─── Found & Fresh ──────► Return cached data
│
└─── Not found or stale ──► Fetch from source
└──► Store in Redis
└──► Update timestamp
└──► Return fresh dataWhen Data is Fetched
- Cache miss (key not in Redis)
- Cache expired (timestamp older than
cacheTimeSeconds) - Force refresh requested (
forceRefresh = true)
When Cache is Returned
- Data exists in Redis
- Timestamp is within the
cacheTimeSecondswindow - Not forcing refresh
TypeScript Support
The library is written in TypeScript and provides full type safety:
import { CreateCacheServiceOptions } from "@kokosro/ioredis-cache";
type Product = {
id: string;
name: string;
price: number;
};
// Type inference works automatically
const productCache = createCacheService<Product>({
fetch: async (id) => {
// Return type must be Promise<Product | undefined>
return await api.getProduct(id);
},
});
// Result is typed as Product | undefined
const product = await productCache("prod-123");