다른 모듈에서 Nest.js 서비스 주입

Nest.js 프레임워크에서 다른 모듈에 정의된 서비스를 사용하려면, 의존성 주입(Dependency Injection)과 모듈 설정을 올바르게 구성해야 합니다. 이 글에서는 두 개의 모듈을 예시로 사용하여 서비스 내보내기와 가져오기 과정을 상세히 설명합니다.

Nest.js 프로젝트 생성

Nest.js 프로젝트를 시작하려면 먼저 시스템에 Nest.js CLI(명령 줄 인터페이스)가 설치되어 있어야 합니다. 설치되어 있지 않다면, 다음 명령어를 사용하여 설치하십시오.

npm install -g @nestjs/cli

CLI가 설치된 후에는 아래 명령어를 통해 새로운 Nest.js 프로젝트를 생성할 수 있습니다.

nest new <project-name>

<project-name> 부분을 원하는 프로젝트 이름으로 변경하면 됩니다. 이 명령어를 실행하면, 지정한 이름의 새 Nest.js 프로젝트가 생성됩니다.

생성된 프로젝트의 기본 구조는 다음과 같습니다.

다른 모듈에서 서비스 주입을 연습하기 위해, ‘module-a’와 ‘module-b’라는 두 개의 모듈을 생성하고 각 모듈에 해당하는 서비스와 컨트롤러 파일도 만들겠습니다.

‘module-a’를 생성하려면 아래 명령어를 실행하십시오.

nest generate module module-a

그리고 ‘module-b’는 다음 명령어로 생성합니다.

nest generate module module-b

이제 ‘module-a’에 서비스와 컨트롤러 파일을 추가합니다.

nest generate service module-a && nest generate controller module-a

마찬가지로 ‘module-b’에도 서비스와 컨트롤러 파일을 생성합니다.

nest generate service module-b && nest generate controller module-b

현재 프로젝트 구조는 ‘src/module-a’ 및 ‘src/module-b’ 디렉터리를 포함하여 아래 이미지와 유사해야 합니다.

모듈 A에서 서비스 내보내기

‘module-a’에서 서비스를 내보내려면, ‘module-a’의 모듈 파일(module-a.module.ts)에서 해당 서비스를 exports 배열에 명시해야 합니다. Nest.js CLI는 기본적으로 @Module 데코레이터에 exports 배열을 제공하지 않으므로, 생성된 모듈 파일은 다음과 같습니다.

import { Module } from '@nestjs/common';
import { ModuleAService } from './module-a.service';
import { ModuleAController } from './module-a.controller';

@Module({
  providers: [ModuleAService],
  controllers: [ModuleAController],
})
export class ModuleAModule {}

‘module-a’를 가져오는 모듈에서 ‘module-a.service.ts’에 접근할 수 있도록, @Module 데코레이터에 exports 배열을 생성하고 ‘ModuleAService’를 추가합니다.

수정된 코드는 다음과 같습니다.

import { Module } from '@nestjs/common';
import { ModuleAService } from './module-a.service';
import { ModuleAController } from './module-a.controller';

@Module({
  providers: [ModuleAService],
  controllers: [ModuleAController],
  exports: [ModuleAService],
})
export class ModuleAModule {}

다음으로, 테스트를 위해 ‘module-a.service.ts’ 파일에 간단한 함수를 추가합니다.

import { Injectable } from '@nestjs/common';

@Injectable()
export class ModuleAService {
  getHello(): string {
    return '안녕하세요, 모듈 A에서 왔습니다!';
  }
}

이 함수는 간단한 문자열을 반환합니다. 이제 ‘module-b’에서 이 서비스를 가져와 해당 함수를 호출함으로써 서비스가 올바르게 주입되었는지 확인합니다.

서비스를 모듈 B로 가져오기

한 모듈을 다른 모듈로 가져오려면, 해당 모듈을 받는 모듈의 imports 배열에 추가해야 합니다. 이 경우, ‘module-b’의 @Module 데코레이터 imports 배열에 ‘module-a’를 추가해야 합니다.

Nest.js CLI는 imports 배열을 자동으로 생성하지 않으므로, 직접 추가해야 합니다.

먼저, ‘module-a.module.ts’를 ‘module-b.module.ts’로 가져오고 imports 배열을 생성한 후 ‘ModuleAModule’을 배열에 추가합니다.

import { Module } from '@nestjs/common';
import { ModuleBController } from './module-b.controller';
import { ModuleBService } from './module-b.service';
import { ModuleAModule } from '../module-a/module-a.module';

@Module({
  imports: [ModuleAModule],
  controllers: [ModuleBController],
  providers: [ModuleBService],
})
export class ModuleBModule {}

다음으로 ‘module-b.service.ts’ 파일을 열고, ‘@nestjs/common’과 ‘../module-a/module-a.service’에서 Inject 데코레이터와 ‘ModuleAService’를 가져옵니다.

import { Injectable, Inject } from '@nestjs/common';
import { ModuleAService } from '../module-a/module-a.service';

Inject 데코레이터는 매개변수를 의존성 주입 대상으로 지정합니다.

이제 ‘ModuleBService’ 클래스에 다음 코드 블록을 추가합니다.

@Inject(ModuleAService)
private readonly moduleAService: ModuleAService;

위 코드는 ‘ModuleAService’에서 사용 가능한 메서드에 대한 ‘ModuleBService’ 접근 권한을 부여합니다.

‘ModuleAService’의 ‘getHello’ 메서드를 호출하여 서비스를 테스트할 수 있습니다.

import { Injectable, Inject } from '@nestjs/common';
import { ModuleAService } from 'src/module-a/module-a.service';

@Injectable()
export class ModuleBService {
  @Inject(ModuleAService)
  private readonly moduleAService: ModuleAService;

  getHello(): string {
    return this.moduleAService.getHello();
  }
}

다음으로, ‘module-b.controller.ts’ 파일을 열고, 생성된 코드를 아래 코드로 교체합니다.

import { Controller, Get } from '@nestjs/common';
import { ModuleBService } from './module-b.service';

@Controller('module-b')
export class ModuleBController {
  constructor(private readonly moduleBService: ModuleBService) {}

  @Get('/hello')
  getHello(): string {
    return this.moduleBService.getHello();
  }
}

위 코드는 ‘getHello’ 함수에 대한 GET 경로 핸들러를 설정합니다.

마지막으로, curl을 사용하여 ‘localhost:3000/module-b/hello’에 대한 GET 요청을 보내면 콘솔에 “안녕하세요, 모듈 A에서 왔습니다!”라는 메시지가 출력될 것입니다.

성공적으로 다른 모듈에 서비스를 주입했습니다. 이는 여러 모듈이 서로의 메서드를 호출해야 하는 Nest.js API를 구축할 때 유용하게 사용될 수 있습니다.

교차 모듈 주입의 이점

다른 모듈에서 서비스를 직접 호출하는 것은 처음에는 간단해 보일 수 있지만, 장기적으로는 시스템이 복잡해지고 유지보수 및 확장성이 떨어질 수 있습니다.

그러나 교차 모듈 주입은 코드 모듈성과 재사용성을 높여 유지보수를 더욱 용이하게 만듭니다. 또한 의존성을 중앙 집중화하고 테스트 가능성을 향상시키며 확장 가능하고 분리된 아키텍처를 지원합니다.