Modules
Module은 @Module()
데코레이터가 붙은 클래스이다.
@Module()
데코레이터는 Nest가 어플리케이션의 구조를 구성할때 사용하는 메타데이터를 붙여준다.
각 어플케이션은 최소 하나의 루트 모듈을 갖는다. 루트 모듈은 Nest가 모듈, 프로바이더의 관계, 의존성을
만들 때 사용하는 내부 자료구조인 어플리케이션 그래프를 만들 때 시작점으로 사용한다.
모듈은 구성 요소들을 체계화하는 효율적인 방법으로, 대부분의 어플리케이션 아키텍쳐에서는
서로 밀접한 관계에 있는 기능들을 하나의 모듈로 캡슐화 하게 된다.
@Module()
데코레이터는 모듈을 정의하는 속성들을 갖는 하나의 객체를 사용한다.
속성 | 설명 |
providers | Nest Injector에 의해 인스턴스가 만들어지고, 해당 모듈에 공유될 프로바이더들 |
controllers | 인스턴스가 만들어져야 하는, 해당 모듈에 정의된 컨트롤러들 |
imports | 임포트된 모듈들의 리스트. 이들은 해당 모듈에 필요한 프로바이더를 내보내는 모듈이어야 함. |
exports | providers의 부분집합이며, 다른 모듈에서 이 모듈을 임포트 했을 때 사용할 수 있도록 할 프로바이더들. 프로바이더 자체나 프로바이더의 토큰을 넣을 수 있음. |
모듈은 기본적으로 프로바이더들을 캡슐화 한다.
현재 모듈에 직접 속해 있지 않거나, 임포트 한 모듈에서 내보내지 않는 프로바이더는 주입이 불가능하다.
즉, 모듈에서 내보내진 프로바이더는 모듈의 공개 인터페이스나 API라고 볼 수 있다.
기능 모듈
CatController
와 CatsService
는 같은 어플리케이션 도메인에 속해 있다.
두 클래스는 서로 밀접한 관계에 있기에, 기능 모듈로 묶는 것이 좋다.
기능 모듈은 적절하게 코드를 조직하여 코드를 체계적으로 유지하고, 기능 간에 확실한 경계를 만들 수 있다.
// cats/cats.module.ts
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
)에 임포트 해야한다.
// app.module.ts
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}
현재 디렉토리 구조
src
├─ cats
│ ├─ dto
│ │ └─ create-cat.dto.ts
│ ├─ interfaces
│ │ └─ cat.interface.ts
│ ├─ cats.controller.ts
│ ├─ cats.module.ts
│ └─ cats.service.ts
├─ app.module.ts
└─ main.ts
공유 모듈
Nest에서 모듈들은 기본적으로 싱글톤이다.
여러 모듈에서 어떠한 프로바이더든 같은 인스턴스를 공유할 수 있다.
모든 모듈은 공유 모듈이다. 한번 생성되면, 어떠한 모듈에서 재사용할 수 있게 된다.
CatsService
의 인스턴스를 여러 다른 모듈에서 공유해야하는 상황이라면 CatsService
프로바이더를
모듈의 exports
배열에 추가하여 해당 프로바이더를 내보내야 한다.
// 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
을 임포트한 모듈은 모두 CatsService
에 접근할 수 있게 되며,
임포트한 모든 다른 모듈들은 같은 인스턴스를 공유하게 된다.
모듈 다시 내보내기
모듈은 자신이 갖고 있는 프로바이더를 내보낼 수 있으며, 자신이 임포트한 모듈을 다시 내보낼 수도 있다.
CommonModule
은 CoreModule
에서 임포트도 되고, 내보내지기도 한다.
이를 통해 다른 모듈에서 CoreModule
을 임포트하면 둘 다 사용할 수 있게 된다.
@Module({
imports: [CommonModule],
exports: [CommonModule],
})
export class CoreModule {}
의존성 주입
모듈 클래스는 프로바이더를 주입할 수도 있다.
// cats.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {
constructor(private catsService: CatsService) {}
}
그러나, 모듈 클래스 자체는 순환 의존성(Circular Dependency) 때문에 프로바이더로 주입될 수 없다.
전역 모듈
만약 어떤 모듈을 모든 곳에서 임포트 해야 한다면, @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
프로바이더는 어디서든 쓸 수 있게 되고, 해당 서비스를 주입 받고 싶어하는 모듈에서는
CatsMoudle
을 imports
배열에 넣을 필요가 없게 된다.
동적 모듈
Nest의 모듈 시스템은 동적 모듈이라는 강력한 기능이 있습니다.
기능을 통해 프로바이더를 동적으로 등록하고 설정할 수 있는, 커스텀 가능한 모듈을 쉽게 만들 수 있다.
import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';
@Module({
providers: [Connection],
})
export class DatabaseModule {
static forRoot(entities = [], options?): DynamicModule {
const providers = createDatabaseProviders(options, entities);
return {
module: DatabaseModule,
providers: providers,
exports: providers,
};
}
}
이 모듈은 @Module()
데코레이터를 통해 Connection
프로바이더를 기본적으로 정의한다.
forRoot()
매서드의 매개변수로 들어온 entities
와 option
객체에 따라 저장소(Repository) 등의 어떤
프로바이더들을 노출하게 된다.
동적 모듈을 통해 반환된 속성들은 @Module()
데코레이터에 정의된 기본 모듈 메타데이터를 확장한다.
이렇게 하면, 정적으로 정의된 Connection
프로바이더와 동적으로
생성된 저장소 프로바이더 둘 다 모듈에서 내보내지게 된다.
// 만약 동적 모듈을 전역 스코프에 등록하고 싶다면, global 속성을 true로 주면 된다.
{
global: true,
module: DatabaseModule,
providers: providers,
exports: providers,
}
DatabaseModule
은 아래와 같이 임포트, 설정할 수 있다
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 {}
만약 동적 모듈을 다시 내보내고 싶다면, exports
배열에서 forRoot()
호출을 제외할 수 있다.
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';
@Module({
imports: [DatabaseModule.forRoot([User])],
exports: [DatabaseModule],
})
export class AppModule {}
'프레임워크 및 라이브러리 > Nest.js' 카테고리의 다른 글
[Nest.js] Exception filters (0) | 2024.04.16 |
---|---|
[Nest.js] Providers (0) | 2024.04.14 |
[Nest.js] Controllers (0) | 2024.04.12 |
[Nest.js] Nest.js 개념 (0) | 2024.04.05 |