Expand description
WebSocket gateways for nestrs.
A #[gateway] struct with a #[messages] impl holds
#[subscribe_message("event")] handlers. Messages ride a JSON envelope
{ "event": "...", "data": ... }. Because a WS upgrade is an HTTP GET,
a gateway self-mounts on the existing HTTP transport — listing it in
#[module(providers = [...])] is the entire wiring; it inherits port,
CORS, TLS, and is governed by the boot-time access graph.
#[gateway(path = "/ws")]
#[use_guards(AuthGuard)]
struct ChatGateway {
#[inject] svc: Arc<RoomService>,
}
#[messages]
impl ChatGateway {
#[subscribe_message("message")]
async fn on_message(&self, msg: SendMessage) -> ChatMessage { /* ... */ }
}§Return-type contract
()— send nothing.T— serialize as the reply on the request’s event name.Result<(), E>/Result<T, E>—Err(e)becomes an error frame{ "event": "<event>", "data": { "error": "<Display of e>" } }and awarn!(target: "nest_rs::ws", ...)log.
Detection is syntactic on the type’s last path segment being Result: a
type alias over Result is not detected and would leak the error
variant on the wire. Always return Result (or std::result::Result)
directly. Display for the error must be wire-safe — avoid
#[error(transparent)] over an ORM/sqlx error.
§Server→client push
WsServer is the @WebSocketServer analog — a connection registry
provided by WsModule. A handler reaches it by declaring a
&WsClient parameter (a reference, distinguished from the owned
payload). Pushes funnel through a per-connection outbox drained by a
writer task, so the read loop never blocks on a slow Sink.
§Guards and lifecycle hooks
- Connection-level:
#[use_guards]on the gateway struct reuses the HTTPGuardtrait and runs on the upgrade request. - Per-message:
#[use_guards]beside a#[subscribe_message]runs the Layer System chain (global + per-message, deduped byTypeId) each time the event fires — sameGuard::check_ws_messageinterface.
#[on_connect] / #[on_disconnect] on the #[messages] impl block are
the OnGatewayConnection / OnGatewayDisconnect analogs; on_disconnect
runs while the connection is still registered.
§Per-gateway namespacing
WsServer is generic over a zero-sized namespace marker (default
Global). #[gateway(namespace = MyNs)] mounts against its own
WsServer<MyNs> — a separate registry the macro self-provides — so two
gateways isolate without sharing a registry.
§Ambient request data context
The connection loop runs in a task after the upgrade completes, so the
task-locals an HTTP request installs have unwound by the time a message
handler runs. The SocketContext seam captures opaque per-connection
state from the post-guard upgrade request and re-installs it around each
dispatch — this is how nest_rs_seaorm::ws re-binds executor + ability
per message without nestrs-ws depending on the ORM or authz.
Re-exports§
pub use serde_json;pub use tracing;pub use poem;
Structs§
- Event
Layer Table - Per-gateway event-name → guard chain, built once at mount by
#[messages]from the global + per-message Layer-System chain. Frozen for the rest of the process: the dispatcher just iterates. - Gateway
Endpoint - The endpoint returned by
gateway_endpoint. Generic over the gateway’s namespaceNso it holds the gateway’s ownWsServer<N>;Nnever escapes onto the handler surface. - Global
- Default namespace marker for
WsServer. - WsClient
- Per-connection handle a
#[subscribe_message]handler receives by declaring a&WsClientparameter — the@ConnectedSocketanalog. Holds its gateway’s registry as a type-erasedRegistryso the handler surface stays free of the namespace parameter. - WsEnvelope
{ "event": ..., "data": ... }— the wire shape every gateway message rides.- WsModule
- WsServer
- Connection registry shared across every connection of a gateway — the
@WebSocketServeranalog. Registered as a singleton byWsModulefor theGlobalnamespace; any service can#[inject] Arc<WsServer>to push to clients in reaction to a domain event.
Enums§
- WsReply
- Dispatch outcome the connection loop turns into a frame (or silence).
Traits§
- Gateway
- Per-connection message dispatcher a gateway implements.
#[messages]emits the impl:dispatchmatches the event name, deserializes the payload, calls the handler (passing&WsClientif it asks for one), and wraps the return inWsReply. Never written by hand. - Registry
- Object-safe face of a
WsServer— the push/room surface aWsClientneeds without naming the namespace. Payloads cross it pre-encoded asserde_json::Valueso the trait stays object-safe. - Socket
Context - WsMessage
Check - Object-safe view of [
nest_rs_guards::Guard::check_ws_message] so the table can store any guard without importing the trait directly (avoids a nest-rs-ws → nest-rs-guards dep cycle).
Functions§
Type Aliases§
- BoxFuture
- Captured
- Opaque per-connection state captured on upgrade and handed back to every
aroundcall. - ConnId
- Identifies one live connection within a
WsServer. Allocated on connect; never reused within a process run.
Attribute Macros§
- async_
trait - gateway
#[gateway(path = "/ws")]— the@WebSocketGatewayanalog. Generatesfrom_container,pub const PATH, and the inherent helpers#[messages]reads back.- messages
- Bind a
#[gateway]impl block’s message handlers. Each#[subscribe_message("event")]method handles{ "event": "...", "data": ... }; the owned parameter is deserialized fromdata, the return value serialized back under the same event (()=> no reply).