-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Open
Description
Problem
Interceptors in gqlgen only receive the request context as their first parameter.
For queries and mutations, this works fine because execution is linear:
- Receive request
- Execute resolver
- Return response (context == request context)
For subscriptions, however:
- gqlgen starts a goroutine that publishes values to a channel
- gqlgen reads from this channel and encodes responses
- At this point, the response has no associated context that interceptors can access
As a result, interceptors cannot access or enrich the "response context" (e.g., metadata, tracing, request-scoped values) for subscription payloads.
They only see the request context from when the subscription was created.
Proposed Changes
1. Extend Response
struct with a Context
field
Current:
type Response struct {
Errors gqlerror.List `json:"errors,omitempty"`
Data json.RawMessage `json:"data"`
Label string `json:"label,omitempty"`
Path ast.Path `json:"path,omitempty"`
HasNext *bool `json:"hasNext,omitempty"`
Extensions map[string]any `json:"extensions,omitempty"`
}
Proposed:
type Response struct {
Context context.Context `json:"-"`
Errors gqlerror.List `json:"errors,omitempty"`
Data json.RawMessage `json:"data"`
Label string `json:"label,omitempty"`
Path ast.Path `json:"path,omitempty"`
HasNext *bool `json:"hasNext,omitempty"`
Extensions map[string]any `json:"extensions,omitempty"`
}
This allows interceptors to access response-level context.
2. Introduce a SubscriptionField interface for subscription result payloads
Instead of subscription resolvers returning (<-chan *T, error)
, have them return something like:
type SubscriptionField[T any] interface {
GetContext() context.Context
GetField() T
}
So subscription resolvers could return:
(<-chan SubscriptionField[*T], error)
This lets each published item carry its own context, which flows naturally into the modified Response.Context.
Some benefit
- Consistent interceptor behavior across queries, mutations, and subscriptions withouth break current interceptor code
- Enables request/response tracing, per-event metadata, and richer observability for subscriptions
- Clean separation of concerns: business payload stays in GetField(), while per-response metadata lives in context.Context
nmazzon
Metadata
Metadata
Assignees
Labels
No labels