1. Class Transformer(๋ณํ)
1.1 Class Transformer ํน์ฑ
- TS Decorator๋ฅผ ์ฌ์ฉํด์ ํด๋์ค๋ฅผ ๊ฒ์ฆํ๋ค (Validate)
- ๋๊ธฐ (Synchronous), ๋น๋๊ธฐ (Asynchronous) ๋ฐฉ์ ๋ชจ๋๋ฅผ ์ง์ํ๋ค.
- Class Validator ์์ฒด์ ์ผ๋ก ์ ๊ณตํด์ฃผ๋ Validator๋ค์ ์ฌ์ฉ ํ ์ ์๋ค.
- ์ปค์คํ Validator๋ฅผ ์ฝ๊ฒ ๋ง๋ค ์ ์๋ค.
- ์ปค์คํ ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ๋ฐํ ํ ์ ์๋ค.
- Class Validator๋ฅผ ์ ์ํ ๊ฐ๋ฐ์๊ฐ ์์ํ ํ๋ก์ ํธ๋ค
1.2 Class Transformer ์ค์น ๋ฐ ์ฌ์ฉ๋ฒ
(1) Class Transformer ์ค์น
1yarn add class-transformer
(2) Class Transformer ์ฌ์ฉ๋ฒ
1class User {2@Exclude()3name: string45@Transform(({ value }) => value.toUpperCase())6email: string7}
์ด๋ค Transformer๋ ๊ฒ์ฆํ๊ณ ์ถ์ ํ๋กํผํฐ์ Class Transformer์์ ์ ๊ณตํ๋ Decorator๋ฅผ ๋ถ์ฌ์ฃผ๋ฉด ๋๋ค.
1const plainUser = {2name: 'John',3email: 'John@example.com',4}5const user = plainToClass(User, plainUser)67// User { email: 'JOHN@EXAMPLE.COM' }8console.log(user)910const plain = classToPlain(user)1112// { email: 'JOHN@EXAMPLE.COM' }13console.log(plain)
validate() ํจ์๋ก ๊ฐ์ฒด๋ฅผ ๊ฒ์ฆํ์๋, Class Validator์ ๋ถํฉํ์ง ์์ ๊ฐ์ด ์
๋ ฅ๋๋ค๋ฉด ํด๋น๋๋ ์๋ฌ๊ฐ ๋ฐํ๋๋ค.
1.3 ์ค์ฒฉ ํด๋์ค ๋ณํ
1class Address {2city: string3country: string4}56class User {7@Exclude()8name: string910@Type(() => Address)11address: Address12}
์ค์ฒฉ๋ ๊ฐ์ฒด ํ์ ์ Type ๋ฐ์ฝ๋ ์ดํฐ์ ์ ๊ณตํด์ค๋ค.
1const plainUser = {2name: 'John',3address: {4city: 'New York',5country: 'USA',6},7}89const user = plainToClass(User, plainUser)1011// USer { address: Address { city: 'New York', country: 'USA' }}12console.log(user)
plainToClass๋ฅผ ์คํํ๋ฉด ์ค์ฒฉ๋ ๊ฐ์ฒด๋ Type ๋ฐ์ฝ๋ ์ดํฐ์ ์ ๋ ฅ๋ ํด๋์ค์ ์ธ์คํด์ค๋ก ๋ณํ๋๋ค
1.4 Custom Transformer
1class User {2@Exclude()3name: string45@Transform(({ value }) => value.toLowerCase())6email: string7}
Transform ๋ฐ์ฝ๋ ์ดํฐ๋ ์ ์ฉ๋ ํ๋กํผํฐ์ ๊ฐ์ ์๊ท๋จผํธ๋ก ์ ๊ณตํด์ฃผ๋ฉฐ ๋ณํ ํ๊ณ ์ถ์ ํํ๋ก ๊ฐ์ ๋ฐํํด์ฃผ๋ฉด ๋๋ค.
1const plainUser = {2name: 'John',3email: 'JOHN@EXAMPLE.COM',4}56const user = plainToClass(User, plainUser)78// john@example.com9console.log(user.email)
plainToClass๋ฅผ ์คํํ๋ฉด ์ค์ฒฉ๋ ๊ฐ์ฒด๋ Type ๋ฐ์ฝ๋ ์ดํฐ์ ์ ๋ ฅ๋ ํด๋์ค์ ์ธ์คํด์ค๋ก ๋ณํ๋๋ค
2. Exclude Annotation
๋ฏผ๊ฐํ ๊ฐ์ธ์ ๋ณด์ ๊ฐ์ด ๋ ธ์ถํ๊ณ ์ถ์ง ์์ ์ปฌ๋ผ์ ์ ์ธ(exclude)ํ ์ ์๋ค.
1@Column()2@IsString({3message: stringValidationMessage,4})5@Length(3, 8, {6message: lengthValidationMessage,7})8@Exclude() // ์ถ๊ฐ9password: string
e.g. ๋น๋ฐ๋ฒํธ๋ฅผ ๋ ธ์ถํ๊ณ ์ถ์ง ์์ ๊ณณ์์ interceptor๋ฅผ ๋ฑ๋กํด์ฃผ๋ฉด, API ์์ฒญ ์ ํด๋น ์ปฌ๋ผ์ ๋ณด๊ฐ ์ ์ธ๋๋ค.
1// ์๋ต23@Controller('users')4export class UsersController {5constructor(private readonly usersService: UsersService) {}67@Get()8/*** ClassSerializerInterceptor ๋ป9* Serialization(์ง๋ ฌํ)10* - ํ์ฌ ์์คํ ์์ ์ฌ์ฉ๋๋ (NestJS) ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๋ค๋ฅธ ์์คํ ์์๋ ์ฌ์ฉํ ์ ์๋ ํฌ๋งท์ผ๋ก ๋ณํ11* - class์ object์์ JSON ํฌ๋งท์ผ๋ก ๋ณํ12*13* Deserialization(์ญ์ง๋ ฌํ) : ์ง๋ ฌํ์ ๋ฐ๋14*/15@UseInterceptors(ClassSerializerInterceptor)16getUsers() {17return this.usersService.getAllUsers()18}1920// ์๋ต21}
3. Exclude Annotation ์ต์ ํ๊ตฌ
1@Column()2@IsString({3message: stringValidationMessage,4})5@Length(3, 8, {6message: lengthValidationMessage,7})8/*** ๐ toClassOnly์ toPlainOnly9* Request10* frontend -> backend11* plain object (JSON) -> class instance (dto)12*13* Response14* backend -> frontend15* class instance (dto) -> plain obejct (JSON)16*17* toClassOnly -> class Instance ๋ณํ๋ ๋๋ง (์์ฒญ์ผ ๋)18* toPlainOnly -> plain object๋ก ๋ณํ๋ ๋๋ง (์๋ต์ผ ๋)19* ์๋ต์ด ๋๊ฐ ๋๋ง password๋ฅผ ์ ์ธ์ํค๊ณ ์ถ์ ๋20*/21@Exclude({ toPlainOnly: true })22password: string
4. ClassSerializer AppModule์ ์ ์ฉ
๊ทธ๋ฐ๋ฐ ์ด๋ ๊ฒ ์ผ์ผ์ด ์ ์ธ ์ด๋ ธํ ์ด์ ์ ๋ค๋ ๊ฒ์ ์ฌ๋์ด๊ธฐ์ ์ค์ํ๋ฉด ๋น ์ง ์ ์๋ค.
- ๊ทธ๋์ ์๋์ผ๋ก ๋ชจ๋ API์ ๊ธฐ๋ณธ์ ์ผ๋ก class-transformer ์ ๋ ธํ ์ด์ ์ด ๋ฌ๋ ค์์ผ๋ฉด, ๋ชจ๋ ๊ธฐ๋ณธ ์ ์ฉ๋๋ค.
- ์ด๋ฅผ ์ํด ClassSerializer์ App ๋ชจ๋์ ์ ์ฉํ๋ฉด ๋๋ค.
- user ์ปจํธ๋กค๋ฌ์์ ClassSerializerInterceptor๋ฅผ ์ง์ด๋ค.
1// ์๋ต23@Module({4// ์๋ต5providers: [6AppService,7{8provide: APP_INTERCEPTOR,9useClass: ClassSerializerInterceptor,10},11],12})13export class AppModule {}
์ด๋ ๊ฒ ํ๋ฉด ๋ชจ๋ API์์ Exclude ์ด๋ ธํ ์ด์ ์ ์ ์ฉ์ํฌ ์ ์๋ค.
5. Expose Annotation ์ฌ์ฉ
์์๋ฅผ ์ํด ๋๋ค์๊ณผ ์ด๋ฉ์ผ์ ์์ ํ๋กํผํฐ๊ฐ ํฌํจ๋์ด์ผ ํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
1// users.entity.ts ์๋ต2@Expose()3get nicknameAndEmail() {4return this.nickname + '/' + this.email5}
- ์ด๋ฐ ์์ผ๋ก ์ค์ ์กด์ฌํ์ง ์๋ ํ๋กํผํฐ๋ฅผ expoese(๋ ธ์ถ)์ํฌ ์ ์๋ค.
- ๊ธฐ๋ฅ๋ง ํ์ธํด๋ณด๊ณ , ์ง์์ ์์๋ณต๊ท์ํจ๋ค.
6. Expose Annotation ํด๋์ค์ ์ ์ฉ
๋๋ฌด ๋ณด์์ฑ์ด ๊ฐํ ๊ฐ์ฒด๋ผ์, ๊ธฐ๋ณธ์ผ๋ก ๋ค ๋ณด์ด์ง ์๊ฒํ๊ณ , ๋ณด์ด๊ฒํ ํ๋กํผํฐ๋ง ์ ์ฉ์ํฌ ์ ์๋ค.
1// ์๋ต23@Entity()4@Exclude() // ์ถ๊ฐ5export class UsersModel extends BaseModel {6// ์๋ต7@Expose()8nickname: string910// ์๋ต11@Expose()12email: string1314// ์๋ต15}
- ์ด๋ฐ ์์ผ๋ก ํด๋์ค ์์ฒด์๋ค๊ฐ Exlcude ์ด๋ ธํ ์ด์ ์ ์ ์ฉํ๋ฉด ๋๋ค.
- ๊ทธ๋ฆฌ๊ณ ๋ ธ์ถ์ํฌ ํ๋กํผํฐ์๋ง Expose ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ฃผ๋ฉด ๋๋ค.
- ๊ธฐ๋ฅ๋ง ํ์ธํด๋ณด๊ณ , ์ง์์ ์์๋ณต๊ท์ํจ๋ค.