HJW's IT Blog

NestJS Document 알아보기 : Middleware 본문

NestJS

NestJS Document 알아보기 : Middleware

kiki1875 2024. 10. 20. 14:21

MiddleWare

NestJS 에서 미들웨어는 라우트 핸들러가 호출되기 전, 실행되는 함수로, Req, Res 객체에 접근이 가능하며, next() 메서드로 다음 미들웨어에 제어를 넘길 수 있다.

NestJS에서 미들웨어는 @Injectable() 이 붙은 클래스로 구현이 가능하다. 미들웨어 클래스는 NestMiddleware 를 implement 해야 한다. 아래는 간단한 미들웨어 클래스의 예시이다

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
    use(req: Request, res: Response, next: NextFunction){
        console.log('Request..');
        next();
    }
}

 


 

Applying Middleware

미들웨어는 @Module() 에 정의되지 않으며, 모듈 클래스의 configure() 메서드에서 설정된다.

아래는 위에서 구현한 LoggerMiddleware를 AppModule 레벨에서 설정하는 예시이다.

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
    imports: [CatsModule],
})
export class AppModule implements NestModule {
    configure(consumer: MiddlewareConsumer{
        consumer
            .apply(LoggerMiddleware)
            .forRoutes('cats');
    }
}

해당 예시에서 LoggerMiddleware/cats 경로에만 적용된다. 만약 이에 더불어 특정 HTTP 메소드에만 적용하고 싶다면, forRoutes() 메서드에 추가 옵션을 지정할 수 있다

.forRoutes({path: 'cats', method: RequestMethod.GET})

MiddlewareConsumer 클래스

MiddlewareConsumer 는 미들웨어를 관리하는 여러 메서드를 제공하는 헬퍼 클래스이다. 이 클래스의 메서드는 체인형식으로 연결하여 사용이 가능하다.

forRoutes() 메서드는 여러 문자열, RoutesInfo 객체, 컨트롤러 클래스 등을 인수로 받을 수 있으며, 다수의 컨트롤러를 쉼표로 구분하여 넘길 수 있다.

다음은 하나의 컨트롤러에 대해 LoggerMiddleware 를 적용하는 예시이다

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';
import { CatsController } from './cats/cats.controller';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes(CatsController);
  }
}

특정 경로를 제외할 수도 있는데,

consumer
    .apply(LoggerMiddleware)
    .exclude(
        { path: 'cats', method: RequestMethod.GET },
        { path: 'cats', method: RequestMethod.POST},
        'cats/(.*),
    )
    .forRoutes(CatsController);

해당 예시에서는 LoggerMiddleware 가 CatsController의 모든 경로에 적용되지만, Get , Post 메서드로 /cats 에 접근하는 요청은 제외된다.

 


Functional Middleware

단순한 미들웨어의 경우, 클래스로 정의하지 않고 함수로 정의할 수도 있다. 이를 함수형 미들웨어라고 하며, 클래스 기반 미들웨어보다 간단하게 작성이 가능하다.

import { Request, Response, NextFunction } from 'express'

export function logger(req: Request, res: Response, next: NextFunction){
    console.log('Request...');
    next();
}

// 적용시키기
consumer
    .apply(logger)
    .forRoutes(CatsController);

여러 미들웨어를 적용시키고 싶다면, 미들웨어 사이를 , 로 구분하면 된다

consumer
    .apply(cors(), helmet(), logger)
    .forRoutes(CatsController);

모든 경로에 대해 한 번에 미들웨어를 설정하고 싶을 경우, INestApplication 인스턴스에서 제공하는 use() 메서드를 사용하면 된다

const app = await NestFactory.create(AppModule);
app.use(logger);
await app.listen(process.env.PORT ?? 3000);

//혹은 모듈내에서 forRoutes('*')