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