序列化
序列化是在对象在网络响应中 返回之前发生的过程。这是一个合适的地方,可以提供转换和清理要返回给客户端的数据的规则。 例如,像密码这样的敏感数据应始终从响应中排除。或者,某些属性可能需要额外的转换,例如仅发送实体的属性子集。 手动执行这些转换可能会很繁琐且容易出错,并且可能会让您不确定是否已覆盖所有情况。
概述
Nest提供了一个内置的功能,以确保可以以一种简单直接的方式执行这些操作。
ClassSerializerInterceptor
拦截器使用强大的 class-transformer
包,
以提供一种声明性且可扩展的方式来转换对象。它执行的基本操作是获取方法处理程序返回的值,
并应用 class-transformer
转换函数 instanceToPlain()
。
通过这样做,它可以应用在实体/DTO类上由 class-transformer
装饰器表达的规则,
如下所述。
序列化不适用于 StreamableFile
响应。
排除属性
假设我们想要自动排除用户实体的password
属性。我们可以如下注释实体:
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);
}
}
现在考虑一个包含返回该类实例的方法处理程序的控制器。
@UseInterceptors(ClassSerializerInterceptor)
@Get()
findOne(): UserEntity {
return new UserEntity({
id: 1,
firstName: 'Kamil',
lastName: 'Mysliwiec',
password: 'password',
});
}
请注意,我们必须返回该类的实例。 如果返回一个普通的 JavaScript 对象,例如 { user: new UserEntity() }
,则该对象将无法正确序列化。
ClassSerializerInterceptor
从 @nestjs/common
导入。
当请求此端点时,客户端将接收到以下响应:
{
"id": 1,
"firstName": "Kamil",
"lastName": "Mysliwiec"
}
请注意,可以将拦截器应用于整个应用程序(如此处所述)。
拦截器和实体类声明的组合确保任何返回 UserEntity
的方法都将确保删除password
属性。
这为您提供了一种集中执行此业务规则的手段。
公开属性
您可以使用 @Expose()
装饰器为属性提供别名,或执行计算属性值的函数(类似于 getter
函数),如下所示。
@Expose()
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}
转换
您可以使用 @Transform()
装饰器执行额外的数据转换。
例如,以下结构返回 RoleEntity
的 name
属性而不是整个对象。
@Transform(({ value }) => value.name)
role: RoleEntity;
传递选项
您可能希望修改转换函数的默认行为。
要覆盖默认设置,请将它们作为选项对象传递给 @SerializeOptions()
装饰器。
@SerializeOptions({
excludePrefixes: ['_'],
})
@Get()
findOne(): UserEntity {
return new UserEntity();
}
@SerializeOptions()
装饰器从 @nestjs/common
导入。
通过 @SerializeOptions()
传递的选项作为底层 instanceToPlain()
函数的第二个参数传递。
在这个例子中,我们自动排除所有以 _
前缀开头的属性。
示例
可以在这里找到一个可工作的示例。
WebSockets 和微服务
尽管本章节显示了使用 HTTP 风格应用程序(例如,Express 或 Fastify)的示例,
但是 ClassSerializerInterceptor
对于 WebSocket 和微服务同样适用,
无论使用的是什么传输方法。
了解更多
阅读有关 class-transformer
包提供的可用装饰器和选项的更多信息。