Nodejs

 

1. 전체 흐름

  1. 클라이언트 → Gateway (HTTP 요청)

  2. Gateway Controller → AuthService 호출

  3. AuthService → user 서비스로 TCP 요청 전송

  4. User 서비스 → 실제 회원가입/로그인 로직 처리

  5. 응답 → Gateway → 클라이언트 반환

 

 

2. 코드 흐름과 설명

(1) Gateway app.module.ts

  • 환경변수를 ConfigModule로 관리합니다.

  • ClientsModule.registerAsync로 user 서비스와 TCP 연결을 설정합니다.

  • Joi 스키마를 이용해 필수 환경변수를 검증합니다.

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validationSchema: Joi.object({
        HTTP_PORT: Joi.number().required(),
        USER_HOST: Joi.string().required(),
        USER_TCP_PORT: Joi.number().required(),
      }),
    }),
    ClientsModule.registerAsync({
      clients: [
        {
          name: USER_SERVICE,
          useFactory: (cs: ConfigService) => ({
            transport: Transport.TCP,
            options: {
              host: cs.getOrThrow('USER_HOST'),
              port: cs.getOrThrow('USER_TCP_PORT'),
            },
          }),
          inject: [ConfigService],
        },
      ],
      isGlobal: true,
    }),
    AuthModule,
  ],
})
export class AppModule {}

???? 보완 설명: isGlobal: true를 지정하면 ConfigModule과 ClientModule을 앱 전체에서 재사용할 수 있습니다. 따라서 각 모듈마다 중복 선언할 필요가 없습니다.

 

 

(2) main.ts

  • 전역 파이프 ValidationPipe를 사용하여 DTO 유효성 검사를 자동으로 처리합니다.

  • 환경 변수 HTTP_PORT로 실행 포트를 제어합니다.

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(process.env.HTTP_PORT ?? 3000);
}
bootstrap();

???? 보완 설명: ValidationPipe는 class-validator와 함께 동작하여 DTO에 지정된 검증 규칙(@IsString(), @IsNotEmpty() 등)을 자동 적용합니다.

 

 

(3) AuthController

  • @Authorization() 데코레이터를 통해 요청 헤더에서 토큰을 가져옵니다.

  • 토큰이 없으면 UnauthorizedException을 발생시킵니다.

  • 실제 로직은 Gateway가 아니라 User 서비스가 담당합니다.

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('register')
  registerUser(@Authorization() token: string, @Body() dto: RegisterDto) {
    if (!token) throw new UnauthorizedException('토큰이 필요합니다');
    return this.authService.register(token, dto);
  }

  @Post('login')
  loginUser(@Authorization() token: string) {
    if (!token) throw new UnauthorizedException('토큰이 필요합니다');
    return this.authService.login(token);
  }
}

???? 보완 설명: Controller는 단순히 요청을 검증하고 Service에 전달하는 역할만 맡습니다. 비즈니스 로직은 없습니다.

 

 

(4) AuthService

  • User 서비스와의 TCP 통신을 담당합니다.

  • ClientProxy.send()로 메시지를 보내고 lastValueFrom()으로 응답을 Promise로 변환합니다.

@Injectable()
export class AuthService {
  constructor(@Inject(USER_SERVICE) private readonly userMicroservice: ClientProxy) {}

  register(token: string, dto: RegisterDto) {
    return lastValueFrom(
      this.userMicroservice.send({ cmd: 'register' }, { ...dto, token }),
    );
  }

  login(token: string) {
    return lastValueFrom(
      this.userMicroservice.send({ cmd: 'login' }, { token }),
    );
  }
}

???? 보완 설명: 실제 운영 환경에서는 timeout() 연산자를 추가해 무한 대기 상황을 방지하는 것이 좋습니다. 또한 에러가 발생했을 때 Gateway에서 클라이언트에게 적절한 예외를 반환해야 합니다.

 

 

(5) Authorization 데코레이터

  • HTTP 요청의 authorization 헤더 값을 추출합니다.

export const Authorization = createParamDecorator((data: any, ctx: ExecutionContext) => {
  const req = ctx.switchToHttp().getRequest();
  return req.headers['authorization'];
});

???? 보완 설명: 일반적으로 Bearer <token> 형태로 전달되므로, Bearer 접두어를 잘라내고 순수 토큰만 전달하도록 개선하는 것이 바람직합니다.

 

 

(6) DTO

Gateway용 DTO

  • 클라이언트로부터 입력값을 검증합니다.

export class RegisterDto {
  @IsString() @IsNotEmpty() name: string;
  @IsNumber() @IsNotEmpty() age: number;
  @IsString() @IsNotEmpty() profile: string;
}

User 서비스용 DTO

  • Gateway에서 합쳐진 payload(token 포함)를 검증합니다.

export class RegisterDto {
  @IsString() token: string;
  @IsString() name: string;
  @IsNumber() age: number;
  @IsString() profile: string;
}

???? 보완 설명: Gateway와 User 서비스에서 사용하는 DTO는 목적이 다르므로 분리하는 것이 바람직합니다.

 

 

3. 최종 정리

  • Gateway: 요청 수신 → 토큰 검증 → user 서비스로 메시지 전달.

  • User 서비스: 실제 회원가입/로그인 로직 수행.

  • 이점: 관심사 분리, 서비스 확장성, 보안/로깅 일원화.

  • 보완점: 토큰 파싱, 예외 처리, 통신 타임아웃.

 

 

4. 체크리스트

  • Gateway에 AuthController 추가

  • Authorization 데코레이터 구현

  • AuthService에서 user 서비스와 TCP 통신 구현

  • Gateway/User 서비스 DTO 분리

  • ConfigModule로 환경 변수 관리

  • ValidationPipe로 입력 검증

  • Bearer 토큰 파싱 및 예외 처리 고려

  • 타임아웃/에러 처리 보완

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

신중하되 천천히 하라. 빨리 뛰는 것이야말로 넘어지는 것이다. -셰익스피어

댓글 ( 0)

댓글 남기기

작성