nestjs
nestjs 공식문서를 부분적으로 정리한 내용입니다.
미들웨어는 라우트 핸들러가 실행되기 전에 실행되는 함수이다. 미들웨어는 요청과 응답 객체에 접근할 수 있으며 next()
로 미들웨어를 호출한다.
네스트 미들웨어는 기본적으로 익스프레스 미들웨어와 동일하다. 다음은 익스프레스 공식문서에 작성된 미들웨어에 대한 설명이다.
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('LoggerMiddleware is working now');
next();
}
}
@Injectable()
데코레이터를 사용한다. NestMiddleware
인터페이스를 implement해야한다.constructor
를 통해 설정할 수 있다.생성한 미들웨어를 적용해보자. @Module에서 미들웨어를 불러올때는 모듈 클래스의 configure()
메소드를 사용한다. 미들웨어를 사용하는 모듈은 NestModule
을 implement해야한다. 다음은 LoggerMidleware를 AppModule 레벨에 적용한 예시이다.
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');
}
}
//만약 특정 메소드에 대해서만 미들웨어를 실행시키고 싶은 경우
.forRoutes({ path: 'cats', method: RequestMethod.GET });
/cats
라우트 핸들러에 적용했다. 따라서 /cats
로 들어오는 모든 요청에 대해서는 LoggerMiddleware가 실행될 것이다.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);
}
}
위의 예시에 configure 메소드 내에 consumer의 타입이 MiddlewareConsumer로 지정되어있다. 이는 helper class로 미들웨어를 다루기 위한 내장 메소드를 제공한다. 위에서 작성된대로 fluent style로 체이닝할 수 있다.
forRoutes 메소드 인자로는 string, multiple strings, a RouteInfo Object, a controller class, multiple controller classes 등이 올 수 있다. 일반적으로는, 여러개의 controller들을 쉼표로 이어 작성할 것이다.
apply 메소드는 하나의 미들웨어를 입력받거나 여러개를 입력받을 수 있다.
consumer.apply(cors(), helmet(), logger).forRoutes(CatsController);
특정 라우트에 대해서 설정해줄 수 있는 것과 마찬가지로 exclude
메소드를 사용하여 특정 라우트를 제외시킬 수도 있다. exclude 메소드는 string, multiple strings, a RouteInfo Object 등을 인자로 받는다. 아래의 예시는 GET /cats, POST /cats, cats/.* 등에 대해서는 미들웨어가 실행되지 않는다.
consumer
.apply(LoggerMiddleware)
.exclude(
{ path: 'cats', method: RequestMethod.GET },
{ path: 'cats', method: RequestMethod.POST },
'cats/(.*)',
)
.forRoutes(CatsController);
앞선 예시들에서는 클래스로 미들웨어를 생성했는데, 함수로도 할 수 있다. 다음은 클래스 기반 미들웨어를 함수형태로 변경한 예시이다.
//logger.middleware.ts
import { Request, Response, NextFunction } from 'express';
export function logger(req: Request, res: Response, next: NextFunction) {
console.log(`Request...`);
next();
};
//app.module.ts
mport { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CatsController } from './cats/cats.controller';
import { CatsModule } from './cats/cats.module';
import { logger } from './common/middleware/logger.middleware';
@Module({
imports: [CatsModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(logger).forRoutes(CatsController); //apply 시키는 함수명만 변경됨
}
}
모든 라우트에서 실행되는 미들웨어를 만들고 싶다면, main.ts 파일에서 생성된 app에 대해 use()
를 사용하면 된다.
//main.ts
const app = await NestFactory.create(AppModule);
app.use(logger);
await app.listen(3000);
.forRoutes('*')
와 같이 작성해줄 수 있다.