Nest 공식문서 Middleware

송은우·2022년 3월 25일
0

Middleware

Root 핸들러 앞에 호출되는 함수. req,res 객체에 접근 가능하고, next() 미들웨어 함수가 request-response cycle 안에 포함된다
Nest 공식문서 Middleware 이미지

Nest middleware는 express와 동일한 효과를 갖고 있다.
1. execute any code
2. make changes to the request and response object
3. end the request-response cycle.
4. call the next middleware function in the stack
5. 이 middleware가 끝이 아니라면 next()를 호출해야 한다. 아니라면 그냥 대기상태에 빠짐

Middleware는 NestMiddleware 를 implement 하고있는 class나, 아무 제약이 없는 function 으로 이루어진다.

class형 middleware

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

대표적인 클래스 middleare의 예시가 된다
constructor를 통해서 DI를 이용할 수 있다.
Module() 데코레이터에서는 미들웨어를 쓸 수 없는데,
모듈이 NestModule를 implements하고있다면 confirue에서 middleware를 적용할 수 있다.

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',method: RequestMethod.GET);
  }
}

같은 방식으로 특정 경로에 특정 메서드에만 설정할 수도 있고, 생략한다면 모든 매서드에, 모든 경로에 다 적용할 수도 있다. 당연히 wildcard를 지원하고, ?+*()가 정규 표현식으로 작용된다
configure() 메서드는 async,await을 지원한다.

Fastify는 를 사용하지 못 한다. (.,:splat*)를 사용하는 방식으로 처리할 수 있다.

MiddlewareConsumer는 헬퍼 클래스이고, fluent style(메서드 체이닝 consumer.apply().forRoute.)같은 방식으로 구현된다

여기서 forRoute에는 되게 다양한 것들이 들어갈 수 있다.
하나의 문자열, 여러 문자열, RouteInfo객체, 컨트롤러 클래스, 여러 컨트롤러 클래스 ,로만 구분해주면 다 넣을 수 있다.

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

apply()역시 , 로 구분하면 여러개의 middleware를 적용할 수 있다.

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

같은 방식으로 특정 경로를 제외할 수 있다.
여기서 경로는 wildcard를 구분할 때 path-to-regexp라는 패키지를 사용한다.

function 형 middleware

아무것도 의존하지 않는 middleware의 경우 그냥 function형으로 만드는 것이 훨씬 간단하다

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

export function logger(req: Request, res: Response, next: NextFunction) {
  console.log(`Request...`);
  next();
};
consumer
  .apply(logger)
  .forRoutes(CatsController);

Global middlware
Global middleware는 라우터에 딱 1번만 적용되는 전역 미들웨어로

const app = await NestFactory.create(AppModule);
app.use(logger);
await app.listen(3000);

INestApplication instance에다가 app.use를 이용해서 적용할 수 있다.
단 DI 컨테이너에 접근할 수 없기에 functional middleware를 써서 그냥 아무것도 없이 쓰거나, class Middleware로 forRoute("*")같은 방식을 통해서 어떤 모듈에서든 사용할 수 있다.

profile
학생의 마음가짐으로 최선을 다하자

0개의 댓글