Nestjs - 다른 모듈의 서비스에서 리포지토리, 서비스 사용하기

jonghyun.log·2022년 4월 20일
2

nestjs 개발

목록 보기
4/4
post-thumbnail

개발하다 보면 기존에 만들어 두었던 서비스를 가져와서 재사용해야할 때가 있다.

하지만 이때, 모듈을 통한 의존성주입을 잘해주지 못하면 의도치 않은 에러를 마주하게 될 수도 있다.
직접 한번 예제를 통해 어떤식으로 해야하는지 알아보자.

1. 다른 모듈의 서비스 주입하기

ReviewService 에서 review 생성을 할때 기존에 구현해둔 UserServiceGoodsService 를 재사용해서 User 정보와 Goods 정보를 가져와서 저장하고자 한다. (리뷰를 생성할때 리뷰를 작성한 유저 정보와 구매한 상품 정보를 불러와서 저장한다.)

@Injectable()
export class ReviewService {
  constructor(
    @InjectRepository(ReviewRepository)
    private reviewRepository: ReviewRepository,
    private goodsService: GoodsService,
    private userService: UserService,
  ) {}
  async createReview(createReviewDto: CreateReviewDto) {
    const { goodsId, userId } = createReviewDto;
    const user = await this.userService.getUserInfo(userId);
    const goods = await this.goodsService.getGoodsById(goodsId);
    return this.reviewRepository.createReview(createReviewDto, goods, user);
  }
}

constructor 안의 부분이 리포지토리에 사용하고자 하는 서비스와 리포지토리를 의존성 주입해주는 부분이다.
그런데, 이렇게만 해서는 서비스와 리포지토리를 사용할 수가 없다.
Nest.js 는 모듈단위로 애플리케이션을 관리하기 때문에 모듈에서 따로 가져오고 내보내 주는 작업을 해주어야 하기 때문이다.

먼저 유저서비스상품서비스를 각각의 모듈에서 내보내주는 작업을 해주자.

//UserModule
@Module({
  imports: [
    TypeOrmModule.forFeature([UserRepository]),
  ],
  controllers: [UserController],
  providers: [UserService],
  exports: [UserService],
})
export class UserModule {}
//GoodsModule
@Module({
  imports: [TypeOrmModule.forFeature([GoodsRepository])],
  controllers: [GoodsController],
  providers: [GoodsService],
  exports: [GoodsService],
})
export class GoodsModule {}

Module에서 exports 배열을 통해 원하는 서비스를 내보내 줄 수 있다.

(여기서 UserServiceGoodsService 는 각각 UserRepositoryGoodsRepository 를 통해 디비에 데이터를 접근하고 있다.)

이제 내보내 주는 작업을 했으니 가져오는 작업을 해주자.

//ReviewModule
@Module({
  imports: [
    UserModule,
    GoodsModule,
    TypeOrmModule.forFeature([
      ReviewRepository,
    ]),
  ],
  controllers: [ReviewController],
  providers: [ReviewService, GoodsService, UserService],
})
export class ReviewModule {}

이제 직접 한번 리뷰를 생성하는 코드를 실행해보면 안타깝게도 에러가 나온다.
뭐가 문제일까? 바로 GoodsServiceUserService 에서 사용하는 레포지토리들도 내보내 주어야 하기 때문이다.

2. 다른 모듈의 레포지토리 주입하기

위의 모듈에서 내보내고 가져오는 작업에서 리포지토리를 내보내고 가져오는 작업을 추가해주도록 하자.

위의 코드에서 exportsTypeOrmModule 을 추가해주면 레포지토리 내보내는 작업이 완료된다.

//UserModule
@Module({
  imports: [
    EmailModule,
    AuthModule,
    TypeOrmModule.forFeature([UserRepository]),
  ],
  controllers: [UserController],
  providers: [UserService],
  exports: [UserService, TypeOrmModule],
})
export class UserModule {}
//GoodsModule
@Module({
  imports: [TypeOrmModule.forFeature([GoodsRepository])],
  controllers: [GoodsController],
  providers: [GoodsService],
  exports: [GoodsService,TypeOrmModule],
})
export class GoodsModule {}

이제 ReviewModule 에서도 가져오는 작업을 추가해주자
importsTypeOrmModule.forFeature 배열안에 리포지토리들을 추가하자.

//ReviewModule
@Module({
  imports: [
    UserModule,
    GoodsModule,
    TypeOrmModule.forFeature([
      ReviewRepository,
      UserRepository,
      GoodsRepository,
    ]),
  ],
  controllers: [ReviewController],
  providers: [ReviewService, GoodsService, UserService],
})
export class ReviewModule {}

이제 위의 과정처럼 다른 모듈에 있는 서비스와 레포지토리들을 주입해 재사용하면 된다.

참고한 링크

2개의 댓글

comment-user-thumbnail
2022년 8월 26일

안녕하세요 좋은글 남겨주셔서 감사합니다.
다름이 아니라 EntityMetadataNotFoundError: No metadata for "xxxrepository" was found.
라는 에러가 발생하는데 저의 짐작으로는 TypeOrmModuleOptions의 entites 쪽인거 같은데 리포지토리 클래스들을 넣어줘도 같은 에러가 발생하네요.다른 방안이나 해당 글의 코드 구현하셨을때의 설정 알려주신다면 감사하겠습니다!

1개의 답글