Nest.JS (3) 미들웨어와 Exception filters,Pipes,interceptor

Seong·2022년 11월 16일
0

Nest.js

목록 보기
3/9
post-thumbnail

미들웨어

Nest 미들웨어는 기본적으로 express 미들웨어와 동일하다.

미들웨어 기능은 다음 작업을 수행할 수 있습니다.
모든 코드를 실행합니다.
요청 및 응답 객체를 변경합니다.
요청-응답 주기를 종료합니다.
스택에서 다음 미들웨어 함수를 호출합니다.
현재 미들웨어 기능이 요청-응답 주기를 종료하지 않으면 next()다음 미들웨어 기능으로 제어를 전달하도록 호출해야 합니다. 그렇지 않으면 요청이 중단됩니다.

미들웨어 생성

nest g mi 미들웨어 명 

처음 미들웨어를 생성했을때 req,res,next가 any로 되어있으니 직접 수정해주고 미들웨어를 만들어주자.

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  private logger = new Logger('HTTP') //nest.js에서는 Logger를 기본적으로 지원해준다.

  use(req: Request, res: Response, next: NextFunction) {
    this.logger.log(req.ip,req.originalUrl)
    next();
  }
}

그후 의존성 주입을해야하는데 @module 데코레이터로는 미들웨어 의존성주입을 하지 못한다.

공식문서에 모듈 클래스의 configure() 메소드를 이용하라고 적혀있다.

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

Exception filters

필터 만들기

Nest에서 에러처리하는건 httpException()임
Filters파일을 만들어서 원하는 형식으로 반환시킬 수 있음

http-exception.filter.ts

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

@Catch(HttpException) //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(); //httpException의 stats받기
    const err = exception.getResponse(); //httpException의 인자 받기

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

필터를 적용시키는 방법은 각 코드마다 적용시키는 방법과 전역에 적용시키는 방법이 있음

@UseFilters()

@useFilters(필터명) 을적용시키면된다. 클래스,메소드 둘다 됨

  @Get('errorTest')
  @UseFilters(HttpExceptionFilter)
  errTest(){
    throw new HttpException('고의적 에러',401);
  }

UseGlobalFilters()

main.ts에 app.useGlobalFilters(new 필터명)을 사용하면 전역에서 예외 처리가 된다

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

Pipes

파이프란? 클라이언트 요청에서 들어오는 데이터를 유효성 검사 및 변환을 수행하여 서버가 원하는 데이터를 얻을 수 있도록 도와주는 클래스입니다.

Pipes는 변환과 유효성 체크가 있다.

Handler-level-pipes

Controller의 핸들러 레벨에서 @usePipes를 사용해 사용할 수 있다.

  @Get(':id')
  @UsePipes(pipe)
  getBoardById(@Param('id') id: string) {
    return this.boardService.getBoardById(id);
  }

Parameter-level-pipes

핸들러보다 더 좁은개념, 핸들러 전체가아니라 파라미터 하나에만 적용

@Get(':id')
findOne(@Param('id',ParseIntPipe) id:number){
  console.log(typeof id)  
  return `${id}`;
}

Global Pipes

전역으로 관리하고 싶으면 main.ts에 Pipe를 넣으면된다

  app.useGlobalPipes(new ValidationPipe())

커스텀 파이프 만들기

모든파이프에선 PipeTransform라는 인터페이스를 구현해야한다.
모든파이프에는 tranform 메소드가 필요하다

  • tranform 메소드에서 return된 값은 Route Handler로 전달된다.

    
     readonly StatusOptions =[
       BoardStatus.PRIVATE,
       BoardStatus.PUBLIC
     ]
     transform(value: any, metadata: ArgumentMetadata) {
       value=value.toUpperCase();
       if(!this.isStatusValid(value)){
         throw new BadRequestException(`${value} is not Status`)
       }
       return value
     }
    
     private isStatusValid(status:any){
       const index = this.StatusOptions.indexOf(status);
       return index !== -1;
     }

    이 경우 매개변수가 PRIVATE 또는 PUBLIC이 아닐경우 에러처리를 한다.

Interceptor

컨트롤러를 불러오기전에 한번호출, 완료후 한번 더 호출 하는과정이다.

import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class UndifinedToNullInterceprtor implements NestInterceptor {
  intercept(
    context: ExecutionContext,
    next: CallHandler<any>,
  ): Observable<any> | Promise<Observable<any>> {
    console.log('before...');
    //전부분
    return next
      .handle()
      .pipe(map((data) => (data === undefined ? null : data))); //후부분
  }
}

마찬가지로 @useInterceptors로 장착하거나 main.ts에서 global로 사용할 수 있다.

Nest의 생명주기

  1. Incoming request
  2. Globally bound middleware
  3. Module bound middleware
  4. Global guards
  5. Controller guards
  6. Route guards
  7. Global interceptors (pre-controller)
  8. Controller interceptors (pre-controller)
  9. Route interceptors (pre-controller)
  10. Global pipes
  11. Controller pipes
  12. Route pipes
  13. Route parameter pipes
  14. Controller (method handler)
  15. Service (if exists)
  16. Route interceptor (post-request)
  17. Controller interceptor (post-request)
  18. Global interceptor (post-request)
  19. Exception filters (route, then controller, then global)
  20. Server response
profile
메모장

0개의 댓글