Nest.js에서 클라이언트와 데이터 통신을 하기 위해서는 DTO(Data Transfer Object)를 사용해야 합니다.
DTO는 데이터를 전송하기 위해 작성된 객체로 Nest.js에서는 모든 데이터를 DTO로 주고받습니다.
DTO를 작성하기 위한 패키지 설치
$ npm i class-validator class-transformer
DTO 클래스 작성
// create-article.dto.ts
import { IsNumber, IsString } from 'class-validator';
export class CreateArticleDto {
@IsString()
readonly title: string;
@IsString()
readonly content: string;
@IsNumber()
readonly password: number;
}
@IsString, @IsNumber 데코레이터는 Nest.js에서 제공하는 데코레이터가 아닌
class-validator에서 제공하는 데코레이터 입니다.
위의 코드에서는 클라이언트로부터 전달받아야 하는 title, content를 DTO 객체의 변수로 선언했고 title, content 둘 중 하나라도 String 값으로 오지 않으면 자동으로 400 에러를 리턴합니다.
DTO는 통상적으로 요청(Get, Post, Put, Delete) 1개에 1개를 만듭니다.
하지만 전달받는 데이터가 같은(중복되는) DTO가 생길 수 있는데
그럴 때는 @nestjs/mapped-types의 PartialType을 상속받으면 됩니다.
상속받은 클래스에서 필요한 데이터만 뽑아서 사용하면 됩니다.
그중 일부만을 선택해서 사용하고 싶다면
@nestjs/mapped-types의 PickType을 상속받아 나는 이 부모 클래스에서 이 필드만 필요해 라고 선언하면 됩니다.
@nestjs/mapped-types 설치 코드
$ npm i @nestjs/mapped-types
update-article.dto.ts 코드 // PartialType 사용
import { PartialType } from '@nestjs/mapped-types';
import { CreateArticleDto } from './create-article.dto';
export class UpdateArticleDto extends PartialType(CreateArticleDto) {}
delete-article.dto.ts 코드 // PickType 사용
import { PickType } from '@nestjs/mapped-types';
import { CreateArticleDto } from './create-article.dto';
export class DeleteArticleDto extends PickType(CreateArticleDto, [
'password',
] as const) {}
DTO의 유효성 검사
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe()); // 이 한줄만 넣어주면 됩니다! 잊지마세요!
await app.listen(3000);
}
bootstrap();
컨트롤러 코드
import {
Body,
Controller,
Delete,
Get,
Param,
Post,
Put,
} from '@nestjs/common';
import { BoardService } from './board.service';
import { CreateArticleDto } from './dto/create-article.dto';
import { DeleteArticleDto } from './dto/delete-article.dto';
import { UpdateArticleDto } from './dto/update-article.dto';
@Controller('board')
export class BoardController {
constructor(private readonly boardService: BoardService) {}
@Get('/articles')
getArticles() {
return this.boardService.getArticles();
}
@Get('/articles/:id')
getArticleById(@Param('id') articleId: number) {
return this.boardService.getArticleById(articleId);
}
@Post('/articles')
createArticle(@Body() data: CreateArticleDto) {
return this.boardService.createArticle(
data.title,
data.content,
data.password,
);
}
@Put('/articles/:id')
updateArticle(
@Param('id') articleId: number,
@Body() data: UpdateArticleDto,
) {
return this.boardService.updateArticle(
articleId,
data.title,
data.content,
data.password,
);
}
@Delete('/articles/:id')
deleteArticle(
@Param('id') articleId: number,
@Body() data: DeleteArticleDto,
) {
return this.boardService.deleteArticle(articleId, data.password);
}
}
서비스 코드
import {
Injectable,
NotFoundException,
UnauthorizedException,
} from '@nestjs/common';
import _ from 'lodash';
@Injectable()
export class BoardService {
// 데이터베이스를 사용하지 않아 일단은 배열로 구현을 하였으니 오해 말아주세요!
// 보통은 TypeORM 모듈을 이용하여 리포지토리를 의존합니다. 이건 나중에 배울게요!
private articles = [];
// 게시글 비밀번호를 저장하기 위한 Map 객체입니다.
private articlePasswords = new Map();
getArticles() {
return this.articles;
}
getArticleById(id: number) {
return this.articles.find((article) => return article.id === id);
}
createArticle(title: string, content: string, password: number) {
const articleId = this.articles.length + 1;
this.articles.push({ id: articleId, title, content });
this.articlePasswords.set(articleId, password);
return articleId;
}
updateArticle(id: number, title: string, content: string, password: number) {
if (this.articlePasswords.get(id) !== password) {
throw new UnauthorizedException(
`Article password is not correct. id: ${id}`,
);
}
const article = this.getArticleById(id);
if (_.isNil(article)) {
throw new NotFoundException(`Article not found. id: ${id}`);
}
article.title = title;
article.content = content;
}
deleteArticle(id: number, password: number) {
if (this.articlePasswords.get(id) !== password) {
throw new UnauthorizedException(
`Article password is not correct. id: ${id}`,
);
}
this.articles = this.articles.filter((article) => article.id !== id);
}
}
'내일배움캠프 노드 4기 > Today I Learned' 카테고리의 다른 글
[Nest.js] 미들웨어 사용해보기 (0) | 2023.03.09 |
---|---|
[Nest.js] lodash 모듈을 못 불러와요 (0) | 2023.02.21 |
[Nest.js] 게시판 만들기 (0) | 2023.02.15 |
[Nest.js] IoC와 DI (0) | 2023.02.10 |
[Nest.js] 프로젝트 기본 코드 분석 (0) | 2023.02.10 |