Act99 기술블로그

[Nestjs] 주식사이트 만들기-2 채팅 백엔드 만들기 (WebSoketGateway with NestJS) 본문

개발팁저장소/nestjs

[Nestjs] 주식사이트 만들기-2 채팅 백엔드 만들기 (WebSoketGateway with NestJS)

Act99 2021. 12. 9. 16:18

이번에는 채팅기능을 구현하려고 한다.

처음에는 Nestjs 와 Graphql 을 이용해서 CRUD를 만들고 gql 태그를 이용해 Apollo Client로 쿼리를 보내주고 Mutation 을 보내주는 형태로 채팅을 구현하려고 했다.

 

하지만 보통 실시간 채팅 앱 구현은 Websocket을 이용한다고 해서 채팅구현 로직을 바꾸게 되었다.

두 가지 방법을 모두 써서 괜찮은 것으로 구현하려고 하는데,

 

첫 번째는 NestJS 자체의 WebSocket을 이용해 실시간 채팅을 구현하는 방법

두 번째는 GraphQL 과 WebSocket을 이용해 채팅을 구현하는 방법

 

이렇게 두 가지 방법을 사용하려고 한다.

 

먼저, NestJS의 WebSoketGateway 방법을 진행했다.

이 방법은 정말 간단하게 구현이 가능한데,

먼저 nest g gateway (원하는이름) 게이트웨이를 만든 후, app.module => Provider에 넣어준다.

 

그리고 app.gateway.ts에 다음과 같이 코드를 적는다.

import { Logger } from '@nestjs/common';
import {
  SubscribeMessage,
  WebSocketGateway,
  WebSocketServer,
  OnGatewayInit,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway()
export class AppGateway
  implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
  @WebSocketServer() server: Server;
  private logger: Logger = new Logger('ChatGateway');

  @SubscribeMessage('msgToServer')
  handleMessage(client: Socket, payload: string): void {
    this.server.emit('msgToClient', payload, client.id);
  }
  afterInit(server: Server) {
    this.logger.log('Init');
  }
  handleConnection(client: Socket) {
    this.logger.log(`Client connected: ${client.id}`);
  }
  handleDisconnect(client: Socket) {
    this.logger.log(`Client disconnected: ${client.id}`);
  }
}

Logger은 NestJS 터미널에 로그 이름을 띄워주는 기능이며, Server, Client 는 socket.io 에서 왔으며 서버와 클라이언트와의 양방향 소통을 가능하게 해준다. 그리고 Subscribe는 Nestjs의 websocket 사용시 필요한 데코레이션이며 나머지, afterInit, handle~~ 은 연결 유무를 Log로 표현하기 위한 핸들러이다.

 

 

 

다음 Nextjs 와 연동을 시켰다.

 

- chat.tsx

interface Message {
  id: string;
  name: string;
  text: string;
}
interface Payload {
  name: string;
  text: string;
}

const socket = io("http://localhost:4000");

const Chat: React.FC = () => {
  const [title] = useState("BTC");
  const [name, setName] = useState("");
  const [text, setText] = useState("");
  const [messages, setMessages] = useState<Message[]>([]);

  useEffect(() => {
    const receivedMessage = (message: Payload) => {
      const newMessage: Message = {
        id: uuid.v4(),
        name: message.name,
        text: message.text,
      };
      setMessages([...messages, newMessage]);
    };
    socket.on("msgToClient", (message: Payload) => {
      receivedMessage(message);
    });
  }, [messages, name, text]);

  const validateInput = () => {
    return name.length > 0 && text.length > 0;
  };
  const sendMessage = () => {
    if (validateInput()) {
      const message: Payload = {
        name,
        text,
      };
      socket.emit("msgToServer", message);
      setText("");
    }
  };
  return (<div></div>)

 

데이터를 센딩할 시 입력값이 옳바르면 메시지를 서버로 보내주고, 새로운 메시지가 서버에 도달해 클라이언트로 가면

useEffect를 이용해 메시지가 업데이트 될 때마다 메시지 컴포넌트가 화면에 나타나게끔 만든 구조다.

** 이 작업의 경우, 채팅기능 구현은 처음이기 때문에 github나 기타 Medium 등의 커뮤니티 코드를 많이 참조했다.**

 

그리고 NestJS와의 연결상태를 확인해보기위해 로그를 확인해봤는데,

 

연결이 잘 되고 있다.

 

하지만 홈페이지 내에서는

 

 

이렇게 CORS 에러가 생기고 있었다. (다른 출처의 리소스를 교차로 접근 시 생기는 에러)

(혼자 조그만 사이트를 개발할 때도 이걸 발견한 적이 있는데...)

 

한번 혼자 해결해봐야겠다.