DTO ( Data Transfer Object ) with NestJS

DTOλ₯Ό μ™œ μ‚¬μš©ν•΄μ•Ό ν•˜μ£ ?

Posted by Seohyun Park, Aileen on October 24, 2023 · 6 mins read
FRAMEWORK, NESTJS

πŸš€ DTO (Data Transfer Object) with NestJS

μ–Όλ§ˆ μ „, νšŒμ‚¬ νŒ€μ›μ—κ²Œ DTOλ₯Ό μ™œ ꡳ이 μ‚¬μš©ν•΄μ•Όν•˜λŠ”μ§€?에 λŒ€ν•œ μ§ˆλ¬Έμ„ λ°›μ•˜λ‹€.

κ·Έλž˜μ„œ 이번 ν¬μŠ€νŒ…μ—μ„œλŠ” DTOλ₯Ό μ™œ μ‚¬μš©ν•΄μ•Όν•˜λŠ”μ§€μ— λŒ€ν•΄ μ•Œμ•„λ³΄κ³ μž ν•œλ‹€.

λ¨Όμ €, DTOλŠ” Data Transfer Object의 μ•½μžλ‘œ, 데이터 전솑 객체라고 ν•œλ‹€.

DTOλŠ” λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ 데이터λ₯Ό μ–»μ–΄ μ„œλΉ„μŠ€λ‚˜ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직으둜 전달할 λ•Œ μ‚¬μš©ν•˜λŠ” 객체이닀.

μ•„λ§ˆ, μ•žμ„œ 받은 μ§ˆλ¬Έμ€, μ—”ν„°ν‹°λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜λ©΄ λ˜μ§€ μ™œ DTOλ₯Ό μ‚¬μš©ν•΄μ•Όν•˜λ‚˜? λΌλŠ” μ˜λ¬Έμ΄μ—ˆμ„ 것이닀.



1. λ³΄μ•ˆμƒμ˜ 이유 - μ—”ν„°ν‹°λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜λ©΄, μ—”ν„°ν‹°μ˜ λͺ¨λ“  데이터가 λ…ΈμΆœλœλ‹€.

μ•„λž˜ μ˜ˆμ‹œλŠ”, User 에 κ΄€ν•œ μ—”ν„°ν‹° ν΄λž˜μŠ€μ΄λ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    // user.entity.ts
    import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

    @Entity()
    export class User {
        @PrimaryGeneratedColumn()
        id: number;

        @Column()
        loginType: string;

        @Column()
        email: string;

        @Column()
        password: string;

        @Column()
        socialId: string;

        @Column()
        socialAccessToken: string;

        @Column()
        name: string;

        @Column()
        nickname: string;

        @Column()
        profileImage: string;
    }

μœ„μ™€ 같은 μ—”ν„°ν‹°λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜λ©΄, λͺ¨λ“  데이터가 λ…ΈμΆœλ˜κΈ° λ•Œλ¬Έμ— λ³΄μ•ˆμƒμ˜ 이유둜 DTOλ₯Ό μ‚¬μš©ν•œλ‹€.

μ•„λž˜ μ˜ˆμ‹œλŠ”, νŠΉμ • User λ₯Ό μ‘°νšŒν•˜λŠ” API 이닀.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    // user.controller.ts
    import { Controller, Get, Param } from '@nestjs/common';
    import { UserService } from './user.service';

    @Controller('user')
    class UserController {
        constructor(private readonly userService: UserService) {}

        @Get(':id')
        async getUser(@Param('id') id: number) {
            return await this.userService.getUser(id);
        }
    }

    // user.service.ts
    import { Injectable } from '@nestjs/common';
    import { InjectRepository } from '@nestjs/typeorm';
    import { Repository } from 'typeorm';
    import { User } from './user.entity';

    @Injectable()
    class UserService {
        constructor(
            @InjectRepository(User)
            private readonly userRepository: Repository<User>,
        ) {}

        async getUser(id: number) {
            return await this.userRepository.findOne(id);
        }
    }

이 API λ₯Ό ν˜ΈμΆœν•˜λ©΄, μ•„λž˜μ™€ 같은 응닡이 μ˜¨λ‹€.

1
2
3
4
5
6
7
8
9
10
11
    {
        "id": 1,
        "loginType": "email",
        "email": "test@test.com",
        "password": "test",
        "socialId": null,
        "socialAccessToken": null,
        "name": "test",
        "nickname": "test",
        "profileImage": null
    }

λͺ¨λ“  데이터가 λ…ΈμΆœλ˜κΈ° λ•Œλ¬Έμ— λ³΄μ•ˆμƒμ˜ 이유둜 DTOλ₯Ό μ‚¬μš©ν•œλ‹€.

