From 1f5e966fd87c3d90a8f60e8dcc2de6e970a92059 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 15 Dec 2024 22:16:11 -0800 Subject: [PATCH] Document derived resolves --- website/docs/04-docblock-tags/04-context.mdx | 37 +++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/website/docs/04-docblock-tags/04-context.mdx b/website/docs/04-docblock-tags/04-context.mdx index 3bbd04c3..cc8a8dd8 100644 --- a/website/docs/04-docblock-tags/04-context.mdx +++ b/website/docs/04-docblock-tags/04-context.mdx @@ -13,6 +13,8 @@ type GQLCtx = { }; ``` +## Consuming context values in resolvers + Grats will detect any resolver parameter that is typed using the `@gqlContext` type and ensure that the context object is passed to the resolver in that position: ```ts @@ -37,7 +39,40 @@ export function me(ctx: GQLCtx): User { Unlike `graphql-js`, Grats does not require that the context object be passed as a specific positional argument to the resolver. You can place the context object anywhere in the argument list, as long as the type is annotated with the `@gqlContext` type. ::: -## Constructing your context object +## Derived context values + +In some cases you may have a context value that is expensive to create, or is only used in some resolvers. In these cases you can define a _derived resolver_. A derived resolver is a function produces a context value. It may optionally read, as arguments, other context values, including other derived context values. + +Once a derived resolver is defined, the type it returns becomes a new context type. **Any resolver argument typed with this type will receive the value produced by the derived resolver returning that type.** + +:::tip +Derived context functions will be called individually by each resolve that wants to aces the derived context value. If you want the result to be reused across multiple resolvers, you should memoize the result. +::: + +```ts +/** + * A resolver which reads both the global context and a derived context value. + * + * @gqlQueryContext */ +export function me(ctx: GQLCtx, db: Database): User { + return db.users.getById(ctx.userID); +} + +// A derived context resolver cached using a WeakMap to ensure the value is +// computed at most once per request. + +const DB_CACHE = new WeakMap(); + +/** @gqlContext */ +function createContext(ctx: GQLCtx): Database { + if (!DB_CACHE.has(ctx)) { + DB_CACHE.set(ctx, new Database()); + } + return DB_CACHE.get(ctx); +} +``` + +## Constructing your root context object The mechanism by which you construct your context object will vary depending upon the GraphQL server library you are using. See your GraphQL server library's documentation for more information.