Nodejs

 

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, 파이프, 데코레이터 등을 추가해 더 확장할 수 있습니다.

 

 

 

 

 

about author

PHRASE

Level 60  라이트

의식(衣食)이 족해야 영욕(榮辱)을 안다. -관자

댓글 ( 0)

댓글 남기기

작성