미들웨어는 라우트 핸들러 이전에 호출되는 컴포넌트다. 라우트 핸들러란 엔드포인트마다 동작을 수행하는 컴포넌트를 뜻한다. 라우트 핸들러는 요청 경로와 컨트롤러를 매핑해 주고, 미들웨어는 이런 라우트 핸들러 이전에 실행된다.
미들웨어는 다음과 같은 동작을 할 수 있다.
요청-응답 생명주기를 끝낸다는 것은 (1) 응답을 보내거나 (2) 에러 처리를 하는 것을 뜻한다. 생명주기를 끝내지 않을 때에는 next() 호출로 다음 미들웨어에게 제어권을 주어야 한다.
미들웨어로 수행하는 작업들은 보통 다음과 같다.
$ nest g middleware 미들웨어명
일전에 모듈을 생성했던 것과 같은 방식으로 미들웨어를 생성할 수 있다. 생성한 미들웨어의 기본 코드 기반으로 logger를 구현해 봤다.
import { Injectable, Logger, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
private logger = new Logger();
use(req: Request, res: Response, next: NextFunction) {
res.on('finish', () => {
this.logger.log(
`${req.ip} ${req.method} ${res.statusCode}`,
req.originalUrl,
);
});
next();
}
}
첫 번째 특징으로는 express에서 봤었던 use
와 next()
다. 실제로 Nest의 미들웨어는 기본적으로 express 미들웨어와 동일하다. Nest 역시 express의 미들웨어처럼 use를 이용해서 미들웨어를 사용할 수 있다.
두 번째 특징으로는 서비스단에서 봤었던 @Injectable()
가 미들웨어에서도 보인다는 점이다. 즉, 의존성 주입으로 모듈단에서 공급자로 취급되었던 서비스단처럼 미들웨어 역시 의존성 주입을 할 수 있다.
이렇게 생성된 미들웨어는 바로 사용할 수 없다. 공급자는 만들어졌으나, app.module
모듈에 보내 주어야(의존성 주입을 해 주어야) 실행할 수 있다. 다만 다른 공급자들처럼 @module()
데코레이터 내에 넣는 게 아니라 모듈 클래스의configure()
메서드를 통해 미들웨어를 설정한다. 공식 홈페이지에서 제공하는 코드를 적용한 예는 다음과 같다.
import { CatsModule } from './cats/cats.module';
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggerMiddleware } from './logger.middleware';
@Module({
imports: [CatsModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes('cats');
}
}
LoggerMiddleware
는 위 코드에서 볼 수 있듯이 의존성 주입이 가능한 제공자(provider)다. 그리고 consumer.apply(LoggerMiddleware)
는 말 그대로 consumer 소비자에게 LoggerMiddleware
를 제공해 준다는 뜻이다. NestModule
은 약속을 추가해 준 인터페이스를 의미한다.
forRoutes('cats')
은 cats
라우터에 바인딩을 해 주는 것이다. '*'
와일드카드를 넣으면 전체 경로를 뜻하게 된다. 이렇게 .forRoutes
뒤에 오는 경로로 들어오는 요청을 수행하면 logger.middleware
의 use 안의 내용이 실행되는 것을 확인할 수 있다.