NestJS - DTO๋ ์ class๋ก ๋ง๋ค๊น?
โ NestJS, DTO โ 5 min read
์๋ฌธ์ ๐ค
TypeScript์ NestJS๋ก ๊ฐ๋ฐํ๋ ๋์ค, ๋ฌธ๋ ๊ทธ๋ฐ ์๋ฌธ์ด ๋ค์๋ค.
'DTO(Data Transfer Object)๋ ์ class๋ก ๊ตฌํํ๋๊ฑธ๊น..?'
๊ทธ์ ํ์
์ฒดํฌ๋ฅผ ์ํด์๋ผ๋ฉด interface๋ type์ผ๋ก๋ ๊ฐ๋ฅํ๊ฒ ์๋๊ฐ?
๊ทธ๋ฐ๋ฐ ์ ๋ง์ ๋ ํผ๋ฐ์ค์์, ๊ทธ๋ฆฌ๊ณ ๊ณต์ ๋ฌธ์์์๋ class๋ก DTO๋ฅผ ๊ตฌํํ๋ ๊ฑธ๊น?
๐ก ๊ถ๊ธ์ฆ ํด๊ฒฐ..!
์์ธ๋ก ๊ถ๊ธ์ฆ์ ๋น ๋ฅด๊ฒ ํด๊ฒฐํ ์ ์์๋ค..
์ฌ์ง์ด ๊ณต์ ๋ฌธ์์ ๊ธฐ์ฌ ๋์ด ์๋ ๋ด์ฉ์ด์๋ ๊ฒ...
NestJS DTO vs Interface
NestJS ๊ณต์๋ฌธ์ - Controllers - Request payloads
But first (if you use TypeScript), we need to determine the DTO (Data Transfer Object) schema. A DTO is an object that defines how the data will be sent over the network. We could determine the DTO schema by using TypeScript interfaces, or by simple classes. Interestingly, we recommend using classes here. Why? Classes are part of the JavaScript ES6 standard, and therefore they are preserved as real entities in the compiled JavaScript. On the other hand, since TypeScript interfaces are removed during the transpilation, Nest can't refer to them at runtime. This is important because features such as Pipes enable additional possibilities when they have access to the metatype of the variable at runtime.
TypeScript๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ DTO ์คํค๋ง๋ฅผ ๊ฒฐ์ ํด์ผ ํฉ๋๋ค. DTO๋ ๋คํธ์ํฌ๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ์ ์ก๋๋ ๋ฐฉ๋ฒ์ ์ ์ํ๋ ๊ฐ์ฒด์ ๋๋ค. TypeScript Interface๋ ๊ฐ๋จํ class๋ฅผ ์ฌ์ฉํ์ฌ DTO ์คํค๋ง๋ฅผ ๊ฒฐ์ ํ ์ ์์ต๋๋ค. ํฅ๋ฏธ๋กญ๊ฒ๋ ์ด ์ํฉ์์๋ class๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. class๋ JavaScript ES6 ํ์ค์ ์ผ๋ถ์ด๋ฏ๋ก JavaScript๋ก ์ปดํ์ผํด๋ ์ค์ ๊ฐ์ฒด๋ก ๋จ์์์ง๋ง, TypeScript interface๋ ๋ณํ ์ค์ ์ ๊ฑฐ๋๋ฏ๋ก Nest๊ฐ ๋ฐํ์์ interface๋ฅผ ์ฐธ์กฐํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. Pipe์ ๊ฐ์ ๊ธฐ๋ฅ์ ๋ฐํ์์ ๋ณ์์ ๋ฉํํ์ ์ ์ ๊ทผํ ์ ์์ ๋ ์ ์ฉํ๋ฏ๋ก, ๋ฐํ์ ์ ์ฐธ์กฐ ๊ฐ๋ฅ ์ฌ๋ถ๋ ์ค์ํฉ๋๋ค.
์ถ์ฒ: NestJS ๊ณต์ ๋ฌธ์
class๋ ์ปดํ์ผ ์ดํ์๋ ๋จ์์์ด ๋ฐํ์์๋ ์ฐธ์กฐํ ์ ์๋ค๋ ์ ์ด DTO๋ฅผ class๋ก ๊ตฌํํ๋ ํต์ฌ์ ์ธ ์ด์ ์๋ค.
DTO๋ ๋ฐ์ดํฐ ์ ์ก์ ์ฐ๋ ๊ฐ์ฒด์ธ ๋งํผ ๋ฐ์ดํฐ ํ์
์ด๋ ๊ฐ์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ํํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์๋ฐ, ์ด๋ฅผ ์ํด์๋ ๋ฐํ์์๋ DTO์ ์ ๊ทผํ ์ ์์ด์ผํ๋ค...!
export class CreateMeetupDto { @ApiProperty({ description: '์ด๋ฒคํธ ์ ๋ชฉ (์ต๋ 50์)', minLength: 1, maxLength: 50, }) @Transform((params) => typeof params.value === 'string' ? params.value.trim() : params.value ) @IsString() @IsNotEmpty() @MaxLength(50) title: string;
@ApiProperty({ description: '์ด๋ฒคํธ ์ค๋ช
(์ต๋ 255์)', minLength: 1, maxLength: 255, }) @IsString() @Transform((params) => params.value.trim()) @IsNotEmpty() @MaxLength(255) description: string;}
์๋ ๋ด๊ฐ ์ค์ ๋ก ํ๋ก์ ํธ์์ ์ฌ์ฉํ๋ DTO ์ค ํ๋๋ค.
ํด๋น DTO์์๋ @IsString()
, @IsNotEmpty()
, @MaxLength(255)
๋ฑ์ ํ์ฉํ์ฌ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
ํ์ ๊ณผ ๊ฐ ๊ตฌ๋ถํ๊ธฐ
์ฐธ๊ณ : ์ดํํฐ๋ธ ํ์ ์คํฌ๋ฆฝํธ - ์์ดํ 8 ํ์ ๊ณต๊ฐ๊ณผ ๊ฐ ๊ณต๊ฐ์ ์ฌ๋ฒ ๊ตฌ๋ถํ๊ธฐ
ํ์
์คํฌ๋ฆฝํธ ํ๋ ์ด๊ทธ๋ผ์ด๋๋ ํ์
์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๋ณํํ ๊ฒฐ๊ณผ๋ฌผ์ ๋ณด์ฌ์ค๋ค.
์ปดํ์ผ ๊ณผ์ ์์ ํ์
์ ์ ๊ฑฐ๋๊ธฐ ๋๋ฌธ์, ์ฌ๋ผ์ง๋ ๊ฒ์ด ์๋ค๋ฉด ํ์
์ผ ๊ฒ์ด๋ค.
type๊ณผ interface ์์ฝ์ด๋ฅผ ์ด์ฉํ์ฌ ์ ์ธํ๋ฉด ํ์
์ด ๋๊ณ , class๋ const, let๋ก ์ ์ธํ๋ฉด ๊ฐ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.
ํนํ, class์ enum์ ์ํฉ์ ๋ฐ๋ผ ํ์
๊ณผ ๊ฐ์ด ์ ๋ถ ๊ฐ๋ฅํ ์์ฝ์ด์ด๋ค.