hono-server-cache-middleware
makes it easier to implement server side caching and invalidation in your hono application. It is different from the cache middleware provided by hono.
- 🚀 Simple integration with Hono applications
- 🎯 Flexible cache key generation
- 🔄 Automatic cache invalidation on non-GET requests
- ⚙️ Customizable cache storage backends
- 🎨 Route-based cache matching
- 📊 Cache hit/miss headers
npm install hono-server-cache
import { Hono } from 'hono'
import { serverCache } from 'hono-server-cache'
const app = new Hono()
// Example using an in-memory cache
const cache = new Map()
app.use(serverCache({
// Cache all routes under /api
matcher: ['/api/*'],
// Cache operations
readCacheFn: (key) => cache.get(key),
writeCacheFn: (key, value) => cache.set(key, value),
invalidateCacheFn: (key) => cache.delete(key)
}))
Creates a middleware function for handling server-side caching.
type HonoCachingOptions<T> = {
keyFn?: (ctx: Hono.Context) => string
readCacheFn: (key: string) => T | undefined | null | Promise<T | undefined | null>
writeCacheFn: (key: string, value: T) => void | Promise<void>
invalidateCacheFn: (key: string) => void | Promise<void>
matcher: string[] | ((ctx: Hono.Context) => MatcherFnResponse)
}
keyFn
: Function to generate cache keys. By default, it uses request path to generate keyreadCacheFn
: Function to read from cachewriteCacheFn
: Function to write to cacheinvalidateCacheFn
: Function to invalidate cache entriesmatcher
: Array of route patterns or function to determine cache behavior
type MatcherFnResponse = {
read: boolean // Whether to attempt reading from cache
write: boolean // Whether to cache the response
invalidate: boolean // Whether to invalidate the cache
}
app.use(serverCache({
matcher: ['/api/*'],
keyFn: (ctx) => `_key:${ctx.req.path}:${ctx.req.query('version')}`,
// ... cache functions
}))
app.use(serverCache({
matcher: (ctx) => ({
read: ctx.req.method === 'GET',
write: ctx.req.method === 'GET',
invalidate: ctx.req.method === 'POST'
}),
// ... cache functions
}))
import { Redis } from 'ioredis'
const redis = new Redis()
app.use(serverCache({
matcher: ['/api/*'],
readCacheFn: async (key) => {
const data = await redis.get(key)
return data ? JSON.parse(data) : null
},
writeCacheFn: async (key, value) => {
await redis.set(key, JSON.stringify(value))
},
invalidateCacheFn: async (key) => {
await redis.del(key)
}
}))
The middleware automatically adds an X-Cache
header to responses:
X-Cache: HIT
- Response was served from cacheX-Cache: MISS
- Response was generated fresh
- For GET requests matching the cache patterns:
- Attempts to read from cache first
- If cache miss, executes the handler and caches the response
- For non-GET requests:
- Invalidates the cache for the matching key
- Processes the request normally
MIT
Contributions are welcome! Please feel free to submit a Pull Request.