2.4 KiB
loaders — per-request DataLoader scope
(no submodules)
Purpose
loaders defines the per-request DataLoader scope the engine creates
around every incoming GraphQL operation. Two concurrent requests
receive distinct loader instances; the cache never leaks across
request boundaries even though both requests draw from the same set of
loader factories registered on the abstract GraphqlRegistry.
The module is deliberately the thinnest possible wrapper around the
LoaderFactory.create() surface owned by @suaveplan/api-types/graphql.
The engine calls createRequestLoaderScope() once per request; resolvers
that need a loader call scope.get(name, factory); the engine disposes
the scope at request end.
Features
- One scope per request — distinct cache per request guaranteed.
- Loader lazily instantiated on first
get(name, factory)call; subsequent calls reuse the instance. dispose()blocks subsequentget()calls so a buggy late resolver cannot resurrect a freed cache.- Zero runtime dependencies — pure JS, fits in ~40 lines.
Usage: Basic
import { createRequestLoaderScope } from "@suaveplan/api-graphql-apollo/loaders";
const scope = createRequestLoaderScope();
const userLoader = scope.get("users", userLoaderFactory);
const user = await userLoader.load("u_42");
scope.dispose();
Usage: Advanced
Wire the scope into a resolver context object so resolvers consume loaders by name through the request context:
import { createRequestLoaderScope } from "@suaveplan/api-graphql-apollo/loaders";
function makeContext(): RequestContext {
const scope = createRequestLoaderScope();
return {
loaders: {
users: () => scope.get("users", userLoaderFactory),
orders: () => scope.get("orders", orderLoaderFactory),
},
finalize: () => scope.dispose(),
} as unknown as RequestContext;
}
API Reference
RequestLoaderScope:get<TKey, TValue>(name, factory): { load }dispose(): voidsize(): number
createRequestLoaderScope(): RequestLoaderScope.
Implementation Notes
The scope is a closure over a Map<string, LoaderInstance> plus a
disposed boolean. Throwing on get after dispose surfaces the
late-resolver bug at the call site instead of silently producing
inconsistent reads. The size accessor is provided so OTel histograms
can record loader-fanout per request.