🗃️ 내가 다시 볼 것

[NestJS] WebSocket에서 Error Message 보내기

전호영 2024. 1. 16. 02:00

최종 프로젝트에서 채팅을 구현하던 도중 에러 핸들링이 되지 않는 문제가 생겼다.

문제상황은 Websocket에서 createChat() 이벤트를 실행하던 도중 발생했다.

// src/chats/chats.gateway.ts
@WebSocketGateway({
  namespace: 'chats',
})
export class ChatsGateway implements OnGatewayConnection {
  constructor(
    private readonly chatsService: ChatsService,
    private readonly messagesService: ChatMessagesService,
  ) {}
  @WebSocketServer()
  server: Server;
	...
  @SubscribeMessage('create_chat')
  async createChat(@MessageBody() createChatDto: CreateChatDto) {
    const chat = await this.chatsService.createChat(createChatDto);
  }
	...
}

 

creatChat()은 간단히 유저 목록을 받아, 유저들로 이뤄진 채팅방을 만드는 이벤트이다.

만약 존재하지 않는 유저를 보내거나, 아무런 유저도 보내지 않은 경우 등 에러가 발생해야한다.

 

위와 같이 Internal Server Error가 발생하는 것을 볼 수 있다.

 

 

터미널을 보면 createChat 로직으로 들어간 것을 볼 수 있다.

우리가 Dto를 만들었으므로, 잘못된 정보를 보냈을 경우, Dto에서 걸러줘야 하는데 현재 걸러주지 못하고 있는 상황이다.

이런 경우 pipe를 사용해야 하는데, 프로젝트의 main.ts에

app.useGlobalFilters(new HttpExceptionFilter());

 

위 설정을 해줘도 WebSocket에서 Dto에선 잘못된 값들을 걸러주지 못하고 있다.

기본적으로 NestJS는 REST API 기준으로 만들어졌으므로, WebSocket의 Dto가 적용이 안되는 것이다.

Gateway에서 Validate를 사용하려면 직접 데코레이팅을 해줘야한다.

 

@UsePipes(
    new ValidationPipe({
      transform: true,
      whitelist: true,
      forbidNonWhitelisted: true,
    }),
  )
  @SubscribeMessage('create_chat')
  async createChat(@MessageBody() createChatDto: CreateChatDto) {
    const chat = await this.chatsService.createChat(createChatDto);
  }

 

 

여전히 Internal Server Error가 발생한다.

터미널을 보면

 

 

Bad Request Exeption이 발생하는 것을 볼 수 있다.

우리가 보고싶은 에러는 Websocket에러인데, HttpException을 상속받는 Bad Request Exception을 던지고 있다.

이런 경우 HttpException에러를 받아서 WsException으로 변환해주면 된다.

// src/common/exception-filter/ws.exception-filter.ts
import { Catch, HttpException } from '@nestjs/common';
import { BaseWsExceptionFilter } from '@nestjs/websockets';

@Catch(HttpException)
export class WsExceptionFilter extends BaseWsExceptionFilter<HttpException> {
  catch(exception: HttpException, host) {
    const socket = host.switchToWs().getClient();
    socket.emit('exception', { data: exception.getResponse() });
  }
}

위 코드 처럼 HttpException 에러가 발생할 경우, 에러 메세지를 exception이란 이벤트로 소켓에 emit하면 된다.

실제 코드에 적용한 뒤 응답이 바뀌는지 알아보자

 

 

@UsePipes(
    new ValidationPipe({
      transform: true,
      whitelist: true,
      forbidNonWhitelisted: true,
    }),
  )
  @UseFilters(WsExceptionFilter)
  @SubscribeMessage('create_chat')
  async createChat(@MessageBody() createChatDto: CreateChatDto) {
    const chat = await this.chatsService.createChat(createChatDto);
  }

 

 

우리가 원하는 WsException 에러를 받을 수 있게 됐다