이제 controller와 연결되어 데이터베이스 관련 로직을 처리할 service를 추가해보려고 한다.
nest g service board --no-spec
이렇게 하면 board.service.ts 파일이 생성되고 board.module.ts에는 provider로 방금 생성한 service가 추가된다.
service를 만들면 해당 class에 @Injectable()이라는 데코레이터가 붙는다. 이는 NestJS의 종속성을 주입(Dependency Injection, DI)하기 위한 핵심 요소로서, 해당 클래스를 Nest의 DI에 등록하는데 사용된다.
module 파일의 providers 배열에는 @Injectable 데코레이터가 붙은 클래스가 나열되는데, 이것은 해당 module이 생성하고 관리해야하는 종속성 목록을 정의한다. 이를 통해 Nest는 해당 인스턴스를 생성하고 필요한 곳에 주입할 수 있다.
class의 생성자를 통해서 다른 class의 인스턴스를 주입받는 경우에 사용한다.
pipe는 입력 데이터를 원하는 형식으로 변환(transformation)하는 경우나 입력 데이터에 대한 유효성 검사(validation)를 할때 주로 사용한다.
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(ValidationPipe);
await app.listen(3000);
@Controller('board')
@UsePipes(ValidationPipe)
export class boardController {
// 모든 핸들러에 대해 ValidationPipe가 적용
}
@Post()
@UsePipes(ValidationPipe)
createBoard(@Body() createBoardDto: CreateBoardDto): Promise<Board> {
return this.boardService.createBoard(createBoardDto);
}
@Post()
async create(@Body(ValidationPipe) createBoardDto: CreateBoardDto) {
this.boardService.create(createBoardDto);
}
위와 같이 파이프를 통해 유효성 검사를 하게 되면 DTO에 정의해 놓은 유효성 검사 규칙에 따라 validation을 수행한다.
이때 클래스 검증기(class-validator)와 클래스 변환기(class-transformer) 라이브러리를 사용하여 유효성을 검사하기 때문에 아래와 같이 설치가 필요하다.
npm install class-validator class-transformer --save
DTO
Data Transfer Oject의 약자로, 데이터베이스와 클라이언트 사이, 서버의 내부 계층 간, 또는 네트워크를 통해 데이터를 전송할 때 사용하는 객체를 말한다. DTO는 타입 안정성을 제공하고, 네트워크를 통해 전송되는 데이터 구조를 명확히 하는 역할을 하며, API의 명세(specification)이나 문서화에도 도움이 된다. 또한 DTO는 유효성 검사 규칙을 포함하여 입력 데이터의 유효성 검사를 간편하게 할 수 있는 방법을 제공한다.
createBoardDto는 아래와 같이 필요한 속성들을 정의한 클래스로 추후에 전달해야 할 인자가 많아지더라도 DTO의 내부만 고치면 되기 때문에 유지보수성이 높아진다.
import { IsNotEmpty } from 'class-validator';
export class CreateBoardDto {
@IsNotEmpty()
title: string;
@IsNotEmpty()
description: string;
}
이렇게 DTO 내부에서 유효성 검사를 해야 할 속성에 대해 유효성 검사 규칙을 적용해주면 파이프를 통해 유효성 검사를 쉽게 진행할 수 있다.
추가적인 유효성 검사 규칙은 아래의 링크를 참고하길 바란다.
https://github.com/typestack/class-validator#manual-validation
기본적으로 제공되는 ValidationPipe 같은 것을 제외하고 직접 파이프를 만들고 싶다면 PipeTransform 인터페이스를 구현하는 클래스를 만들어 사용할 수 있다. 이 클래스는 아래와 같이 transform이라는 메소드를 가져야 하며 이는 파이프의 로직을 담당한다.
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';
@Injectable()
export class CustomPipe implements PipeTransform {
transform(value: any) {
// 변환 또는 유효성 검사 로직
if (!isValid(value)) {
throw new BadRequestException('Validation failed');
}
return value;
}
}