-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Problem Statement
Currently, rt allows for shared state via a generic State object passed through the router context:
const router = new Router<State>()
.get("/*", async ({ state, next }) => {
state.user = { name: "Wazoo" };
return await next();
})
.get("/:name", ({ state }) => {
// state is accessible here
});While this works well for direct route handlers, it requires "prop drilling" the state or request object into every subsequent function call (e.g., database services, helper utilities, or deep-nested business logic) that needs access to request-specific data like the current user, trace IDs, or localized strings.
Proposed Solution
We should implement or provide a best-practice example for using Deno's node:async_hooks AsyncLocalStorage API within rt. This would allow developers to access the current request's state globally within the asynchronous execution flow without manually passing the state object.
Implementation Idea
We could introduce a middleware utility or a built-in method to wrap the router execution in an AsyncLocalStorage context.
Example Usage:
import { AsyncLocalStorage } from "node:async_hooks";
import { Router } from "@fartlabs/rt";
const als = new AsyncLocalStorage<State>();
// A utility function that can be called anywhere in the app
export function useCurrentUser() {
const store = als.getStore();
return store?.user;
}
const router = new Router<State>()
.use(async ({ state, next }) => {
// Wrap the entire downstream execution in the ALS context
return await als.run(state, () => next());
})
.get("/profile", () => {
const user = useCurrentUser(); // No need to pull from arguments!
return new Response(`Hello, ${user.name}`);
});Reference
Benefits
- Cleaner Code: Removes the need to pass
stateorreqthrough every layer of the service architecture. - Better Integration: Allows 3rd-party logging or telemetry libraries to hook into the
rtrequest lifecycle easily. - Consistency: Aligns
rtwith modern patterns used in frameworks like Next.js (headers(),cookies()) or Hono.
Tasks
- Create a
best-practices/async-local-storage.tsexample in the repository. - (Optional) Consider a built-in
.useStorage(als)helper method on theRouterclass to automate the.run()wrapping. - Update documentation to show how to handle request-scoped logging using this pattern.