Middleware
Middleware는 라우트 핸들러가 실행되기 전에 호출되는 함수이다.Express의 미들웨어와 기본적으로 동일하며, 요청(Request) 및 응답(Response) 객체와 애플리케이션의 요청-응답 주기에서 그 다음의 미들웨어 함수(next()) 접근할 수 있다.
Middleware 구현
NestJS에서Middleware는 두 가지 방식으로 구현할 수 있다.클래스(Class) 기반 미들웨어
@Injectable()데코레이터가 적용된 클래스로 구현하며 이 클래스는 NestMiddleware 인터페이스를 구현해야 한다.
// logger.middleware.ts import { Injectable, NestMiddleware} from '@nestjs/common' import { Request, Response, NestFunction } from 'express' @Injectable() export class LoggerMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { // 수행 내용 next(); } }함수(Functional) 기반 미들웨어
- 특별한 요구사항 없이 간단한 함수로 구현 가능하며, 의존성 주입이 필요 없는 간단한 미들웨어에 적합하다.
// logger.middleware.ts import { Request, Response, NestFunction } from 'express' export function logger(req: Request, res: Response, next: NextFunction){ // 수행 내용 next(); }
Middleware 적용
Middleware는@Module()데코레이터에서 설정하는 것이 아니라, 모듈 클래스의configure()메서드를 사용하여 설정한다. 미들웨어를 포함하는 모듈은NestModule인터페이스를 구현해야 한다.MiddlewareConsumer는 미들웨어 관리를 돕는 헬퍼 클래스이며,apply()와forRoutes()같은 메서드를 제공한다.
// app.module.ts
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); // 특정 컨트롤러의 모든 라우트에 적용
}
}Middleware 조건부 적용
특정 라우트 적용
forRoutes()메서드에 문자열로 된 경로를 전달하여 특정 라우트에만 미들웨어를 적용할 수 있다. 특정 HTTP 요청 메서드에만 적용할려면 경로와 메서드를 포함한 객체를 전달한다.
consumer
.apply(LoggerMiddleware)
.forRoutes({ path: 'cats', method: RequestMethod.GET }) // 'cats' 경로의 GET 요청에만 적용라우트 와일드 카드
- 경로에 와일드 카드(
*)를 사용하여 패턴 기반으로 라우트를 지정할 수 있다.
forRoutes({ path: 'ab*cd', method: RequestMethod.ALL })특정 라우트 제외
exclude()메서드를 사용하면 특정 라우트를 미들웨어 적용 대상에서 제외할 수 있다.
consumer
.apply(LoggerMiddleware)
.exclude(
{ path: 'cats', method: RequestMethod.GET }, // 'cats' 경로의 GET 요청 제외
{ path: 'cats', method: RequestMethod.POST }, // 'cats' 경로의 POST 요청 제외
)
.forRoutes(CatsController); // CatsController의 나머지 라우트에 적용여러 미들웨어 적용
apply()메서드에 여러 미들웨어를 쉼표로 구분하여 전달하면 순차적으로 실행되는 여러 미들웨어를 바인딩 할 수 있다.
consumer
.apply(cors(), helmet(), logger)
.forRoutes(CatController);전역 (Global) 미들웨어
- 애플리케이션의 모든 라우트에 미들웨어를 한 번에 적용하려면
main.ts파일에서INestApplication인스턴스의use()메서드를 사용한다.
// main.ts
const app = await NestFactory.create(AppModule);
app.use(logger) // 'logger' 미들웨어를 전역으로 적용
await app.listen(3000)- 이 방식으로는 의존성 주입(DI) 컨테이너에 접근할 수 없어, DI가 필요한 경우, 모듈 내에서
consumer.apply(MyMiddleware).forRoutes('*')와 같이 모든 라우트에 적용하는 방식을 사용해야 한다.
의존성 주입 (Dependency Injection)
- 클래스 기반 미들웨어는
NestJS의 다른 구성요소(Provider,Controller)와 마찬가지로 의존성 주입을 완벽하게 지원한다. 생성자를 통해 같은 모듈 내에서 사용가능한 의존성을 주입 받을 수 있다.