모듈이란 여러 컴포넌트를 조합하여 더 큰 작업을 수행할 수 있게 하는 단위를 말한다.
Nest 애플리케이션이 실행되기 위해서는 하나의 루트 모듈이 존재하고 이 루트 모듈은 다른 모듈들로 구성된다. 이를 통해 책임을 나누고 응집도를 높일 수 있다.
모듈을 어떻게 나눌 것인지는 명확한 기준은 없지만 유사한 기능끼리 모듈로 묶어서 설계하게 될 것이다.
모듈은 @Module 데커레이터를 사용한다. @Module 은 ModuleMetadata를 인수로 받으며 ModuleMetadata는 아래와 같이 정의된다.
export declare function Module(metadata: ModuleMetadata): ClassDecorator;
export interface ModuleMetadata {
imports?: Array<Type<any> | DynamicModule | Promise<DynamicModule> | ForwardReference>;
controllers?: Type<any>[];
providers?: Provider[];
exports?: Array<DynamicModule | Promise<DynamicModule> | string | symbol | Provider | ForwardReference | Abstract<any> | Function>;
}
가져온 모듈은 다시 내보내기가 가능하다. 예를 들어 AppModule이 CoreModule과 CommonModule의 기능이 모두 필요하다면 AppModule은 모두를 가지고 오는 것이 아니라 CoreModule만을 가져오고, CoreModule에서는 CommonModule을 내보내면 AppModule에서 CommonModule을 가지고 오지 않아도 사용할 수 있다.
@Module({
providers: [CommonService],
exports: [CommonService], // CommonService 제공
})
export class CommonModule {}
@Injectable()
export class CommonService {
hello(): string {
return 'Common Hello~';
}
}
@Module({
imports: [CommonModule],
exports: [CommonModule],
})
export class CoreModule {}
@Module({
imports: [CoreModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
@Controller()
export class AppController {
constructor(private readonly commonService: CommonService) {}
@Get('/common-hello')
getCommonHello(): string {
return this.commonService.hello();
}
}
Nest는 모듈 범위 내에서 프로바이더를 캡슐화한다. 따라서 어떤 모듈에 있는 프로바이더를 사용하려면 모듈을 먼저 import 해야한다.
하지만 헬퍼나 DB 연결 등의 전역적으로 쓸 수 있는 프로바이더가 필요한 경우 전역 모듈로 제공할 수 있다.
전역 모듈은 @Global 데커레이터를 선언한다. 전역 모듈은 루트 모듈이나 코어 모듈에서 한 번만 등록해야 한다.
@Global()
@Module({
providers: [CommonService],
exports: [CommonService],
})
export class CommonModule {}
만들고 있는 유저 서비스는 루트 모듈인 AppModule만 존재한다. 유저 관리 기능을 UserModule로, 이메일 기능은 EmailModule로 분리하는 작업을 진행하자.
UserModule을 아래 cli 를 통해 생성한다.
$ nest g mo Users
생성된 UserModule에 UserController와 UserService를 추가한다. EmailService를 사용하므로 함께 추가한다.
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { EmailService } from 'src/email/email.service';
@Module({
imports: [],
controllers: [UsersController],
providers: [UsersService, EmailService],
})
export class UsersModule {}
AppModule에 UserModule이 자동으로 import 되어 있고 AppModule에서 UsersController, UsersService, EmailService를 참조할 필요가 없으므로 제거한다.
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
@Module({
imports: [UsersModule],
controllers: [],
providers: [],
})
export class AppModule {}
이메일 모듈을 생성한다.
$ nest g mo Email
생성된 EmailModule에서 EmailService를 UserModule에서 사용할수 있도록 exports 해준다.
import { Module } from '@nestjs/common';
import { EmailService } from './email.service';
@Module({
providers: [EmailService],
exports: [EmailService],
})
export class EmailModule {}
UsersModule에서 EmailModule을 import해주고 EmailService는 삭제한다.
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { EmailModule } from 'src/email/email.module';
@Module({
imports: [EmailModule],
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}
본 포스트는 한용재 저자의 NestJS로 배우는 백엔드 프로그래밍을 기반으로 스터디하며 정리한 내용들입니다.