Middleware

middleware에 관하여 2강 참조

  • logging middleware
  • json middleware

뭐 이런걸 만들었음

이를 nest에서도 사용할 수 있다.

Middleware에 Dependency Injection

Middleware 만들기

cli를 통해 만든다.

nest g middleware logger
import { Injectable, NestMiddleware } from '@nestjs/common';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log(req.ip);
    next();
  }
}

그러면 위와 같이 생성이 되고 (ip를 찍을 수 있도록 코드 수정)

등록하려면 app.module.ts 파일에

export class AppModule{}

이였던 부분을

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes('cats');
  }
}

와 같이 수정한다.

forRoutes('*') 를 쓸 경우 모든 부분을 다 돌 수 있는 것이다.

이렇게하고 요청을 보내면

로거 미들웨어를 돌아서 ip를 찍어주는 것을 볼 수 있다.

logger 를 사용하기

this.logger.log(`${req.ip} ${req.method}`, req.originalUrl);

위를 사용하면 로깅을 사용할 수 있는 것임

Exception and Filter

아무 엔드포인트나 들어가면 404 코드가 뜸.

이걸 서비스에서 사용할 때, 페이지로 띄우고 싶다거나

아니면 어떤 요청에서 에러가 있다고 할 때

throw new HttpException('api is broken', 401);

이런 식으로 필터 걸어줄 수 있는 것이다.

공식문서의 http exception 을 가져온다.

https://docs.nestjs.com/exception-filters

import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
} from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}

위의 코드를 보면 response, request 를 둘다 가져온다. statusCode와 timeStamp를 찍어준다.

Filter를 적용하는 방법

  • decorator 방법

cats.controller.ts 파일에 아래와 같이 적용한다.

  @Get()
  @UseFilters(HttpExceptionFilter)
  getAllCat() {
    return 'all cat';
  }

그러면 그 결과 아래와 같은 로그가 찍히는 것을 확인할 수 있다.

{
    "success": false,
    "timestamp": "2022-12-18T11:22:26.312Z",
    "path": "/cats",
    "error": "api broken"
}

이거를 Class 위에다가도 쓸 수 있다.

@UseFilters(HttpExceptionFilter)
export class CatsController {
  constructor(private readonly catsService: CatsService) {}
  ...
}

위와 같이 사용

  • global로 등록하는 방법

main.ts 에다가 적용한다.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './http-exception.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new HttpExceptionFilter());
  await app.listen(8000);
}
bootstrap();

useGlobalFilters() 를 사용하면 된다.

결론 Middleware를 거치고 Controller를 거치고 Service를 거친 후 Filter까지 거친다는 것을 알면 된다.

Pipes

넘어오는 파라미터의 type을 변환해줌.

  @Get(':id')
  getOneCat(@Param('id', ParseIntPipe) param) {
    console.log(param);
    console.log(typeof param);
    return 'one cat';
  }

위와 같이 코딩하면 원래 id 값으로 넘어오는 param의 type은 string 이였는데 int로 바꿔서 받을수 있게 된다.

근데 만약에 int로 바꿀 수 없는 abc 뭐 이런게 들어 왔다면 알아서 validation error를 보내준다.