We use cookies to enhance your experience on the site
CodeWorlds

class-transformer — The Art of Data Transformation

The gate guard doesn't just check who enters — sometimes it must also dress the visitor in the appropriate toga or take away unnecessary items. This is exactly what class-transformer does — a library for controlling how data is transformed between different formats.

Basic Concepts

class-transformer offers two main transformation directions:

1// plain object → class instance
2const legionary = plainToInstance(CreateLegionaryDto, requestBody);
3
4// class instance → plain object
5const plainObject = instanceToPlain(legionary);

@Exclude() — hide sensitive data

The most commonly used decorator. It hides a field when converting an object to a JSON response. It's like a guard withholding confidential documents:

1import { Exclude } from 'class-transformer';
2
3export class LegionaryResponseDto {
4  name: string;
5  rank: string;
6
7  @Exclude()
8  secretMissionCode: string;  // This field will NOT appear in the response
9
10  @Exclude()
11  salary: number;  // Pay is also classified
12}

For this to work, the controller must use serialization:

1import { UseInterceptors, ClassSerializerInterceptor } from '@nestjs/common';
2
3@UseInterceptors(ClassSerializerInterceptor)
4@Controller('legionaries')
5export class LegionaryController {
6  @Get(':id')
7  findOne(@Param('id') id: string) {
8    // secretMissionCode and salary will be hidden
9    return this.service.findOne(id);
10  }
11}

@Expose() — control field visibility

The opposite of

@Exclude()
. When you use the
excludeAll
strategy, only fields with
@Expose()
will be visible:

1import { Exclude, Expose } from 'class-transformer';
2
3@Exclude()
4export class LegionaryResponseDto {
5  @Expose()
6  name: string;    // Visible
7
8  @Expose()
9  rank: string;    // Visible
10
11  salary: number;  // HIDDEN (because the entire class has @Exclude)
12  secretCode: string;  // HIDDEN
13}

@Transform() — custom transformation

Allows you to define custom transformation logic for a field:

1import { Transform } from 'class-transformer';
2
3export class CreateLegionaryDto {
4  @Transform(({ value }) => value.trim().toLowerCase())
5  name: string;
6  // " MARCUS  " → "marcus"
7
8  @Transform(({ value }) => new Date(value))
9  enlistmentDate: Date;
10
11  @Transform(({ value }) => Math.round(value))
12  experienceYears: number;
13}

@Type() — nested type transformation

When you have nested objects,

@Type()
tells class-transformer which class to convert to:

1import { Type } from 'class-transformer';
2
3class WeaponDto {
4  name: string;
5  damage: number;
6}
7
8export class LegionaryDto {
9  name: string;
10
11  @Type(() => WeaponDto)
12  weapon: WeaponDto;
13  // { name: "Gladius", damage: 50 } → WeaponDto instance
14}

plainToInstance and instanceToPlain

These functions allow you to manually transform data:

1import { plainToInstance, instanceToPlain } from 'class-transformer';
2
3// From a plain object to a class instance
4const rawData = { name: 'Marcus', rank: 'centurio' };
5const legionary = plainToInstance(CreateLegionaryDto, rawData);
6// Now legionary is a class instance with validation
7
8// From a class instance to a plain object
9const plain = instanceToPlain(legionary);
10// Fields with @Exclude() will be removed

Practical Example — DTO with Transformations

1import { Exclude, Expose, Transform, Type } from 'class-transformer';
2import { IsString, IsNumber } from 'class-validator';
3
4export class CreateLegionaryDto {
5  @IsString()
6  @Transform(({ value }) => value.trim())
7  name: string;
8
9  @IsString()
10  rank: string;
11
12  @IsNumber()
13  age: number;
14}
15
16export class LegionaryResponseDto {
17  @Expose()
18  name: string;
19
20  @Expose()
21  rank: string;
22
23  @Expose()
24  @Transform(({ value }) =>
25    value > 10 ? 'Veteranus' : 'Tiro'
26  )
27  experienceLevel: string;
28
29  @Exclude()
30  internalCode: string;
31}

class-transformer is a powerful tool that gives you full control over how data enters and leaves your API. Combined with class-validator, you create an impenetrable gate defense!

Go to CodeWorlds