서버/Nest

NestJS Module

realtrynna 2022. 12. 12. 20:58

NestJS Module

특정한 기준(도메인)으로 쪼개진 코드 집합이며 @Module 데코레이터가 달린 클래스를 의미한다.

기능별로 코드를 모듈화(쪼개는) 하는 이유는 책임을 나누고 응집도를 높여 코드의 이해도와 유지 보수가 용이한 이점을 가져가기 위해서다.

 

하나의 애플리케이션은 하나 이상의 Root 모듈이 존재하고 Root 모듈 아래 여러 개의 하위 모듈로 구성된다.

모듈은 기본적으로 프로바이더를 캡슐화하며 현재 모듈에 속해있지 않거나 가져온 모듈에서 export 하지 않는 프로바이더는 주입할 수 없다.

 

Root Module
프로젝트 main.ts 진입 파일에서 NestFactory에 create 메서드 인수로 들어가는 모듈을 의미한다.

 

@Module 데코레이터는 다음 코드와 같은 ModuleMetadata 타입의 인수를 받는다.

  • imports
    해당 모듈에서 사용하기 위한 프로바이더를 가지고 있는 다른 모듈 즉 프로바이더를 노출하는 모듈
  • controllers
    해당 모듈 안에 정의되어 인스턴스화되어야 하는 컨트롤러의 집합
  • providers
    Injector가 인스턴스화시키고 해당 모듈 안에서 공유하는 프로바이더
  • exports
    해당 모듈에서 제공하는 프로바이더의 부분 집합 해당 모듈을 가져와 다른 모듈에서 사용할 수 있도록 노출할 프로바이더

 

export interface ModuleMetadata {
    /**
     * Optional list of imported modules that export the providers which are
     * required in this module.
     */
    imports?: Array<Type<any> | DynamicModule | Promise<DynamicModule> | ForwardReference>;
    /**
     * Optional list of controllers defined in this module which have to be
     * instantiated.
     */
    controllers?: Type<any>[];
    /**
     * Optional list of providers that will be instantiated by the Nest injector
     * and that may be shared at least across this module.
     */
    providers?: Provider[];
    /**
     * Optional list of the subset of providers that are provided by this module
     * and should be available in other modules which import this module.
     */
    exports?: Array<DynamicModule | Promise<DynamicModule> | string | symbol | Provider | ForwardReference | Abstract<any> | Function>;
}

 

Feature Modul

같은 도메인과 관련된 기능을 하는 코드를 체계적으로 유지하고 명확한 경계를 설정하는 모듈이다.

 

모듈은 독립적으로 개발되어 테스트 및 배포될 수 있어 재사용이 가능하다. 이로 인해 프로젝트 규모가 커질수록, 팀의 규모가 커질수록, SOLID 원칙을 지키는 데 도움이 된다.

 

import { Module } from '@nestjs/common';

import { UserController } from 'src/controllers';
import { UserService } from 'src/providers/user.service';

@Module({
    imports: [],
    controllers: [UserController],
    providers: [UserService],
    exports: [],
})
export class UserModule {}

 

Shared Module

Node 특성과 마찬가지로 Nest에서 모듈은 싱글톤이다. 이런 특성으로 여러 모듈 간 쉽게 공급자의 동일한 인스턴스 공유가 가능하고 모든 모듈은 생성되면 재사용이 가능하다. 

 

사용자 모듈에서 인증 서비스를 사용한다면 코드는 다음과 같다.

 

// auth.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AuthService {
    validateUser(): boolean {
        return true;
    }
}

// auth.module.ts
import { Module } from '@nestjs/common';

import { AuthService } from 'src/providers/auth.service';

@Module({
    imports: [],
    providers: [AuthService],
    exports: [AuthService],
})
export class AuthModule {}

// app.module.ts
import { Module } from '@nestjs/common';

import { UserModule } from 'src/modules';
import { AuthModule } from 'src/modules/auth.modules';

@Module({
    imports: [
        UserModule,
        AuthModule,
    ],
    controllers: [],
    providers: [],
})
export class AppModule {}
// user.service.ts
import { Injectable } from '@nestjs/common';

import { AuthService } from 'src/providers/auth.service';

@Injectable()
export class UserService {
    constructor(private readonly authService: AuthService) {}

    async validateUser() {
        return this.authService.validateUser();
    }
}

// user.controller.ts
import {
    Controller,
    Body,
    Query,
    Param,
    Get,
    Post,
    HttpCode,
} from '@nestjs/common';

import { UserService } from 'src/providers/user.service';

@Controller('user')
export class UserController {
    constructor(private readonly userService: UserService) {}

    @Get()
    async validateUser() {
        return this.userService.validateUser();
    }
}


// user.module.ts
import { Module } from '@nestjs/common';

import { UserController } from 'src/controllers';
import { UserService } from 'src/providers/user.service';
import { AuthService } from 'src/providers/auth.service';

@Module({
    imports: [],
    controllers: [UserController],
    providers: [UserService, AuthService],
    exports: [],
})
export class UserModule {}

 

Global Module

별도의 설정 없이 애플리케이션 전역에서 사용할 수 있으며 @Global 데코레이터로 등록한다. 글로벌 모듈은 Root 모듈 또는 코어 모듈에 의해 딱 한 번만 등록돼야 한다. 

 

프로바이더는 모듈 안에 속해있으므로 프로바이더를 전역 설정할 수 없다. 특정 프로바이더를 다른 모듈에서 사용하려면 특정 프로바이더가 속한 모듈을 먼저 가져와야 한다.

import { Module, Global } from '@nestjs/common';

@Global()
@Module({
    imports: [
        ConfigModule.forRoot({
            cache: true,
            validationSchema,
            load: [AppConfig, DbConfig],
            envFilePath:
                process.env.NODE_ENV === 'PRODUCTION'
                    ? path.resolve(__dirname, '../../.env')
                    : path.resolve(__dirname, '../../.env.dev'),
        }),
    ],
    providers: [EnvService],
    exports: [EnvService],
})
export class EnvModule {}

 

참고

https://docs.nestjs.com/modules
https://www.wisewiredbooks.com/nestjs/overview/05-modules.html
https://tristy.tistory.com/43

'서버 > Nest' 카테고리의 다른 글

NestJS Controller Versioning  (0) 2022.12.06
NestJS  (0) 2022.11.19