[NestJS 공식문서 정독하기] Overview - Middleware

2022. 7. 1. 02:00Web/NestJS

반응형
🔗  https://docs.nestjs.com/middleware
 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com

Middleware

  • 미들웨어는 route 핸들러 전에 호출되는 함수임
  • 미들웨어 함수는 요청, 응답 객체에 접근할 수 있음
  • 요청/응답 사이클상의 다음 미들웨어 함수인 next() 함수에도 접근 가능
  • NestJS의 미들웨어는 기본적으로 express의 미들웨어와 동일함

Express 미들웨어에서 할 수 있는 것 (NestJS와 동일)

  • 코드 실행
  • 요청, 응답 객체 수정
  • 요청/응답 사이클 종료
  • 다음 미들웨어 호출

NestJS 미들웨어 구현 방법

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();
  }
}
  • 함수 또는 클래스로 구현할 수 있음
  • 클래스로 구현하면 @Injectable 데코레이터와 함께 NestMiddleware 인터페이스를 구현해야 함
  • DI 가능

미들웨어 적용

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');
  }
}
  • @Module() 데코레이터 내부에서는 설정 불가능
  • 따라서 모듈 클래스의 configure() 메소드로 설정함
  • 해당 메소드를 구현하기 위해 NestModule 인터페이스를 구현해야함
forRoutes({ path: 'cats', method: RequestMethod.GET });
  • 위와 같이 forRoutes 에서 경로 뿐만 아니라 요청 메소드도 설정할 수 있음
forRoutes({ path: 'ab*cd', method: RequestMethod.ALL });
  • 패턴 기반 설정도 가능함 (wildcard)
  • 위 패턴은 abcd, ab_cd, abecd 등과 매칭됨
  • fastify는 * wildcard를 더이상 지원하지 않아서 (.*), :splat* 와 같은 파라미터를 사용해야 함

Middleware consumer

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);
  }
}
  • MiddlewareConsumer 는 helper 클래스임
  • 메소드 체이닝으로 설정함
  • forRoutes() 메소드는 단순 문자열, 여러개의 문자열, RouteInfo 객체, Controller 클래스를 받을 수 있음
  • Controller 클래스는 하나 또는 여러개의 배열을 받을 수도 있음
  • apply() 메소드도 단일 혹은 여러개의 미들웨어를 받을 수 있음

경로 제외하기

consumer
  .apply(LoggerMiddleware)
  .exclude(
    { path: 'cats', method: RequestMethod.GET },
    { path: 'cats', method: RequestMethod.POST },
    'cats/(.*)',
  )
  .forRoutes(CatsController);
  • exclude() 메소드로 미들웨어가 적용되는 경로를 제외할 수 있음

함수형 미들웨어

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);

글로벌 미들웨어

const app = await NestFactory.create(AppModule);
app.use(logger);
await app.listen(3000);
  • 글로벌 미들웨어에서는 DI 컨테이너를 사용할 수 없음
  • 따라서 글로벌 미들웨어는 함수형 미들웨어를 사용할 수 있음
  • DI 컨테이너를 사용하기 위한 대안으로 클래스 미들웨어를 AppModule에 forRoutes('*') 로 설정할 수 있음
반응형