Root 핸들러 앞에 호출되는 함수. req,res 객체에 접근 가능하고, next() 미들웨어 함수가 request-response cycle 안에 포함된다
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 으로 이루어진다.
@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라는 패키지를 사용한다.
아무것도 의존하지 않는 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("*")같은 방식을 통해서 어떤 모듈에서든 사용할 수 있다.