WebSocket guards and pipes help control and process data in real-time communication. Guards check if a user can connect or send messages, while pipes clean or transform the data before use.
WebSocket guards and pipes in NestJS
import { CanActivate, ExecutionContext, Injectable, PipeTransform, ArgumentMetadata } from '@nestjs/common'; import { WsException } from '@nestjs/websockets'; @Injectable() export class MyGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const client = context.switchToWs().getClient(); // Your logic here return true; // or false to block } } @Injectable() export class MyPipe implements PipeTransform { transform(value: any, metadata: ArgumentMetadata) { // Your transformation or validation here return value; // or throw new WsException('Error message') } }
Guards must return true to allow the action or false to block it.
Pipes can modify data or throw exceptions to stop processing.
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; import { WsException } from '@nestjs/websockets'; @Injectable() export class AuthGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const client = context.switchToWs().getClient(); const token = client.handshake.auth.token; if (token === 'secret') { return true; } throw new WsException('Unauthorized'); } }
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common'; import { WsException } from '@nestjs/websockets'; @Injectable() export class ValidateMessagePipe implements PipeTransform { transform(value: any, metadata: ArgumentMetadata) { if (!value.text || typeof value.text !== 'string') { throw new WsException('Invalid message format'); } return value; } }
This example shows a WebSocket gateway that uses a guard to allow only clients with the correct token. It also uses a pipe to check that incoming messages have a valid text string. If both pass, it returns a confirmation message.
import { WebSocketGateway, SubscribeMessage, MessageBody, ConnectedSocket, WsException, UseGuards, UsePipes } from '@nestjs/websockets'; import { Socket } from 'socket.io'; import { Injectable, CanActivate, ExecutionContext, PipeTransform, ArgumentMetadata } from '@nestjs/common'; @Injectable() class AuthGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const client = context.switchToWs().getClient<Socket>(); const token = client.handshake.auth.token; if (token === 'secret') { return true; } throw new WsException('Unauthorized'); } } @Injectable() class ValidateMessagePipe implements PipeTransform { transform(value: any, metadata: ArgumentMetadata) { if (!value.text || typeof value.text !== 'string') { throw new WsException('Invalid message format'); } return value; } } @WebSocketGateway() export class ChatGateway { @UseGuards(AuthGuard) @UsePipes(ValidateMessagePipe) @SubscribeMessage('message') handleMessage(@MessageBody() data: { text: string }, @ConnectedSocket() client: Socket): string { return `Received: ${data.text}`; } }
Always throw WsException in guards or pipes to send error messages to clients.
Use @UseGuards() and @UsePipes() decorators to apply guards and pipes on WebSocket handlers.
Guards run before pipes, so permission checks happen before data validation.
Guards control who can connect or send messages.
Pipes check and transform message data before use.
Use them together to keep your WebSocket app safe and clean.
Practice
Solution
Step 1: Understand the role of guards
Guards in NestJS are used to control access by allowing or denying client connections or message handling.Step 2: Differentiate guards from pipes
Pipes transform or validate data, not control access, so they do not decide connection permissions.Final Answer:
To control access and decide if a client can connect or send messages -> Option AQuick Check:
Guards control access = A [OK]
- Confusing guards with pipes
- Thinking guards transform data
- Assuming guards handle logging
Solution
Step 1: Recall decorator usage for guards
Guards are applied using @UseGuards decorator either on the class or method. Applying on method is valid and common.Step 2: Identify correct decorator and target
@UseGuards is correct for guards; @UsePipes is for pipes, and @UseFilters is for exception filters.Final Answer:
@UseGuards(MyGuard) on the gateway method -> Option BQuick Check:
@UseGuards on method = A [OK]
- Using @UsePipes instead of @UseGuards for guards
- Applying filters instead of guards
- Applying decorators on wrong targets
@SubscribeMessage('msg')
@UsePipes(new ValidationPipe())
handleMessage(@MessageBody() data: CreateDto) {
return 'Received';
}Solution
Step 1: Understand ValidationPipe behavior
ValidationPipe checks incoming data and rejects it if invalid, sending an error response.Step 2: Analyze the method setup
The method uses @UsePipes with ValidationPipe, so invalid data triggers rejection, not acceptance or crash.Final Answer:
The message is rejected and an error is sent back to the client -> Option CQuick Check:
ValidationPipe rejects invalid data = C [OK]
- Assuming invalid data is accepted
- Thinking server crashes on invalid data
- Confusing transformation with acceptance
@SubscribeMessage('chat')
@UseGuards(AuthGuard)
@UsePipes(new ParseIntPipe())
handleChat(@MessageBody() data: string) {
return data;
}Solution
Step 1: Check pipe compatibility with data type
ParseIntPipe expects a value that can be parsed to integer, but data is a string that may not convert properly.Step 2: Validate other decorator usage
AuthGuard is valid for WebSocket guards, and decorator order does not cause error here. Returning Promise is optional.Final Answer:
ParseIntPipe cannot parse a string directly without conversion -> Option DQuick Check:
ParseIntPipe needs numeric input = D [OK]
- Assuming guards can't be used on WebSocket
- Thinking decorator order always matters
- Believing return type must be Promise
Solution
Step 1: Assign correct roles to guard and pipe
Guards handle authentication and authorization, so AuthGuard should be used as a guard.Step 2: Use ValidationPipe with DTO for payload validation
ValidationPipe validates and transforms incoming data using a DTO that checks the 'text' property.Step 3: Evaluate other options
Swapping guards and pipes misuses decorators; using guards only requires manual payload validation lacking automation; using pipes only misses authentication checks.Final Answer:
Use @UseGuards(AuthGuard) to check authentication and @UsePipes(ValidationPipe) with a DTO validating 'text' property -> Option AQuick Check:
Guard for auth + Pipe for validation = B [OK]
- Swapping guards and pipes roles
- Skipping automatic validation
- Assuming pipes handle authentication
Ready to prove it?
Pass the test and this pattern moves unknown
