Backend/NestJS

NestJS Request Lifecycle (1) - Middleware

One-armed-boy 2022. 12. 22. 18:49

์ด์ „ ๊ธ€


๋ฏธ๋“ค์›จ์–ด ( in NestJS )

๋ฏธ๋“ค์›จ์–ด๋ž€ NestJS ์š”์ฒญ ์ƒ๋ช…์ฃผ๊ธฐ์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋“ค์–ด์˜ค๋Š” request๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ์ฒ˜๋ฆฌ๋˜๋Š” ํ•ธ๋“ค๋Ÿฌ์ด๋‹ค. 

Node.js์˜ Express๋ฅผ ๋‹ค๋ค„๋ณด์•˜๋‹ค๋ฉด ์ด๋ฏธ ์ต์ˆ™ํ•œ ๊ฐœ๋…์ธ๋ฐ, Express ๋ฏธ๋“ค์›จ์–ด์—์„œ๋Š” request, response ๊ฐ์ฒด์™€ ๋”๋ถˆ์–ด ๋‹ค์Œ ๋ฏธ๋“ค์›จ์–ด๋‚˜ ๋ผ์šฐํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” next() ํ•จ์ˆ˜๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค.

app.use((req,res,next)=>{
  console.log('Request is received...')
  next() // ์Šคํƒ ์ƒ์˜ ๋‹ค์Œ ๋ฏธ๋“ค์›จ์–ด๋กœ req,res ์ „๋‹ฌ
})

 

๋ฏธ๋“ค์›จ์–ด ์ž‘์„ฑ

NestJS๋„ ๊ธฐ๋ณธ์ ์œผ๋กœ Express๋ฅผ ๋ž˜ํ•‘ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ด๊ธฐ ๋•Œ๋ฌธ์— ์œ„์™€ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•œ๋‹ค. 

๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ ๋˜ํ•œ ์œ„์™€ ๋™์ผํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ(ํ•จ์ˆ˜ ๋ฏธ๋“ค์›จ์–ด), ์˜์กด์„ฑ์ด ํ•„์š”ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์— ์ฃผ์ž…๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด @Injectable() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ด์šฉํ•œ ํด๋ž˜์Šค์˜ use ๋ฉ”์„œ๋“œ์˜ ํ˜•ํƒœ๋กœ ์ž‘์„ฑ์ด ๋œ๋‹ค.(ํด๋ž˜์Šค ๋ฏธ๋“ค์›จ์–ด)

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

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

์ด ๋•Œ๋ฌธ์— ํ•จ์ˆ˜ ๋ฏธ๋“ค์›จ์–ด๋Š” ์˜์กด์„ฑ์ด ํ•„์š” ์—†๋Š” ๊ฐ„๋‹จํ•œ ๋™์ž‘์ผ ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋ฉฐ, ๋˜ ์‚ฌ์šฉ์ด ์ถ”์ฒœ๋œ๋‹ค. 

 

๋ฏธ๋“ค์›จ์–ด ์ ์šฉ

NestJS์—์„œ๋Š” ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํฌ๊ฒŒ 2๊ฐ€์ง€๊ฐ€ ์กด์žฌํ•œ๋‹ค.

1. ์ „์—ญ ๋ฒ”์œ„ ๋ฏธ๋“ค์›จ์–ด

ํ•ด๋‹น ๋ฐฉ์‹์€ ์š”์ฒญ์ด NestJS ์„œ๋ฒ„์— ๋“ค์–ด์™”์„ ๋•Œ ๊ฐ€์žฅ ๋จผ์ € ๊ฑฐ์น˜๋Š” ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐฉ๋ฒ•์€ ๋‹จ์ˆœํ•œ๋ฐ, ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“  ๋’ค NestJS์˜ ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์‹œ์ž‘์ (bootstrap() ํ•จ์ˆ˜)์— Express์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

// logger.middleware.ts
import { Request, Response, NextFunction } from 'express';

export const logger = (req:Request, res:Response, next:NextFunction) => {
  console.log('Request is received...');
  next();
};
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { logger } from './logger.middleware';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(logger);
  await app.listen(3000);
}
bootstrap();

์ „์—ญ ๋ฒ”์œ„ ๋ฏธ๋“ค์›จ์–ด๋Š” ์•ž์„œ ์–ธ๊ธ‰ํ•œ๋Œ€๋กœ ์š”์ฒญ ์ƒ๋ช…์ฃผ๊ธฐ์—์„œ ๊ฐ€์žฅ ์ „๋ฉด์— ์œ„์น˜ํ•˜๊ฒŒ ๋˜๋ฉฐ, ์ „์—ญ ๋ฒ”์œ„ ๋ฏธ๋“ค์›จ์–ด ๊ฐ„ ์ˆœ์„œ๋Š” ๋จผ์ € ๋จผ์ € ํ˜ธ์ถœ๋œ ์ˆœ์„œ์ด๋‹ค. 

