본문 바로가기
BE/Node

Nest 맵

by Chars4785 2022. 7. 28.

좋은 사이트

https://tristy.tistory.com/39?category=993422 

 

[Nest Js] Nest Js 공식 문서 파헤치기 - OverView 2

트리스티가 Nest Js를 공부하며 남긴 기록입니다. 틀린 내용은 언제든지 말씀해주세요 ~! 📣 Controller란 무엇인가? Controller란 사용자(client)의 요청(request)을 처리하고, 응답(response)을 반환하는 역할

tristy.tistory.com

Interceptors

Interceptors have access to response/request before and after the route handler is called.

Registration

  • Directly in the controller class with @UseInterceptors() controller- or method-scoped
  • Globally with app.useGlobalInterceptors() in main.ts

Examples

  • LoggingInterceptor: Request before route handler and afterwards its result. Meassure time it takes.
  • ResultMapping: Transform null to [] or wrap result in a response object: users -> {users: users}

Conclusion

I like that the registration is closer to the route handlers compared to middleware. But there are some limitations, for example, you cannot set the response code or alter the response with Interceptors when you send the response with the library-specific @Res() object in your route handler, see docs.

Middleware

Middleware is called only before the route handler is called. You have access to the response object, but you don't have the result of the route handler. They are basically express middleware functions.

Registration

  • In the module, very flexible way of choosing relevant routes (with wildcards, by method,...)
  • Globally with app.use() in main.ts

Examples

  • FrontendMiddleware: redirect all routes except API to index.html, see this thread
  • You can use any express middleware that is out there. There are lots of libraries, e.g. body-parser or morgan

Conclusion

The registration of middleware is very flexible, for example: apply to all routes but one etc. But since they are registered in the module, you might not realize it applies to your controller when you're looking at its methods. It's also great that you can make use of all the express middleware libraries that are out there.

Exception Filters

Exception Filters are called after the route handler and after the interceptors. They are the last place to make changes before a response goes out.

Registration

  • Directly in the controller class with @UseFilters() controller- or method-scoped
  • Globally app.useGlobalFilters() in your main.ts

Examples

  • UnauthorizedFilter: Map to an easy to understand message for the user
  • NotFoundFilter: Map all routes that are not found (not part of your api) to your index.html.

Conclusion

The basic use case for exception filters are giving understandable error messages (hiding technical details). But there are also other creative ways of usage: When you serve a single page application, then typically all routes should redirect to index.html except the routes of your API. Here, you can redirect on a NotFoundException. Some might find this clever others hacky. Your choice. ;-)


So the execution order is:

Middleware -> Interceptors -> Route Handler -> Interceptors -> Exception Filter (if exception is thrown)

With all three of them, you can inject other dependencies (like services,...) in their constructor.

 

쉬어가는 페이지 - 요청/응답 생명주기

요청/응답 생명주기는 들어온 요청이 어떤 컴포넌트를 거쳐서 처리되고, 생성된 응답은 또 어떤 컴포넌트를 거쳐 처리되는지를 말합니다. 어떤 프레임워크를 사용하더라도 요청/응답 생명주기를 알아두는 것은 중요합니다. 개발할 때나 디버깅 할 때 생명주기를 잘 알면 애플리케이션의 동작을 쉽게 이해할 수 있으므로 가능하면 외워두도록 합시다. 요청/응답 생명주기를 줄여서 요청 생명주기(Request Lifecycle)이라고도 부릅니다.

미들웨어

미들웨어의 실행순서는 정해져 있습니다. 먼저 전역으로 바인딩된 미들웨어를 실행합니다. 이후는 모듈에 바인딩 되는 순서대로 실행합니다. 다른 모듈에 바인딩되어 있는 미들웨어들이 있으면 먼저 루트 모듈에 바인딩 된 미들웨어를 실행하고, imports에 정의한 순서대로 실행됩니다.

가드

가드 역시 전역으로 바인딩된 가드를 먼저 시작합니다. 그리고 컨트롤러에 정의된 순서대로 실행됩니다. 아래 코드에서의 예를 들면 Guard1, Guard2, Guard3의 순서로 실행됩니다.

@UseGuards(Guard1, Guard2)
@Controller('users')
export class UsersController {
  constructor(private usersService: UsersService) {}

  @UseGuards(Guard3)
  @Get()
  getUsers(): Users[] {
    return this.usersService.getUsers();
  }
}

인터셉터

인터셉터의 실행순서는 가드와 유사합니다. 다만 한가지 알아야 할 점은 인터셉터는 RxJS의 Observable 객체를 반환하는데 이는 요청의 실행순서와 반대순서로 동작합니다. 즉, 요청은 전역 > 컨트롤러 > 라우터의 순서대로 동작하지만, 응답은 라우터 > 컨트롤러 > 전역으로 동작합니다.

파이프

파이프는 동작하는 순서가 조금 독특합니다. 파이프가 여러 레벨에서 적용되어 있다면 이전과 마찬가지의 순서대로 적용합니다. 특이한 점은 파이프가 적용된 라우터의 매개변수들이 여러개 있을 때 정의한 순서의 거꾸로 적용합니다. 다음 코드를 보면 파이프가 두 개 적용되어 있습니다. updateUser 함수에는 파이프가 둘 다 적용되는데 GeneralValidationPipe > RouteSpecificPipe 순으로 적용됩니다. 하지만 이들 파이프를 각각 적용하는 updateUser의 파라미터는 query > params > body의 순서대로 적용됩니다. 즉, GeneralValidationPipe가 query > params > body의 순서대로 적용되고, 이후 RouteSpecificPipe가 같은 순서대로 적용됩니다.

@UsePipes(GeneralValidationPipe)
@Controller('users')
export class UsersController {
  constructor(private usersService: UsersService) {}

  @UsePipes(RouteSpecificPipe)
  @Patch(':id')
  updateUser(
    @Body() body: UpdateUserDTO,
    @Param() params: UpdateUserParams,
    @Query() query: UpdateUserQuery,
  ) {
    return this.usersService.updateUser(body, params, query);
  }
}

예외 필터

유일하게 필터는 전역 필터가 먼저 적용되지 않습니다. 라우터 > 컨트롤러 > 전역으로 바인딩된 순서대로 동작합니다. 참고로 필터는 예외를 잡으면(catch) 다른 필터가 동일한 예외를 잡을 수 없습니다. 어떻게 생각하면 당연한 것인데 라우터에 적용된 예외 필터가 이미 예외를 잡아서 처리했는데 전역 예외 필터가 또 잡아서 처리를 할 필요가 없기 때문입니다.

일반적인 요청/응답 생명주기

위의 내용을 종합하면 다음과 같습니다.

참고

https://wikidocs.net/158658

 

쉬어가는 페이지 - 요청/응답 생명주기

요청/응답 생명주기는 들어온 요청이 어떤 컴포넌트를 거쳐서 처리되고, 생성된 응답은 또 어떤 컴포넌트를 거쳐 처리되는지를 말합니다. 어떤 프레임워크를 사용하더라도 요청/응답 ...

wikidocs.net


참고

 

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

'BE > Node' 카테고리의 다른 글

DTO vs Entity  (1) 2022.07.28
Nest.js(5)  (0) 2022.07.02
Nest.js(4)  (0) 2022.06.29
관점 지향 프로그래밍(AOP)  (0) 2022.06.24
Nest.js(2)  (0) 2022.06.23

댓글