Serializing responses
Serialization is turning an object into JSON before sending it to the client. By default NestJS sends the whole object with every field. The built-in ClassSerializerInterceptor together with the class-transformer library lets you mark the entity fields that must not be shown — for example, the password hash.
Marking fields
class-transformer was already installed in the validation lesson. Add the @Exclude() decorator to the password:
// src/users/entities/user.entity.ts
import { Exclude } from 'class-transformer';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
email: string;
@Column()
name: string;
@Exclude()
@Column()
password: string;
@Column({ default: 'user' })
role: string;
}The decorator alone changes nothing: it only marks the field for the interceptor.
Enabling the interceptor
The interceptor is enabled for the whole application in src/main.ts:
// src/main.ts
import { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common';
import { NestFactory, Reflector } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();Now the registration controller can return the whole entity:
// src/users/users.controller.ts
@Post()
register(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}Send POST /users — the response has id, email, name and role, and no password field. Listing fields by hand, as in the users lesson, is no longer needed.
Computed fields
The @Expose() decorator on a getter adds a field to the response that is not in the database:
// src/posts/entities/post.entity.ts
import { Expose } from 'class-transformer';
@Expose()
get excerpt(): string {
return this.content.slice(0, 100);
}Responses with posts now include an excerpt field — the first 100 characters of the text.
Main decorators
| Decorator | What it does |
|---|---|
@Exclude() | Removes the field from the response |
@Expose() | Adds a getter or field to the response |
@Transform(({ value }) => ...) | Changes the field value before sending |
@Type(() => Comment) | Names the class of nested objects |
Common mistake
The interceptor works only with class instances. If the service returns a plain object, for example { ...user } or the result of JSON.parse(), it carries no @Exclude() marks, and the password goes to the client. Return entities obtained from the repository, and if you need to build a response by hand, create a class instance with plainToInstance(User, data) from class-transformer.