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를 구축할 때 유용하게 사용될 수 있습니다.
교차 모듈 주입의 이점
다른 모듈에서 서비스를 직접 호출하는 것은 처음에는 간단해 보일 수 있지만, 장기적으로는 시스템이 복잡해지고 유지보수 및 확장성이 떨어질 수 있습니다.
그러나 교차 모듈 주입은 코드 모듈성과 재사용성을 높여 유지보수를 더욱 용이하게 만듭니다. 또한 의존성을 중앙 집중화하고 테스트 가능성을 향상시키며 확장 가능하고 분리된 아키텍처를 지원합니다.