Modules
모듈은 @Modules() 데코레이터로 주석을 단 클래스이다. 모듈 데코레이터는 Nest가 애플리케이션 구조를 구성하는데 사용하는 메타데이터를 제공한다.
각 애플리케이션에는 하나 이상의 모듈, 즉 루트 모듈이 있다. 루트 모듈은 Nest가 애플리케이션 그래프를 구축하는 데 사용하는 시작점이며, 모듈과 프로바이더 관계 및 종속성을 해결하는데 사용하는 내부 데이터 구조이다. 아주 작은 애플리케이션에는 이론적으로 루트 모듈만 있을 수 있지만, 일반적인 경우는 아니다. 컴포넌트를 구성하는 효과적인 방법으로 모듈을 강력히 권장한다. 대부분의 애플리케이션의 경우 여러개의 모듈을 사용하는 아키텍처를 사용하며, 각 모듈은 밀접하게 관련된 기능 집합을 캡슐화한다.
@Modules() 데코레이터는 모듈에 대한 정보가 기록된 단일 객체를 받는다.
providers | Nest 인젝터에 의해 인스턴스화되고 적어도 이 모듈 전체에서 공유될 수 있는 프로바이더 |
controllers | 인스턴스화 해야하는 해당 모듈에 정의된 컨트롤러 집합 |
imports | 해당 모듈에 필요한 프로바이더를 제공하는 import된모듈 목록 |
exports | 해당 모듈에서 제공하며, 이 모듈을 가져가는 다른 모듈에서 사용할 수 있어야 하는 프로바이더의 하위 집합. |
모듈은 기본적으로 프로바이더를 캡슐화한다. 즉 현재 모듈에 직접 포함되지 않거나 가져온 모듈에서 내보낸 프로바이더를 삽입할 수 없다. 또한 모듈에서 내보낸 공급자를 모듈의 공용 인터페이스 또는 API로 간주할 수 있다.
Feature modules
CatsController와 CatsService는 동일한 애플리케이션 도메인에 속한다. 서로 밀접하게 관련되어 있으므로 기능 모듈로 이동하는 것이 좋다. 기능 모듈은 특정 기능과 관련된 코드를 간단히 정리하여 코드를 체계적으로 유지하고 명확한 경계를 설정한다. 이는 특히 애플리케이션 또는 팀의 규모가 커짐에 따라 복잡성을 관리하고 SOLID 원칙에 따라 개발하는데 도움이 된다.
이를 시연하기 위해 CatsModule을 만들어보자.
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
위에서는 cats.module.ts 파일에 CatsModule을 정의하고 이 모듈과 관련된 모든 것을 cats 디렉토리로 옮겼다. 마지막으로 해야할 일은 이 모듈을 루트 모듈(app.module.ts파일에 정의된 AppModule)로 가져오는 것이다.
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}
이제 디렉토리 구조는 아래와 같다.
Shared modules
Nest에서 모듈은 기본적으로 싱글톤이므로 여러 모듈 간에 동일한 프로바이더의 인스턴스를 손쉽게 공유할 수 있다.
모든 모듈은 자동으로 공유 모듈이 된다. 일단 생성되면 모든 모듈에서 재사용할 수 있다. 여러 다른 모듈 간에 CatsService 인스턴스를 공유하고자 한다고 가정해보자. 이를 위해서는 먼저 아래 그림과 같이 모듈의 exports 배열에 CatsService 프로바이더를 추가하여 내보내야 한다.
// cats.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService]
})
export class CatsModule {}
이제 CatsModule을 Import 하는 모듈은 CatsService에 엑세스할 수 있으며, 이를 Import 하는 다른 모듈과도 동일한 인스턴스를 공유하게 된다.
Module re-exporting
위에서 보았듯이 모듈은 내부 프로바이더를 내보낼 수 있다. 또한 import한 모듈을 다시 export할수도 있다. 아래 예시는 CommonModule을 CoreModule에서 가져오고 다시 내보내서 이 모듈을 가져오는 다른 모듈에서 사용할 수 있도록 한다.
@Module({
imports: [CommonModule],
exports: [CommonModule],
})
export class CoreModule {}
Dependency injection
모듈 클래스는 환경 설정을 목적으로 프로바이더를 삽입할 수도 있다.
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {
constructor(private catsService: CatsService) {}
}
그러나 모듈 클래스 자체는 순환 종속성으로 인해 프로바이더로 주입할 수 없다. 관련된 내용은 FUNDAMENTALS의 Circular Dependency를 참고하라.
Global modules
모든 곳에서 동일한 모듈 세트를 가져와야 한다면 지루할 수 있다. Nest와 달리 Angular 프로바이더는 글로벌 범위에 등록된다. 한번 정의하면 어디서나 사용할 수 있다. 그러나 Nest는 모듈 범위 내에서 프로바이더를 캡슐화한다. 캡슐화 모듈을 먼저 가져오지 않으면 다른 곳에서 모듈의 프로바이더를 사용할 수 없다.
헬퍼, 데이터베이스 연결 등 모든 곳에서 즉시 사용할 수 있어야 하는 프로바이더 집합을 제공하려는 경우 @Global() 데코레이터를 사용하여 모듈을 전역으로 만들라.
import { Module, Global } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Global()
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService],
})
export class CatsModule {}
Global() 데코레이터는 모듈을 전역 범위로 만든다. 전역 모듈은 일반적으로 루트 또는 코어 모듈에 의해 한 번만 등록되어야 한다. 위의 예제에서 CatsService 프로바이더는 유비쿼터스이며, 이 서비스를 삽입하려는 모든 Import 배열에 CatsModule을 import할 필요가 없다.
Dynamic modules
Nest 모듈 시스템에는 동적 모듈이라는 강력한 기능이 포함되어 있다. 이 기능을 사용하면 프로바이더를 동적으로 등록하고 구성할 수 있는 사용자 지정 가능한 모듈을 쉽게 만들 수 있다. 이 장에서는 모듈에 대한 소개를 완료하기 위해 간략한 개요를 제공한다.
다음은 데이터베이스 모듈에 대한 동적 모듈 정의의 예시이다.
import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';
@Module({
providers: [Connection],
exports: [Connection],
})
export class DatabaseModule {
static forRoot(entities = [], options?): DynamicModule {
const providers = createDatabaseProviders(options, entities);
return {
module: DatabaseModule,
providers: providers,
exports: providers,
};
}
}
HINT
forRoot() 메서드는 동적 모듈을 동기식 또는 비동기식(프로미스)으로 반환할 수 있다.
DatabaseModule은 아래와 같이 imports 될 수 있다.
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';
@Module({
imports: [DatabaseModule.forRoot([User])],
})
export class AppModule {}
'NestJS' 카테고리의 다른 글
Providers (1) | 2024.04.17 |
---|---|
Controllers (0) | 2024.04.17 |
First steps (0) | 2024.04.17 |
Introduction (0) | 2024.04.17 |