Summary
Define a unified, driver-agnostic store interface that all middleware store adapters build on. This prevents each middleware (session, ratelimit, csrf, cache, idempotency) from defining its own Redis/Postgres adapter with duplicated connection management.
Problem
Currently each middleware defines its own store interface:
session.Store — Get/Save/Delete/Reset with context
csrf.Storage — Get/Set/Delete (no context)
ratelimit.Store — Allow (domain-specific)
- Future:
cache.Store, idempotency.Store
Each will need Redis and PostgreSQL adapters, leading to 5×2 = 10+ adapter packages with duplicated connection pooling, error handling, and serialization code.
Proposal
Create a middleware/store package with:
// KV is a minimal key-value interface that driver adapters implement.
type KV interface {
Get(ctx context.Context, key string) ([]byte, error)
Set(ctx context.Context, key string, value []byte, ttl time.Duration) error
Delete(ctx context.Context, key string) error
}
Then each middleware adapter is a thin wrapper:
session.NewRedisStore(kv store.KV) — serializes map[string]any to JSON, delegates to KV
csrf.NewRedisStorage(kv store.KV) — wraps Get/Set/Delete
ratelimit.NewRedisStore(kv store.KV) — uses Lua scripts via an extended KV interface
cache.NewRedisStore(kv store.KV) — delegates with prefix
Driver packages implement store.KV:
driver/redis → redis.NewKV(client) implementing store.KV
driver/postgres → postgres.NewKV(pool) implementing store.KV
Benefits
- Add a new driver (Memcached, DynamoDB) once → all middleware get it
- Middleware authors don't need to know about Redis/Postgres internals
- Connection management stays in the driver, not in each middleware adapter
- Testable via
store.MemoryKV (in-memory implementation for tests)
Summary
Define a unified, driver-agnostic store interface that all middleware store adapters build on. This prevents each middleware (session, ratelimit, csrf, cache, idempotency) from defining its own Redis/Postgres adapter with duplicated connection management.
Problem
Currently each middleware defines its own store interface:
session.Store— Get/Save/Delete/Reset with contextcsrf.Storage— Get/Set/Delete (no context)ratelimit.Store— Allow (domain-specific)cache.Store,idempotency.StoreEach will need Redis and PostgreSQL adapters, leading to 5×2 = 10+ adapter packages with duplicated connection pooling, error handling, and serialization code.
Proposal
Create a
middleware/storepackage with:Then each middleware adapter is a thin wrapper:
session.NewRedisStore(kv store.KV)— serializes map[string]any to JSON, delegates to KVcsrf.NewRedisStorage(kv store.KV)— wraps Get/Set/Deleteratelimit.NewRedisStore(kv store.KV)— uses Lua scripts via an extended KV interfacecache.NewRedisStore(kv store.KV)— delegates with prefixDriver packages implement
store.KV:driver/redis→redis.NewKV(client)implementingstore.KVdriver/postgres→postgres.NewKV(pool)implementingstore.KVBenefits
store.MemoryKV(in-memory implementation for tests)