이번에는 데이터 전송 객체(DTO)의 개념과 사용 방법에 대해 알아보겠습니다. DTO는 다양한 계층이나 시스템 간에 데이터를 안전하게 전달하기 위한 패턴으로, class-validator와 class-transformer라는 라이브러리를 함께 활용하면 더욱 효과적으로 사용할 수 있습니다.
DTO란?
DTO(Data Transfer Object)는 여러 계층 또는 시스템 간에 데이터를 전달하는 데 사용되는 설계 패턴입니다. 주요 목적은 데이터를 캡슐화하여 네트워크나 다른 모듈 간의 통신에서 원본 데이터 구조를 노출하지 않도록 하는 것입니다.
DTO의 주요 특징:
- 데이터 캡슐화: DTO는 비즈니스 로직 없이 단순히 데이터만 담고 있으며, 이는 데이터의 전달을 돕습니다.
- 계층 간 전송: 예를 들어 Controller와 Service 계층 사이 또는 클라이언트와 서버 간 통신 시 유용합니다.
- 데이터 교환 단순화: 복잡한 엔티티를 직접 전송하지 않고 필요한 정보만을 전달함으로써 시스템의 결합도를 낮춥니다.
- 필요한 데이터만 전달: 특정 목적에 맞게 데이터를 가공하거나 필터링하여 효율적인 전송이 가능합니다.
DTO 사용 시나리오:
- 클라이언트-서버 통신: 웹 애플리케이션에서는 HTTP 요청/응답 시 DTO를 통해 데이터가 전송됩니다.
- 계층 간 데이터 교환: MVC 구조에서 Controller와 Service 간에도 DTO가 사용됩니다.
- 마이크로서비스 통신: 서비스 간 통신 시 내부 엔티티를 노출하지 않고 DTO를 사용해 데이터를 전달합니다.
DTO vs 엔티티(Entity):
- 엔티티: 데이터베이스 스키마에 직접 매핑되며, 비즈니스 로직 및 DB 연산 기능을 포함합니다.
- DTO: 단순한 데이터 컨테이너로, 비즈니스 로직 없이 데이터 전송에 집중합니다.
예제 코드:
// 사용자 엔티티 (비즈니스 로직 및 DB 필드 포함)
class User {
id: number;
name: string;
email: string;
password: string; // 보안상 노출되지 않음
}
// 사용자 DTO (프론트엔드와의 통신에 사용)
class UserDTO {
id: number;
name: string;
email: string;
constructor(user: User) {
this.id = user.id;
this.name = user.name;
this.email = user.email;
}
}
// DTO 인스턴스 생성
const user = new User();
user.id = 1;
user.name = "John";
user.email = "john@example.com";
user.password = "secret";
// DTO로 변환 후 반환
const userDTO = new UserDTO(user);
관련 라이브러리
1. class-validator:
class-validator는 클래스 인스턴스의 유효성을 검증하는 데 사용됩니다. DTO에 검증 규칙을 정의하고, 데이터의 형식이나 범위 등을 확인할 수 있습니다. 데코레이터(@IsString(), @IsInt() 등)를 활용해 쉽게 검증 로직을 추가할 수 있습니다.
예시:
import { IsString, IsInt, Min } from 'class-validator';
class CreateUserDTO {
@IsString()
username: string;
@IsInt()
@Min(18)
age: number;
}
이 예시에서는 username이 문자열인지, 그리고 age가 18 이상의 정수인지 검증합니다.
2. class-transformer:
class-transformer는 일반 JS 객체와 클래스 인스턴스 간의 변환을 지원합니다. 타입 변환, 속성 이름 변경, 중첩 객체 처리 등의 기능을 제공합니다.
예시:
import { plainToClass } from 'class-transformer';
class CreateUserDTO {
username: string;
age: number;
}
const plainObject = { username: 'John', age: 25 };
const userDTO = plainToClass(CreateUserDTO, plainObject);
plainToClass 함수는 일반 객체를 DTO 클래스 인스턴스로 변환합니다.
DTO의 주요 용도:
- 데이터 검증:
class-validator를 이용해 입력 데이터의 유효성을 점검합니다. - 데이터 전송: 서로 다른 계층이나 컴포넌트 간에 데이터를 전달합니다.
- 데이터 변환: 일반 객체를 클래스 인스턴스로 변환하여 메서드나 속성을 활용합니다.
- 데이터 저장: DTO를 통해 DB와의 상호작용을 수행합니다.
- 타입 안정성 향상: 개발 시 IDE 자동완성과 타입 체크를 통해 코드의 신뢰성을 높입니다.