DTO(Data Transfer Object), 데이터를 오브젝트로 변환하는 객체라는 뜻으로, 각 계층(Controller, View 등) 간의 데이터 교환을 위한 객체를 말한다.
dto를 활용하려는 목적은 Class나 Interface를 통해 데이터를 유효성 검증하기 위해 사용한다.
Class 및 Interface를 활용한 DTO 검증export class createTestDTO {
readonly name: string;
readonly age: number;
readonly location: string[];
}
class-validator로 활용가능
import { IsNumber, IsString } from 'class-validator';
export class createTestDTO {
@IsString()
readonly name: string;
@IsNumber()
readonly age: number;
@IsString({ each: true })
readonly location: string[];
}
![]()
import { Field, InputType, Int } from '@nestjs/graphql';
import { IsNotEmpty, IsEmail } from 'class-validator';
@InputType()
export class CreateUserInput {
@Field()
@IsNotEmpty()
@IsEmail()
email: string;
@Field(() => Int)
@IsNotEmpty()
age: number;
}
Entity와 DTO는 엄연히 분리해서 관리해야한다.
DB Layer와 View Layer 사이의 역할을 분리하기 위해서이다.
DTO 클래스는 View(클라이언트)와 통신하기 때문에 자주 변경되는 한편
Entity 클래스는 실제 테이블과 매핑되어, 변경되면 여러 다른 클래스에 영향을 끼친다.
NestJS 에서 TypeScript로만 작성하고자 할때
클래스 상단에 사용
@ObjectType()
스키마(Scheme) 정의의 대부분은 객체유형(Obejct Type)이다.
정의하는 각 객체 유형은 클라이언트가 상호 작용해야하는 도메인 객체를 나타내야한다.
type Author {
id: Int!
firstName: String
lastName: String
posts: [Post]
}
import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Post } from './post';
@ObjectType()
export class Author {
@Field(type => Int)
id: number;
@Field({ nullable: true })
firstName?: string;
@Field({ nullable: true })
lastName?: string;
@Field(type => [Post])
posts: Post[];
}
@InputType()
이 DTO를 사용하는 Resolver는 @Args('')에 해당 객체에 대한 이름을 반드시 넣어주어야한다.
@InputType()를 사용했을 경우 @Args()는 명시된 객체가 들어오고, DTO로 명시해준 타입에 맞게 들어온다.
예시 @Mutation(() => User)
createUser(@Args('createUserData') createUserData: CreateUserInput): User {
return this.usersService.createUser(createUserData);
}
@ArgsType()
이 DTO는 @Args()에 이름을 넣어줄 필요는 없다.
@ArgsType()를 사용했을때, Resolver는 여러개의 인자를 받게된다.
예시import { ArgsType, Field } from '@nestjs/graphql';
import { IsArray } from 'class-validator';
@ArgsType()
export class GetUsersArgs {
@Field(() => [String])
@IsArray()
userIds: string[];
}
@Query(() => [User], { name: 'users', nullable: 'items' })
getUsers(@Args() getUsersArgs: GetUsersArgs): User[] {
return this.usersService.getUsers(getUsersArgs);
}
@Injectable()
@Resolver()
@Controller()
클래스 내부에 사용
Field
@Field()필드를 작성해줄 때 사용한다. 선택적 유형 함수 선태적 옵션으로 원하는
GraphQL유형을 반환할 수 있다.
A.예시: 어떤 필드가 정수만 반환하기 원할경우.@Field(type => Int)
id: number;
또는
@Field(type => Float)
id: number;
B.예시: 어떤 필드가 배열인 경우.@Field(type => [Item])
cart: Item[];
또는
@Field(type => [String])
id: string[];
B-1.예시: 배열의 항목이 nullable임을 선언 할 경우@Field(type => [Item], { nullable: 'item'})
cart: Item[];
B-2.예시: 배열과 항목 모두 nullable 일 경우@Field(type => [String], { nullable: 'itemsAndList'})
@Resolver()
Resolover는 클라이언트와 상호 작용할 수 있게 도와주는 데코레이터이다.
작성 방법은 대략 아래와 같다.
A.예시: User라는 클래스를 사용할때.@Resolver(() => User)
export class UsersResolver {
constructor(
private readonly usersService: UsersService){}
)
}
@Query(() => User)
getUser(@Args() getUserArgs: GetUserArgs): User {
return this.usersService.getUser(getUserArgs)
}
@Mutation(() => User)
createUser(@Args('createUserData') createUserData: CreateUserInput): User {
return this.usersService.createUser(createUserData);
}
@Query()
@Mutation
@Args()
@Int