NestJS 공식 사이트에 따르면 모듈은 @Module()
데코레이터가 주석으로 달린 클래스다. @Module()
데코레이터는 메타데이터를 제공하고, 이 메타데이터는 애플리케이션 구조를 구성하는 데 사용한다.
일반적으로 모듈은 조그만 클래스나 함수처럼 한 가지 일만 수행하는 소프트웨어 컴포넌트가 아니라, 여러 컴포넌트를 조합하여 작성한 좀 더 큰 작업을 수행하는 단위이다. 즉, 하나의 루트 모듈이 존재하고 이 루트 모듈은 다른 여러 개의 모듈들로 구성된다. 사진처럼 하나의 App Module, 루트 모듈로 향하는 형태이다.
이론적으로 루트 모듈 하나만 존재하는 것도 가능하지만 Nest는 기능별로 모듈을 나눠 사용하는 것을 더 추구한다. 모듈을 쪼개서 사용하는 이유는 여러 모듈에게 각자의 책임을 나누고 응집도를 높이기 위함이다.
import { CatsModule } from './cats/cats.module';
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';
@Module({
imports: [CatsModule, UsersModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
app.module.ts
파일(루트 모듈)을 보면 이렇게 여러 모듈이 import되어 있다. 그럼 이제 CatsModule
과 UsersModule
에서 export한 서비스들을 AppController
나 AppService
에서 사용할 수 있게 된다. 단, 해당 모듈들은 반드시 export된 상태여야 한다. export되어 있지 않다면 캡슐화로 인해 모듈의 공급자들(서비스)을 주입할 수 없게 된다.
$ nest g <schematic> <name> [options]
인수에는 다양한 Schematic이 올 수 있다. (참고: https://docs.nestjs.com/cli/usages) Schematic 중 하나가 module이다. $ nest g module 모듈명
으로 생성 가능하다. 모듈명에 제한은 없지만 공식 사이트에서는 복수형으로 짓고 있으니 복수형이 좀 더 좋은 선택(?)이 아닐까 생각해 본다.
명령어 사용을 하지 않고 하나하나 입력해서 모듈을 만들 수도 있지만, $ nest g module
CLI 방법으로 모듈을 생성하게 되면 app.module.ts
파일에 생성한 모듈이 자동으로 import된다.
모듈은 기본적으로 공급자를 캡슐화한다. 모듈에서 내보낸 공급자는 모듈의 공개 인터페이스 또는 API로 간주할 수 있다. 이 말은 곧 (1) 현재 모듈의 일부가 아니거나 (2) 가져온 모듈에서 export되지 않은 공급자는 주입할 수 없다.
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [],
// exports: [CatsService], 으로 변경해야 사용 가능
})
export class CatsModule {}
위의 코드는 cat.module.ts
파일의 모듈 코드이다. CatsService
가 공급자로 있지만 export가 되어 있지 않은 상태다. 이 경우 해당 공급자는 루트 모듈(app.module.ts
)에서 import 되었다 한들 사용이 불가능하다. 캡슐화가 되어 있기 때문에 접근할 수 없는 것이다. 모듈 사용을 위해서는 반드시 CatsService
를 export 해 주어야 한다.