본 강의는 'john ahn'님의 강의를 정리한 내용입니다.
https://www.youtube.com/watch?v=3JminDpCJNE
파이프란 무엇인가? @Injectable()
데코레이터로 주석이 달린 클래스이다.
또한, 파이프는 컨트롤러 경로 처리기에 의해 처리되는 인수에 대해서 작동하는데 data transformation
과 data validation
를 위해서 사용된다.
다음과 같이 URL 요청이 왔을 때, 먼저 해당 URL에 대한 데이터들을 처리해주는 것이다. 만약 문제가 생기면 통과하지 못하고 Error 처리되며, 통과한다면 데이터를 처리해준 채로 handler에게 가게 된다.
Data Transformation
입력 데이터를 원하는 형식으로 변환하는 것을 말한다. 가령 문자열에서 정수로 바꾸는 것을 의미한다.
Data Validation
유효성 체크로서, 입력 데이터를 평가하고 유효한 경우 변경되지 않은 상태로 전달된다. 그렇지 않으면 데이터가 올바르지 않을 때 예외를 발생시킨다.
만약 이름의 길이가 10자 이하여야 하는데 10자 이상이 되면 에러를 발생시킨다.
Handler-level Pipes, Parameter-level Pipes, Global-level Pipes 3가지로 나뉜다.
@UsePipes(pipe)
데코레이터를 남겨 파이프를 사용한다.@Post()
@UsePipes(pipe)
createBoard(
@Body() createBoardDto : CreateBoardDto
) : Board {
return this.boardService.createBoard(createBoardDto);
}
이런식으로 사용한다.
@Patch('/:id/status')
updateBoardStatus(
@Param('id') id : string,
@Body('status', pipe) status : BoardStatus
){
return this.boardService.updateBoardStatus(id, status);
}
다음과 같이 status
라는 파라미터에 @Body('status', pipe)
가 적용된 것을 볼 수 있다. 파라미터 레벨로 작동시키고 싶다면 @Body()
데코레이터의 두번째 인자로 파이프를 넘겨주면 되는 것이다.
mian.ts
의 app
에 useGlobalPipes()
을 적용시켜주면 된다.async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(globalPipe)
await app.listen(3000);
}
bootstrap();
다음과 같이 사용할 수 있다.
Nestjs의 pipe는 빌트인과, 커스텀이 있는데, 우리가 직접 만드는 파이프가 커스텀 파이프
이고 미리 만들어진 것이 빌트인 파이프
이다.
하나만 보자면, ParseIntPipe
를 사용해보면
@Get(':id')
findOne(@Param('id', ParseIntPipe) id : number){
return;
}
다음의 예제에서 localhost:3000/boards/abc
와 같이 id를 abc와 같은 값으로 보내면 파이프에서 먼저 처리하여number
타입이 아니기 때문에 에러를 발생시킨다.
게시물을 생성할 때, 파이프를 이용하여 유효성 체크를 해보도록 하자
class-validator
, class-transformer
를 설치해보자다음의 명령어를 입력해주자
npm install class-validator class-transformer --save
https://github.com/typestack/class-validator
https://github.com/typestack/class-transformer
사용법은 해당 docs를 보면 된다.
먼저 class-validator
를 이용하여 url로 들어오는 파라미터를 검증해보자, 사용 방법은 매우 단순한데, docs에 있는 데코레이터들을 클래스의 프로퍼티 위에다 적어주면 된다.
createBoard(
@Body() createBoardDto : CreateBoardDto
) : Board {
return this.boardService.createBoard(createBoardDto);
}
그래서 우리는 controller에서 createBoard의 CreateBoardDto를 손보도록 해보자
boards/dto/create-board.dto.ts
import { IsNotEmpty } from 'class-validator'
export class CreateBoardDto{
@IsNotEmpty()
title : string;
@IsNotEmpty()
description : string;
}
다음과 같이 url로 보내지는 데이터에 title, description이 없으면 안된다고 IsNotEmpty()
데코레이터를 이용하여 표시해두도록 하자
이는 data validation
기능을 표시해둔 것일 뿐이며, 파이프가 적용된 것은 아니다. 파이프를 적용하기 위해서는 위에서 소개한 것처럼, 핸들러 레벨, 파라미터 레벨, 글로벌 레벨에서 파이프를 사용하는 데코레이터를 사용해야 data validation
이 적용되는 것이다.
다시 controller 부분으로 가서, createBoard
메서드에 Pipe를 적용해보도록 하자
@Post()
@UsePipes(ValidationPipe)
createBoard(
@Body() createBoardDto : CreateBoardDto
) : Board {
return this.boardService.createBoard(createBoardDto);
}
@UsePipes(ValidationPipe)
을 적용하려는 핸들러에 적어주면 된다. 참고로 ValidationPipe
는 이미 있는 빌트인 파이프이기 때문에, 자동적으로 nest에서 import해준다.
이제 잘 적용되는 지 확인해보도록 하자
post만에 다음과 같이 post 요청을 보내보자
{
"statusCode": 400,
"message": [
"title should not be empty",
"description should not be empty"
],
"error": "Bad Request"
}
이와 같이 제대로된 응답이 온 것을 확인할 수 있다.
@nestjs/common
안에는 예외처리에 대한 Exception
들이 정의되어있다. 이를 이용해서 예외를 처리해보자
service의 getBoardById()
메서드에서 만약 원하는 특정 게시물이 없다면 예외처리를 해주도록 하자
getBoardById(id: string) : Board {
const found = this.boards.find((board) => board.id === id);
if(!found){
throw new NotFoundException("can't find any id : " + id);
}
return found;
}
postman으로 http://localhost:3000/boards/eqweqw
에 GET요청을 하면
{
"statusCode": 404,
"message": "can't find any id : eqweqw",
"error": "Not Found"
}
다음과 같은 결과가 나올 것이다.
이번에는 없는 게시물을 지우려고 할 때를 처리해주도록 하자, 이와 같은 경우는 getBoardById()
를 먼저 호출하고 delete해서 처리해주면 된다.
deleteBoard(id : string){
const found = this.getBoardById(id);
this.boards = this.boards.filter( (board) => board.id !== found.id)
}
getBoardById()
메서드를 호출하고, 해당 found에서 board 객체가 있다면 id가 같을 것이고 없다면 id값이 틀릴 것이다.
이렇게 삭제할 객체가 있는지 없는 지 확인할 수 있다.