DTO란
배경지식
백엔드에서 자원을 효율적으로 사용하기 위해 요청 횟수를 최소화하고, 요청 시 최대한 많은 데이터를 보내는 것이 중요합니다. 어떻게 하면 데이터를 모아서 한번에 전달할 수 있을까라는 고민 끝에 고안된 것이 바로 DTO, 데이터 전송 객체입니다.
DTO란
DTO는 Data Transfer Obejcts의 약자입니다. DTO를 사용하면 input 데이터의 1)프로퍼티와 2)타입을 미리 설정할 수 있습니다. DTO를 사용하면 데이터 타입을 통제하기 때문에 장기적으로 협업에 도움이 됩니다.
DTO를 사용하는 이유
- 유닛 테스트가 쉬워진다. Service 레이어에서 유닛 테스트를 진행 시, Entity를 바로 적용하면 Service 테스트가 가능합니다. 굳이 DB와 연동해서 테스트할 필요가 없어집니다
- 유지보수가 쉬워집니다. 예를 들어 userDto에 name, age 타입이 있고, userService 로직 params에 userDto를 적용해줍니다. 그런데 추후 gender 필드가 추가될 경우, userDto에 gender 타입 추가해주면 끝이 납니다. 만약, Dto가 없다면 필드가 추가될 때마다 userService에 이에 상응하는 params를 추가해주어야 합니다
dto - request payload
dto 만들기
// src/create-event.dto.ts
export class CreateEventDto {
name: string;
description: string;
when: string;
address: string;
}
컨트롤러에서 dto 사용하기
// src/events.controllers.ts
...
import { CreateEventDto } from './create-event.dto';
...
@Post()
create(@Body() input: CreateEventDto) {
// O
return input.address;
// X
return input.love // 'CreateEventDto' 형식에 'love' 속성이 없습니다.ts(2339)
}
...
dto를 사용하면 input 데이터의 형식을 통제할 수 있습니다. 좀 더 풀어보자면, CreateEventDto
에서 우리는 name, description, when, address 프로퍼티만 사용하도록 강제할 수 있습니다. 만약 정의하지 않은 love 프로퍼티를 입력하면 에러가 발생합니다. 이렇게 하면 협업 시에 팀원들에게 프로퍼티만 쓰도록 선택권을 줄 수 있으니 서로 편해집니다.
dto - update payload
만약 update
요청한 데이터의 양식을 체크하고 싶다면 어떻게 해야할까요?
크게 2가지 방식이 있는데, 1)TS optional로 타입 체크를 하거나, 2)nestjs/mapped-types
패키지를 사용하면 됩니다. 저희는 패키지를 사용하여 양식을 체크해보겠습니다.
nestjs/mapped-types 패키지 설치
https://www.npmjs.com/package/@nestjs/mapped-types
npm i --save @nestjs/mapped-types
update-event.dto 생성
update-event.dto.ts라는 dto를 만들어서 update 요청 시 양식을 체크할 것입니다. 이때 TS의 옵셔널 대신 mapped-types 패키지의 PartialType
옵션을 사용할 것입니다. 이 옵션을 사용하면 input의 모든 프로퍼티를 옵셔널로 취급하게 해줍니다.
// src/update-event.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateEventDto } from './create-event.dto';
// CreateEventDto 원본의 일부 타입만 가져오도록 = 옵셔널이랑 같은 효과
export class UpdateEventDto extends PartialType(CreateEventDto) { }
컨트롤러에 dto 적용
// src/events.controllers.ts
...
import { UpdateEventDto } from './update-event.dto';
...
@Patch(':id')
update(@Param('id') identity, @Body() input: UpdateEventDto) {
return input.address;
}
Entity
Entity란?
이벤트 엔티티를 만들어서 적용하기 전에 Entity의 개념에 대해 짚고 넘어갑시다.
Entity
는 실체 또는 객체를 말합니다. 개념, 저장되어야 하는 무엇을 지칭합니다. 예를 들어, 학교에는 과목, 교실이라는 엔티티가 있습니다. 엔티티는 인스턴스의 집합입니다. 과목이란 엔티티 안에는 물리, 미술, 수학이라는 인스턴스들이 포함됩니다.
학교
- 엔티티 : 과목
- 인스턴스 : 물리
- 인스턴스 : 미술
- 인스턴스 : 수학
Entity 작성
// src/event.entity.ts
export class Event {
id: number;
number: string;
description: string;
when: Date;
address: string;
};
Entity 적용
// src/events.controllers.ts
...
import { Event } from './event.entity';
@Controller('/events')
export class EventsController {
// 이벤트 엔티티 적용
private events: Event[] = [];
...
이벤트 엔티티 추가해주었다. 임시 저장소라고 생각하면 된다. 이후 각 CRUD 코드도 엔티티에 맞춰 수정해주었다.
최종 코드 스니펫
// src/events.controllers.ts
import { Body, Controller, Delete, Get, Param, Patch, Post, HttpCode } from '@nestjs/common';
import { CreateEventDto } from './create-event.dto';
import { UpdateEventDto } from './update-event.dto';
import { Event } from './event.entity';
@Controller('/events')
export class EventsController {
// 이벤트 엔티티 적용
private events: Event[] = [];
// 5개 정도 가볍게 유지하는 것이 좋다
@Get()
findAll() {
// 배열을 반환하여도 클라이언트는 JSON 데이터로 받는다
return this.events;
}
// Param 데코레이터 사용하여 파라미터 가져오기
@Get(':id')
findOne(@Param('id') id) {
const event = this.events.find((event) => event.id === parseInt(id));
return event;
}
// Body 데코레이터로 body 값 가져오기
@Post()
create(@Body() input: CreateEventDto) {
// Dto에서 타입 규정했기에 프로퍼티, 타입이 통제
const event = {
...input,
when: new Date(input.when), // dto에는 규정되었지만 input에 없는 데이터 추가
id: this.events.length + 1, // auto-increment
};
this.events.push(event);
return event;
}
@Patch(':id')
update(@Param('id') id, @Body() input: UpdateEventDto) {
const index = this.events.findIndex((event) => event.id === parseInt(id));
this.events[index] = {
...this.events[index],
...input,
when: input.when ? new Date(input.when) : this.events[index].when,
};
return this.events[index]; // 수정 아이템 반환
}
@Delete(':id')
@HttpCode(204)
remove(@Param('id') id) {
// id 가지지 않는 event들만 필터링. 즉, id 가진 이벤트를 제외하는 것
this.events = this.events.filter((event) => event.id !== parseInt(id)); }
}
추가 참조
'Research > Nest.js' 카테고리의 다른 글
10. Nest.js_Database 읽기 (0) | 2023.02.07 |
---|---|
09. Nest.js_ Database 준비 (0) | 2023.02.07 |
07. Nest.js_RestAPI_응답 데이터 유형과 상태코드 (0) | 2023.02.07 |
06. Nest.js_RestAPI_Request Body (0) | 2023.02.07 |
05. Nest.js_RestAPI_Route Parameters (0) | 2023.02.07 |
댓글