2.1 KiB
loaders.ts
(no submodules)
Purpose
Defines the per-request loader bag the Yoga engine constructs at pipeline
step 7 and disposes at step 11. Two concurrent requests therefore see
independent DataLoader instances — caching that R1 establishes for a
key cannot leak to R2 even when both resolvers call
rctx.loaders.customer.load(id) for the same id within the same event
loop tick.
The bag is the binding between the abstract LoaderFactory contract
(owned by @suaveplan/api-graphql) and the concrete request-scoped loader
handles resolvers see. Disposal is a hook for future async-resource
loaders; today's in-memory factories make it a no-op.
Features
- Constructs one loader handle per registered factory.
- Idempotent
dispose()so the engine can safely call it on both the happy path and the error path. - Returned
handlesmap is frozen-by-convention — engine code never mutates after construction.
Usage: Basic
import { createGraphqlRegistry } from "@suaveplan/api-graphql";
import { buildRequestLoaders } from "@suaveplan/api-graphql-yoga";
const reg = createGraphqlRegistry();
reg.addLoader("customer", async (keys) => keys.map((k) => `customer:${String(k)}`));
const snap = (reg as unknown as { freeze: () => { loaders: ReadonlyMap<string, never> } }).freeze();
const bag = buildRequestLoaders(snap.loaders);
const customer = await bag.handles.customer.load("c1");
bag.dispose();
Usage: Advanced
import { buildRequestLoaders } from "@suaveplan/api-graphql-yoga";
function makeRctx(loaders: Awaited<ReturnType<typeof buildRequestLoaders>>) {
return {
loaders: loaders.handles,
dispose: () => loaders.dispose(),
};
}
API Reference
RequestLoaderBag—{ handles, dispose() }.buildRequestLoaders(factories)— constructs the bag.
Implementation Notes
The disposed boolean lets the engine call dispose() on both happy and
error paths without worrying about double-free. When async-resource
loaders land, the close branch will flip from no-op to a real close
sequence; the public shape stays unchanged.