์ด ๋•Œ ํ•ด๋‹น ๋ฐฉ์‹์œผ๋กœ ์ด์šฉ๋˜๋Š” ๋ฏธ๋“ค์›จ์–ด๋Š” ์˜์กด์„ฑ ์ฃผ์ž…์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ๋”ฐ๋ผ์„œ ํ•จ์ˆ˜ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์ฃผ๋กœ ์ด์šฉ๋œ๋‹ค. ๋งŒ์•ฝ ์˜์กด์„ฑ์ด ํ•„์š”ํ•œ ๋ฏธ๋“ค์›จ์–ด์˜ ์ „์—ญ ์„ค์ •์ด ํ•„์š”ํ•˜๋‹ค๋ฉด, ์•„๋ž˜์˜ ๋ชจ๋“ˆ ๋ฒ”์œ„ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ด์šฉํ•œ ์ „์—ญ ์„ค์ •์„ ๊ณ ๋ คํ•ด์•ผํ•œ๋‹ค.

2. ๋ชจ๋“ˆ ๋ฒ”์œ„ ๋ฏธ๋“ค์›จ์–ด

ํ•ด๋‹น ๋ฐฉ์‹์€ ์œ„์˜ ์ „์—ญ ๋ฒ”์œ„ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๊ฑฐ์นœ ๋’ค ์‹คํ–‰๋˜๋Š” ๋ฏธ๋“ค์›จ์–ด๋“ค์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ชจ๋“ˆ ๋ฒ”์œ„ ๋ฏธ๋“ค์›จ์–ด๋“ค์€ ์ตœ์ƒ์œ„ ๋ชจ๋“ˆ์— ๋ฐ”์ธ๋”ฉ๋œ ๋ฏธ๋“ค์›จ์–ด๋ถ€ํ„ฐ ์ž‘๋™ํ•˜๋ฉฐ, ๊ทธ ์ดํ›„์—๋Š” imports ๋ฐฐ์—ด์— ์ถ”๊ฐ€๋˜์–ด์žˆ๋Š” ์ˆœ์„œ๋Œ€๋กœ ๊ฐ ๋ชจ๋“ˆ์˜ ๋ฏธ๋“ค์›จ์–ด๋“ค์ด ์ž‘๋™ํ•œ๋‹ค. 

๋ชจ๋“ˆ ๋ฒ”์œ„์˜ ๋ฏธ๋“ค์›จ์–ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋“ฑ๋กํ•ด์ค€๋‹ค.

import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggerMiddleware } from './logger.middleware';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer:MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .exclude( // ๋ฏธ๋“ค์›จ์–ด ์ ์šฉ์„ ์ œ์™ธํ•  ๊ฒฝ๋กœ, ์—†๋‹ค๋ฉด exclude ๋ฉ”์„œ๋“œ ์ƒ๋žต ๊ฐ€๋Šฅ
        {path: 'test2', method: RequestMethod.ALL,},
      )
      .forRoutes( // ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ ์šฉํ•  ๊ฒฝ๋กœ
        {path: 'test', method: RequestMethod.GET,},
      );
  }
}

๋ชจ๋“ˆ ๋ฒ”์œ„์˜ ๋ฏธ๋“ค์›จ์–ด์—์„œ ์™€์ผ๋“œ์นด๋“œ ๋ฌธ์ž๋ฅผ ์ด์šฉํ•˜๋ฉด ์ „์—ญ ๋ฏธ๋“ค์›จ์–ด์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggerMiddleware } from './logger.middleware';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer:MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('*'); // ๋ชจ๋“  ๊ฒฝ๋กœ, ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด ๋ฏธ๋“ค์›จ์–ด ์ ์šฉ
  }
}

์ด๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ์ด ํ•„์š”ํ•œ ๋ฏธ๋“ค์›จ์–ด๋„ ์ „์—ญ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋ฏธ๋“ค์›จ์–ด vs ์ธํ„ฐ์…‰ํ„ฐ

๋ฏธ๋“ค์›จ์–ด์— ๋Œ€ํ•ด ์ •๋ฆฌ๋ฅผ ํ•˜๋‹ค๋ณด๋‹ˆ ์ดํ›„์— ๋‹ค๋ฃฐ 'NestJS์˜ ์ธํ„ฐ์…‰ํ„ฐ์™€ ๋ฌด์Šจ ์ฐจ์ด๊ฐ€ ์žˆ์ง€?' ๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

์ด์— ๋Œ€ํ•ด ์ข€ ์ฐพ์•„๋ณด๋‹ˆ, ์Šคํƒ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ์˜ ๋‹ค์Œ์˜ ๊ธ€์„ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

https://stackoverflow.com/questions/54863655/whats-the-difference-between-interceptor-vs-middleware-vs-filter-in-nest-js

 

What's the difference between Interceptor vs Middleware vs Filter in Nest.js?

What's the difference between an Interceptor, Filter and Middleware in Nest.js framework? When should one of them be used and favored over the other? Thanks

stackoverflow.com

์š”์•ฝํ•˜์ž๋ฉด,

  1. ์ธํ„ฐ์…‰ํ„ฐ๋Š” ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ „ํ›„๋กœ ์š”์ฒญ, ์‘๋‹ต์„ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.
  2. ๋ฏธ๋“ค์›จ์–ด๋Š” ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ „์—๋งŒ ๋‚˜ํƒ€๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ์š”์ฒญ, ์‘๋‹ต์˜ ์กฐ์ž‘์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ฐ˜ํ™˜๋œ ์‘๋‹ต์— ๋Œ€ํ•ด์„œ๋Š” ์กฐ์ž‘ํ•  ์ˆ˜ ์—†๋‹ค.

์ •๋„๊ฐ€ ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.