NestJS Monorepo에서 Common Library 생성하기
이번 강의 주제는 NestJS에서 공통 라이브러리(Common Library) 생성하기입니다. 마이크로서비스 구조에서는 여러 서비스에서 반복적으로 사용되는 상수, 서비스, DTO 등을 한곳에 모아 재사용할 수 있도록 관리하는 것이 중요합니다. 이를 위해 NestJS는 nest g library 명령어로 쉽게 공용 라이브러리를 만들 수 있습니다.
1. Common Library 생성
nest g library
라이브러리 이름으로 common을 입력하면 다음과 같은 구조가 생성됩니다.
libs/common/ ├── src/ │ ├── common.module.ts │ ├── common.service.ts │ ├── index.ts │ └── ... ├── tsconfig.lib.json
Nest CLI가 nest-cli.json과 package.json도 자동 업데이트 해주어 프로젝트 전반에서 @app/common 경로를 사용할 수 있게 됩니다.
2. 환경 변수 추가
order 서비스에서 user 서비스를 TCP로 호출하기 위해 .env에 다음을 추가합니다.
USER_HOST=user USER_TCP_PORT=3001
이제 환경 변수로 User 서비스의 호스트와 포트를 관리할 수 있습니다.
3. 공통 상수 정의
libs/common/src/const.ts:
export const NOTIFICATION_SERVICE = 'NOTIFICATION_SERVICE'; export const ORDER_SERVICE = 'ORDER_SERVICE'; export const PAYMENT_SERVICE = 'PAYMENT_SERVICE'; export const PRODUCT_SERVICE = 'PRODUCT_SERVICE'; export const USER_SERVICE = 'USER_SERVICE';
서비스 이름을 문자열 상수로 관리하여 하드코딩을 피하고 재사용성을 높입니다.
4. AppModule에서 Common Library 적용
기존에 직접 문자열을 넣었던 부분을 @app/common에서 가져옵니다.
import { USER_SERVICE } from '@app/common';
@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(),
        DB_URL: Joi.string().required(),
        PRODUCT_HOST: Joi.string().required(), // ✅ 추가
        PRODUCT_TCP_PORT: Joi.number().required(), // ✅ 추가
      }),
    }),
      ClientsModule.registerAsync({
      clients: [
        {
          name: USER_SERVICE,
          useFactory: (configService: ConfigService) => ({
            transport: Transport.TCP,
            options: {
              host: configService.getOrThrow<string>('USER_HOST'),
              port: configService.getOrThrow<number>('USER_TCP_PORT'),
            },
          }),
          inject: [ConfigService],
        },
        {
          name: PRODUCT_SERVICE, // ✅ 추가
          useFactory: (configService: ConfigService) => ({
            transport: Transport.TCP,
            options: {
              host: configService.getOrThrow('PRODUCT_HOST'),
              port: configService.getOrThrow('PRODUCT_TCP_PORT'),
            },
          }),
          inject: [ConfigService],
        },
      ],
      isGlobal: true,
    }),
    OrderModule,
  ],
})
export class AppModule {}
이제 문자열 대신 상수를 사용하여 서비스 간 통신의 일관성을 유지할 수 있습니다.
5. OrderService에서 Common Library 활용
import { USER_SERVICE } from '@app/common';
@Injectable()
export class OrderService {
  constructor(@Inject(USER_SERVICE) private readonly userServiceClient: ClientProxy) {}
  async getUserFromToken(token: string) {
    const resp = await lastValueFrom(
      this.userServiceClient.send({ cmd: 'parse_bearer_token' }, { token }),
    );
    return resp;
  }
}
OrderService는 USER_SERVICE 상수를 사용해 User Microservice와 TCP 통신합니다.
이를 통해 서비스 간 의존성을 줄이고 코드 일관성을 확보할 수 있습니다.
다음 단계에서는 이 공통 라이브러리에 DTO, 파이프, 데코레이터 등을 추가해 더 확장할 수 있습니다.













댓글 ( 0)  
댓글 남기기