2. API 의 μ•ˆμ •μ„± - μ—”ν„°ν‹°λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜λ©΄, μ—”ν„°ν‹°μ˜ 데이터가 λ³€κ²½λ˜λ©΄ API 응닡 데이터도 λ³€κ²½λœλ‹€.

μ—”ν„°ν‹°λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜λ©΄, μ—”ν„°ν‹°μ˜ 데이터가 λ³€κ²½λ˜λ©΄ API 응닡 데이터도 λ³€κ²½λœλ‹€.

κΈ°μ‘΄ User ν…Œμ΄λΈ”μ—μ„œ, lastLoginAt μ»¬λŸΌμ„ μΆ”κ°€ν•˜μ˜€λ‹€κ³  κ°€μ •ν•˜μž.

1
2
    @Column()
    lastLoginAt: Date;

이 경우, API 응닡 데이터도 λ³€κ²½λ˜μ–΄μ•Ό ν•œλ‹€.

λ°±μ—”λ“œμ—μ„œλŠ”, API 응닡 데이터λ₯Ό λ³€κ²½ν•˜λŠ” 것은 큰 λ¬Έμ œκ°€ λ˜μ§€ μ•Šμ§€λ§Œ, ν”„λ‘ νŠΈμ—”λ“œμ—μ„œλŠ” 큰 λ¬Έμ œκ°€ λœλ‹€.

ν”„λ‘ νŠΈμ—”λ“œμ—μ„œλŠ”, API 응닡 데이터가 λ³€κ²½λ˜λ©΄, API 응닡 데이터λ₯Ό μ‚¬μš©ν•˜λŠ” λͺ¨λ“  κ³³μ—μ„œ λ³€κ²½λœ 데이터λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

μ΄λŸ¬ν•œ 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ DTOλ₯Ό μ‚¬μš©ν•œλ‹€.

μ•„λž˜ μ˜ˆμ‹œλŠ”, 본인이 μ•„λ‹Œ, λ‹€λ₯Έ User λ₯Ό μ‘°νšŒν•˜λŠ” API 이닀.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    // μ—”ν„°ν‹°λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜λŠ” 경우
    {
        "id": 1,
        "loginType": "email",
        "email": "test@test.com",
        "password": "test",
        "socialId": null,
        "socialAccessToken": null,
        "name": "test",
        "nickname": "test",
        "profileImage": null,
        "lastLoginAt": "2021-10-24T12:00:00.000Z" // μΆ”κ°€λœ 컬럼
    }

    // DTOλ₯Ό μ‚¬μš©ν•˜λŠ” 경우
    {
        "id": 1,
        "email": "test@test.com",
        "name": "test",
        "nickname": "test",
        "profileImage": null // ν•„μš”ν•œ λ°μ΄ν„°λ§Œ μ‘λ‹΅λ°›μ•„μ„œ, μΆ”κ°€λœ 컬럼이 μ‘λ‹΅λ˜μ§€ μ•ŠλŠ”λ‹€.
    }

μœ„μ™€ 같이, ν•„μš”ν•œ λ°μ΄ν„°λ§Œ μ‘λ‹΅λ°›μ•„μ„œ, μΆ”κ°€λœ 컬럼이 μ‘λ‹΅λ˜μ§€ μ•ŠλŠ”λ‹€.

μ΄λŸ¬ν•œ 이유둜, μ—”ν„°ν‹°λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜μ§€ μ•Šκ³ , DTOλ₯Ό μ‚¬μš©ν•œλ‹€.


3. API 응닡 속도 - λΆˆν•„μš”ν•œ 데이터가 ν¬ν•¨λ˜μ–΄, API 응닡 λ°μ΄ν„°μ˜ 크기가 컀진닀.

μ—”ν„°ν‹°λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜λ©΄, λΆˆν•„μš”ν•œ 데이터가 ν¬ν•¨λ˜μ–΄, API 응닡 λ°μ΄ν„°μ˜ 크기가 컀진닀.

예λ₯Ό λ“€μ–΄, User ν…Œμ΄λΈ”κ³Ό μ—°κ΄€λœ Post ν…Œμ΄λΈ”μ΄ μžˆλ‹€κ³  κ°€μ •ν•˜μž.

이 경우, μ—”ν„°ν‹°λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜λ©΄, User ν…Œμ΄λΈ”κ³Ό μ—°κ΄€λœ Post ν…Œμ΄λΈ”μ˜ 데이터도 μ‘λ‹΅λœλ‹€.

ν•˜μ§€λ§Œ, User ν…Œμ΄λΈ”κ³Ό μ—°κ΄€λœ Post ν…Œμ΄λΈ”μ˜ λ°μ΄ν„°λŠ” ν•„μš”ν•˜μ§€ μ•Šλ‹€.