Subscriptions
GraphQL subscriptions are not yet supported in nest-rs-graphql.
The composed schema mounts async_graphql::EmptySubscription as the
subscription root — build_schema is hardcoded to that shape and there
is no #[subscription] decorator. A resolver method tagged with one
would not compile.
This page is short on purpose: it documents the current state honestly and points to the realtime path that does work today.
What’s mounted today
Section titled “What’s mounted today”pub(crate) fn build_schema( container: Container,) -> Schema<DiscoveredQuery, DiscoveredMutation, EmptySubscription> { // … Schema::build( DiscoveredQuery::from_registry(&container), DiscoveredMutation::from_registry(&container), EmptySubscription, ) // …}Two consequences:
- A client opening a WebSocket against
/graphqlwith thegraphql-wsorgraphql-transport-wssubprotocol gets nothing back — async-graphql’s subscription endpoint is not mounted on the poem route. - The SDL has no
type Subscriptionblock. Tooling that requires one will need to wait until the root is real.
Use WebSockets for realtime
Section titled “Use WebSockets for realtime”Today’s realtime path goes through nest-rs-ws. A #[gateway] opens
a typed channel, #[on_connect] / #[on_disconnect] handle the
lifecycle, and #[subscribe_message] routes each inbound envelope —
the same guards, the same Ability, the same per-message scope as a
mutating route.
See the WebSockets section for the full story. The
gateway shape is decoupled from GraphQL by design: a realtime channel
needs its own contract, not a thin layer on top of an async fn
returning a Stream.
The path to first-class subscriptions
Section titled “The path to first-class subscriptions”When subscriptions land in nest-rs-graphql, the shape will look like
the rest of the resolver surface:
- A
#[subscription]orchestrator method on a#[resolver]impl block, returningimpl Stream<Item = T>orimpl Stream<Item = Result<T>>. - The schema builder routed to async-graphql’s
GraphQLSubscriptionendpoint over the same/graphqlmount. - Guards (
GraphqlResolverGuard+ the operation bridge) running once on connection, plus per-message scope if a subscription multiplexes. - A documented transport bridge (probably
graphql-wsover poem) so the playground works end-to-end.
The framework decisions still apply: the schema composes from a
registry (no Subscription tuple to maintain); the Ability is
seeded into the long-lived context once at connection; the executor
is the pool (subscriptions don’t sit in a transaction). None of that
is implemented yet.
Where to go next
Section titled “Where to go next”- WebSockets — the realtime channel that works today.
- Field resolvers — the closest one-shot equivalent: a single response computed from many sources.