Introduce scope-aware Context and #[MapContext]#131
Merged
Conversation
jerowork
reviewed
Jun 10, 2026
jerowork
reviewed
Jun 10, 2026
Resolvers often need per-request data that is neither a GraphQL input nor a DI service: the current HTTP request, the authenticated user, or a value computed by an ancestor field. Until now the generated resolver closures ignored webonyx's context value entirely, so the only escape hatches were `#[Arg]` (client input) and `#[Autowire]` (container), and there was no way to thread request state to a resolver. This adds a first-class `Context` value object and a `#[MapContext]` parameter attribute. `Context` is a webonyx `ScopedContext` that stores objects by class (`attachObject`/`getObject`/`maybeGetObject`) and also implements `ArrayAccess`; because it is scoped, a value attached by a resolver is visible to its descendants without leaking to siblings. Resolvers reach it in two ways. A parameter type-hinted `Context` (no attribute) receives the whole context object, recognised automatically by type, so a resolver can read several values or `attachObject()` something for its descendant fields. `#[MapContext]` instead injects a single object from the `Context` by the parameter type — nullable parameters resolve to `null` when absent, non-nullable parameters throw. The generated query, mutation, and field closures now receive webonyx's context as a `mixed` value and pass it through to `ArgumentNodeResolver`. The value is left untouched (it can be anything the server provides); only `Context`/`#[MapContext]` resolution requires it to be a `Context`, throwing a `ContextException` otherwise. Wiring a `Context` onto the server is up to the consumer via the webonyx `context` option (see the docs).
jerowork
approved these changes
Jun 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolvers often need per-request data that is neither a GraphQL input nor a DI service: the current HTTP request, the authenticated user, or a value computed by an ancestor field. Until now the generated resolver closures ignored webonyx's context value entirely, so the only escape hatches were
#[Arg](client input) and#[Autowire](container), and there was no way to thread request state to a resolver.This adds a first-class
Contextvalue object and a#[MapContext]parameter attribute.Contextis a webonyxScopedContextthat stores objects by class (attachObject/getObject/maybeGetObject) and also implementsArrayAccess; because it is scoped, a value attached by a resolver is visible to its descendants without leaking to siblings.#[MapContext]injects an object from theContextinto a resolver parameter by its type — nullable parameters resolve tonullwhen absent, non-nullable parameters throw.The generated query, mutation, and field closures now receive webonyx's context as a
mixedvalue and pass it through toArgumentNodeResolver. The value is left untouched (it can be anything the server provides); only#[MapContext]resolution requires it to be aContext, throwing aContextExceptionotherwise. Wiring aContextonto the server is up to the consumer via the webonyxcontextoption (see the docs).