Serialization

Serialization is a process that happens before objects are returned in a network response. This is an appropriate place to provide rules for transforming and sanitizing the data to be returned to the client. For example, sensitive data like passwords should always be excluded from the response. Or, certain properties might require additional transformation, such as sending only a subset of properties of an entity. Performing these transformations manually can be tedious and error prone, and can leave you uncertain that all cases have been covered.

Overview

Nest provides a built-in capability to help ensure that these operations can be performed in a straightforward way. The ClassSerializerInterceptor interceptor uses the powerful class-transformer package to provide a declarative and extensible way of transforming objects. The basic operation it performs is to take the value returned by a method handler and apply the classToPlain() function from class-transformer. In doing so, it can apply rules expressed by class-transformer decorators on an entity/DTO class, as described below.

Exclude properties

Let's assume that we want to automatically exclude a password property from a user entity. We annotate the entity as follows:

import { Exclude } from 'class-transformer';
export class UserEntity {
id: number;
firstName: string;
lastName: string;
@Exclude()
password: string;
constructor(partial: Partial<UserEntity>) {
Object.assign(this, partial);
}
}

Now consider a controller with a method handler that returns an instance of this class.

@UseInterceptors(ClassSerializerInterceptor)
@Get()
findOne(): UserEntity {
return new UserEntity({
id: 1,
firstName: 'Kamil',
lastName: 'Mysliwiec',
password: 'password',
});
}

Warning Note that we must return an instance of the class. If you return a plain JavaScript object, for example, {{ '{' }} user: new UserEntity() {{ '}' }}, the object won't be properly serialized.

info Hint The ClassSerializerInterceptor is imported from @nestjs/common.

When this endpoint is requested, the client receives the following response:

{
"id": 1,
"firstName": "Kamil",
"lastName": "Mysliwiec"
}

Note that the interceptor can be applied application-wide (as covered here). The combination of the interceptor and the entity class declaration ensures that any method that returns a UserEntity will be sure to remove the password property. This gives you a measure of centralized enforcement of this business rule.

Expose properties

You can use the @Expose() decorator to provide alias names for properties, or to execute a function to calculate a property value (analogous to getter functions), as shown below.

@Expose()
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}

Transform

You can perform additional data transformation using the @Transform() decorator. For example, the following construct returns the name property of the RoleEntity instead of returning the whole object.

@Transform(role => role.name)
role: RoleEntity;

Pass options

You may want to modify the default behavior of the transformation functions. To override default settings, pass them in an options object with the @SerializeOptions() decorator.

@SerializeOptions({
excludePrefixes: ['_'],
})
@Get()
findOne(): UserEntity {
return new UserEntity();
}

info Hint The @SerializeOptions() decorator is imported from @nestjs/common.

Options passed via @SerializeOptions() are passed as the second argument of the underlying classToPlain() function. In this example, we are automatically excluding all properties that begin with the _ prefix.

WebSockets and Microservices

While this chapter shows examples using HTTP style applications (e.g., Express or Fastify), the ClassSerializerInterceptor works the same for WebSockets and Microservices, regardless of the transport method that is used.

Learn more

Read more about available decorators and options as provided by the class-transformer package here.