Using context
The context is a value created for one request and shared by every resolver in that execution. Typical contents are the signed-in user, an authorization token, database handles and request-scoped caches.
In Rust the context is a type parameter on the schema. There is no ambient context: any; the
compiler checks every resolver against Ctx.
Define the context
Use the context in an object:
Option<Viewer> makes the field nullable, so a signed-out response is
{ "data": { "viewer": null } }.
Create the context in suku
The HTTP layer builds the context before executing the request:
authenticate is application code. Returning Err(HttpError) rejects the request before GraphQL
execution; returning Ok makes the value available to every resolver.
Context is suku's type-erased container. Context::new(value) stores your AppContext.
gql::execute receives it through ExecutionOptions::with_context(...).
Resolver shapes
Every resolver variant receives &Ctx at the end. Async resolvers use Box::pin because the
future borrows the context for its lifetime:
The future must be Send + 'static where the schema requires it. Avoid holding a lock or a
borrowed reference across an await unless the resulting future satisfies those bounds.
Request-scoped caches and loaders
Put request-scoped data in the context so it is dropped with the request:
RequestCache is shared and type-indexed. Loader batches and caches per request. Neither
survives the request, so results cannot leak between users. See
Dataloaders.
Multiple protocols
If HTTP and WebSocket handlers provide different context data, use an enum and match on the transport inside resolvers:
Rust's exhaustive matching keeps each branch honest; there is no optional property that silently
becomes undefined.
Cold-start and shared state
The context is per request. For application-wide state, put an Arc in the context:
Cloning an Arc is cheap. The schema itself is immutable after build() and can be shared across
threads and requests.
