Stores
Both the Session and Cache features in Harpia rely on a generic storage system. By default, they use an in-memory storage, but the framework provides a simple Store interface that you can implement to connect your application to any persistent database like Redis, Memcached, or PostgreSQL.
The Store Interface
If you want to create a custom storage engine, your class just needs to implement the Store interface from @harpiats/core.
export interface Store<T = any> {
get(key: string): Promise<T | undefined>;
set(key: string, data: T): Promise<void>;
delete(key: string): Promise<void>;
}
MemoryStore (Default)
Harpia comes with a built-in MemoryStore that implements this interface. It stores data in a Map directly in the process memory (RAM).
By default, the MemoryStore has a limit of 5000 items to prevent your application from running out of memory. When the limit is reached, it automatically deletes the oldest entry before adding a new one.
import { MemoryStore, Session, Cache } from "@harpiats/core";
// By default, instantiating Cache or Session without options uses MemoryStore(5000)
const cache = new Cache();
// You can customize the item limit if needed
const customMemoryStore = new MemoryStore(10000);
const session = new Session({ store: customMemoryStore });
Production Usage
The MemoryStore is extremely fast and perfect for development, but it loses all its data when the server restarts. Furthermore, if you scale your application to run multiple instances (horizontal scaling), the instances will not share the same memory store. For production, always use a persistent, centralized store like Redis.
Creating a Custom Store (e.g., Redis)
To use a database like Redis, you simply need to create a class that wraps your Redis client and implements the three required methods.
Here is an example of how you can create a RedisStore:
// redis-store.ts
import { createClient } from "redis";
import type { Store } from "@harpiats/core";
// 1. Initialize your Redis client
const redisClient = createClient({ url: "redis://localhost:6379" });
redisClient.connect();
// 2. Implement the Store interface
export class RedisStore<T = any> implements Store<T> {
public async get(key: string): Promise<T | undefined> {
const data = await redisClient.get(key);
return data ? JSON.parse(data) : undefined;
}
public async set(key: string, data: T): Promise<void> {
// You can optionally pass expiration times here
await redisClient.set(key, JSON.stringify(data));
}
public async delete(key: string): Promise<void> {
await redisClient.del(key);
}
}
Injecting the Custom Store
Once your custom store is created, you can inject it directly into the Session or Cache constructors. The framework will automatically start using Redis for all its operations.
// app.ts
import harpia, { Session, Cache } from "@harpiats/core";
import { RedisStore } from "./redis-store";
const app = harpia();
// Now your sessions and caches are distributed and persistent!
const session = new Session({ store: new RedisStore() });
const cache = new Cache({ store: new RedisStore() });