Skip to content

WebSocket 게이트웨이를 사용하면 HTTP 컨트롤러와 동일한 데코레이터 및 DI 스타일로 실시간 연결을 처리할 수 있습니다. 게이트웨이는 @WebSocketGateway로 데코레이트된 클래스로, Elysia의 네이티브 app.ws() 엔드포인트에 자신을 등록합니다.

게이트웨이 정의

typescript
import { Injectable } from "nestelia";
import {
  WebSocketGateway,
  OnOpen,
  OnMessage,
  OnClose,
  type ElysiaWsContext,
} from "nestelia";

@Injectable()
@WebSocketGateway("/ws/chat")
export class ChatGateway {
  @OnOpen()
  handleOpen(ws: ElysiaWsContext) {
    ws.send("연결되었습니다");
  }

  @OnMessage()
  handleMessage(ws: ElysiaWsContext, message: unknown) {
    ws.send(JSON.stringify({ echo: message }));
  }

  @OnClose()
  handleClose(ws: ElysiaWsContext) {
    console.log("클라이언트가 연결을 끊었습니다");
  }
}

모듈에 등록

DI 컨테이너가 해석할 수 있도록 gateways[] providers[] 모두에 게이트웨이를 추가하세요:

typescript
import { Module } from "nestelia";
import { ChatGateway } from "./chat.gateway";
import { ChatService } from "./chat.service";

@Module({
  providers: [ChatGateway, ChatService],
  gateways: [ChatGateway],
})
export class ChatModule {}

핸들러 데코레이터

데코레이터Elysia 훅인수
@OnOpen()open(ws)ws: ElysiaWsContext
@OnMessage()message(ws, msg)ws: ElysiaWsContext, message: unknown
@OnClose()close(ws, code, reason)ws: ElysiaWsContext, code: number, reason: string

세 가지 모두 선택 사항입니다 — 선언된 핸들러만 등록됩니다.

게이트웨이 옵션

@WebSocketGateway의 두 번째 인수로 Elysia ws() 옵션을 전달할 수 있습니다:

typescript
import { t } from "elysia";

@WebSocketGateway("/ws/secure", {
  query: t.Object({ token: t.String() }),
})
export class SecureGateway {
  @OnOpen()
  handleOpen(ws: ElysiaWsContext) {
    const { token } = ws.data.query;
    // 토큰 검증...
  }
}

의존성 주입

게이트웨이는 생성자 주입을 완전히 지원합니다 — 같은 모듈(또는 임포트된 전역 모듈)에 등록된 모든 프로바이더를 주입할 수 있습니다:

typescript
@Injectable()
@WebSocketGateway("/ws/chat")
export class ChatGateway {
  constructor(private readonly chatService: ChatService) {}

  @OnMessage()
  async handleMessage(ws: ElysiaWsContext, message: unknown) {
    const saved = await this.chatService.save(String(message));
    ws.send(JSON.stringify(saved));
  }
}

가드(Guards)

게이트웨이 클래스의 @UseGuards()WebSocket 업그레이드 전(Elysia의 beforeHandle)에 실행됩니다. 가드가 false를 반환하면 연결이 확립되기 전에 403 Forbidden으로 거부됩니다.

typescript
import { UseGuards } from "nestelia";

@Injectable()
@UseGuards(AuthGuard)
@WebSocketGateway("/ws/private")
export class PrivateGateway {
  @OnOpen()
  handleOpen(ws: ElysiaWsContext) {
    ws.send("인증되었습니다");
  }
}

가드 내부에서 context.getType()"ws"를 반환하고, context.switchToHttp().getRequest()는 HTTP 업그레이드 요청을 반환하므로 헤더와 쿠키를 검사할 수 있습니다:

typescript
@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    // WebSocket 게이트웨이의 경우 context.getType() === "ws"
    const req = context.switchToHttp().getRequest<Request>();
    return req.headers.get("authorization") !== null;
  }
}

ElysiaWsContext

ElysiaWsContext는 느슨한 제네릭으로 Elysia의 ElysiaWS를 재내보내기한 것입니다:

typescript
ws.send(data)       // 클라이언트에 메시지 전송
ws.close()          // 연결 종료
ws.data             // query, headers 및 기타 컨텍스트 데이터
ws.data.query       // 검증된 쿼리 파라미터 (스키마 제공 시)

요청 파이프라인

HTTP 업그레이드 요청
  → beforeHandle (가드가 여기서 실행됨)
  → WebSocket 연결 수립
  → open 핸들러
  → message 핸들러 (메시지마다)
  → close 핸들러

MIT 라이선스로 배포됩니다.