Gateways de WebSocket con el adaptador de Socket.IO
Implemente handlers de @WebSocketGateway, rooms y hooks del ciclo de vida para la comunicación en tiempo real.
Gateways de WebSocket con el adaptador de Socket.IO es una lección gratuita de NestJS Enterprise Backend APIs en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de NestJS Enterprise Backend APIs, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de NestJS Enterprise Backend APIs incluye 4 lecciones en total.
Partes de esta lección aún no han sido traducidas y se muestran en inglés.
Why Gateways Exist
REST handles request/response, but real-time features (chat, presence, live dashboards) need a persistent, bidirectional channel. NestJS wraps this with a WebSocket Gateway.
- A gateway is a provider decorated with
@WebSocketGateway(). - By default Nest uses the Socket.IO platform adapter (
@nestjs/platform-socket.io). - Gateways are normal Nest classes: they support dependency injection, guards, pipes, and interceptors just like controllers.
Install the deps with npm i @nestjs/websockets @nestjs/platform-socket.io socket.io.
Declaring a Gateway
Decorate a class with @WebSocketGateway() and register it as a provider in a module. You can pass a port and options such as namespace and CORS config.
@SubscribeMessage('event')binds a handler to an inbound Socket.IO event.- The return value (or a
WsResponse) is emitted back to the calling client.
Below, clients sending ping receive a pong reply.
import { WebSocketGateway, SubscribeMessage, MessageBody } from '@nestjs/websockets';
@WebSocketGateway({ namespace: '/chat', cors: { origin: '*' } })
export class ChatGateway {
@SubscribeMessage('ping')
handlePing(@MessageBody() data: string): { event: string; data: string } {
return { event: 'pong', data: `received: ${data}` };
}
}Accessing the Server Instance
To broadcast to many clients you need the underlying Socket.IO Server. Inject it with the @WebSocketServer() property decorator.
server.emit('event', payload)sends to every connected client in the namespace.- This is the foundation for fan-out features like global announcements.
import { WebSocketGateway, WebSocketServer, SubscribeMessage, MessageBody } from '@nestjs/websockets';
import { Server } from 'socket.io';
@WebSocketGateway({ namespace: '/chat' })
export class ChatGateway {
@WebSocketServer()
server: Server;
@SubscribeMessage('broadcast')
handleBroadcast(@MessageBody() message: string): void {
this.server.emit('announcement', message);
}
}The Connected Socket
Each client has its own Socket. Inject it per-handler with @ConnectedSocket() to read auth data, the socket id, or to reply only to that client.
client.emit(...)targets just the sender.client.iduniquely identifies the connection.client.handshakeexposes headers, query, and auth handed in at connect time.
import { WebSocketGateway, SubscribeMessage, MessageBody, ConnectedSocket } from '@nestjs/websockets';
import { Socket } from 'socket.io';
@WebSocketGateway({ namespace: '/chat' })
export class ChatGateway {
@SubscribeMessage('whoami')
whoAmI(@ConnectedSocket() client: Socket, @MessageBody() _: unknown): void {
client.emit('identity', { id: client.id, token: client.handshake.auth?.token });
}
}Lifecycle Hooks
Gateways can implement lifecycle interfaces to react to connection events:
OnGatewayInit→afterInit(server)runs once the server is ready.OnGatewayConnection→handleConnection(client)fires per new client.OnGatewayDisconnect→handleDisconnect(client)fires when a client leaves.
Use these for presence tracking, auth on connect, and cleanup.
import { WebSocketGateway, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { Logger } from '@nestjs/common';
@WebSocketGateway({ namespace: '/chat' })
export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
private readonly logger = new Logger(ChatGateway.name);
afterInit(server: Server): void {
this.logger.log('Gateway initialized');
}
handleConnection(client: Socket): void {
this.logger.log(`Client connected: ${client.id}`);
}
handleDisconnect(client: Socket): void {
this.logger.log(`Client disconnected: ${client.id}`);
}
}Rooms: Grouping Sockets
A room is a server-side label you attach to sockets so you can broadcast to a subset. A socket can belong to many rooms.
client.join('room')adds the socket to a room.client.leave('room')removes it.- Socket.IO automatically puts each socket in a room named after its own
client.id.
Rooms are how you build per-channel chat, per-tenant dashboards, or per-document collaboration.
import { WebSocketGateway, SubscribeMessage, MessageBody, ConnectedSocket } from '@nestjs/websockets';
import { Socket } from 'socket.io';
@WebSocketGateway({ namespace: '/chat' })
export class ChatGateway {
@SubscribeMessage('joinRoom')
joinRoom(@ConnectedSocket() client: Socket, @MessageBody() room: string): void {
client.join(room);
client.emit('joined', room);
}
}Broadcasting to a Room
Target a room with server.to('room').emit(...). To exclude the sender, emit from the client socket: client.to('room').emit(...) sends to everyone in the room except that client.
server.to(room).emit(...)→ everyone in the room.client.to(room).emit(...)→ everyone in the room but the sender.
import { WebSocketGateway, WebSocketServer, SubscribeMessage, MessageBody, ConnectedSocket } from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
@WebSocketGateway({ namespace: '/chat' })
export class ChatGateway {
@WebSocketServer() server: Server;
@SubscribeMessage('sendToRoom')
sendToRoom(
@ConnectedSocket() client: Socket,
@MessageBody() body: { room: string; text: string },
): void {
client.to(body.room).emit('message', { from: client.id, text: body.text });
}
}Acknowledgements with WsResponse
Socket.IO supports request/response style acknowledgements. In Nest you can return a value, a WsResponse<T> object, or even an Observable that streams multiple emissions back.
- Return
{ event, data }to emit a named event back to the caller. - Returning an
Observableemits one message per value, useful for progress updates.
import { WebSocketGateway, SubscribeMessage, MessageBody, WsResponse } from '@nestjs/websockets';
import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@WebSocketGateway({ namespace: '/jobs' })
export class JobsGateway {
@SubscribeMessage('countdown')
countdown(@MessageBody() n: number): Observable<WsResponse<number>> {
const ticks = Array.from({ length: n }, (_, i) => n - i);
return from(ticks).pipe(map((value) => ({ event: 'tick', data: value })));
}
}Validation with Pipes
Gateways reuse Nest's ValidationPipe, but errors are thrown as WsException rather than HTTP exceptions. Apply the pipe at the handler or gateway level and validate a DTO via @MessageBody().
- Set
transform: trueso plain payloads become class instances. - A
WsExceptionis serialized to anexceptionevent on the client.
import { WebSocketGateway, SubscribeMessage, MessageBody } from '@nestjs/websockets';
import { UsePipes, ValidationPipe } from '@nestjs/common';
import { IsString, MinLength } from 'class-validator';
class SendMessageDto {
@IsString() @MinLength(1)
text: string;
}
@WebSocketGateway({ namespace: '/chat' })
export class ChatGateway {
@UsePipes(new ValidationPipe({ transform: true }))
@SubscribeMessage('send')
send(@MessageBody() dto: SendMessageDto): { event: string; data: string } {
return { event: 'sent', data: dto.text };
}
}Authenticating on Connect
Authenticate clients during handleConnection by reading the token from the handshake and disconnecting unauthorized sockets early. Storing the user on client.data makes it available to every later handler.
- Token usually arrives via
handshake.auth.tokenor anAuthorizationheader. - Call
client.disconnect()to reject bad clients before they join rooms.
import { WebSocketGateway, OnGatewayConnection } from '@nestjs/websockets';
import { Socket } from 'socket.io';
import { JwtService } from '@nestjs/jwt';
@WebSocketGateway({ namespace: '/chat' })
export class ChatGateway implements OnGatewayConnection {
constructor(private readonly jwt: JwtService) {}
async handleConnection(client: Socket): Promise<void> {
try {
const token = client.handshake.auth?.token as string;
client.data.user = await this.jwt.verifyAsync(token);
} catch {
client.emit('error', 'Unauthorized');
client.disconnect();
}
}
}Swapping the Adapter for Scale
Out of the box, Socket.IO state lives in a single process. To run multiple Nest instances behind a load balancer you must share room/emit state. Use a custom adapter with the Redis adapter so broadcasts reach clients on other nodes.
- Subclass
IoAdapterand attach@socket.io/redis-adapterincreateIOServer. - Register it via
app.useWebSocketAdapter(new RedisIoAdapter(app))inmain.ts.
import { IoAdapter } from '@nestjs/platform-socket.io';
import { ServerOptions } from 'socket.io';
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';
export class RedisIoAdapter extends IoAdapter {
private adapterConstructor: ReturnType<typeof createAdapter>;
async connectToRedis(): Promise<void> {
const pub = createClient({ url: 'redis://localhost:6379' });
const sub = pub.duplicate();
await Promise.all([pub.connect(), sub.connect()]);
this.adapterConstructor = createAdapter(pub, sub);
}
createIOServer(port: number, options?: ServerOptions): any {
const server = super.createIOServer(port, options);
server.adapter(this.adapterConstructor);
return server;
}
}Quick Check
Test your understanding of room broadcasting semantics.
Recap
You built a real-time layer with NestJS WebSocket gateways on the Socket.IO adapter:
- Gateway basics:
@WebSocketGateway()providers with@SubscribeMessagehandlers; inject the server via@WebSocketServer()and the per-client socket via@ConnectedSocket(). - Lifecycle hooks:
afterInit,handleConnection, andhandleDisconnectfor init, presence, and cleanup. - Rooms:
client.join/leave, thenserver.to(room)for everyone orclient.to(room)to exclude the sender. - Robustness: validate payloads with
ValidationPipe(errors becomeWsException), authenticate inhandleConnection, and use acknowledgements/Observables for replies. - Scale: swap in a Redis-backed
IoAdapterso broadcasts work across multiple instances.
Preguntas frecuentes
¿La lección «Gateways de WebSocket con el adaptador de Socket.IO» es gratis?
Sí — el texto completo de «Gateways de WebSocket con el adaptador de Socket.IO» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de NestJS Enterprise Backend APIs, actualiza a CoddyKit PRO. El curso de NestJS Enterprise Backend APIs incluye 4 lecciones en total.
¿Qué aprenderé en «Gateways de WebSocket con el adaptador de Socket.IO»?
Implemente handlers de @WebSocketGateway, rooms y hooks del ciclo de vida para la comunicación en tiempo real. Practicas NestJS Enterprise Backend APIs con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar NestJS Enterprise Backend APIs?
No se requiere experiencia previa. NestJS Enterprise Backend APIs en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Gateways de WebSocket con el adaptador de Socket.IO»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de NestJS Enterprise Backend APIs?
Sí. Cada lección de NestJS Enterprise Backend APIs incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Gateways de WebSocket con el adaptador de Socket.IO
- Autenticación y protección de conexiones Socket
- Server-Sent Events para envíos unidireccionales
- Escalado en tiempo real con un adaptador Redis Pub/Sub