序列化 Serialization

导读

序列化是在网络响应中返回对象之前发生的过程。这是一个提供转换和清理要返回给客户端的数据的规则的合适地方。例如,密码等敏感数据应始终从响应中排除。或者,某些属性可能需要额外的转换,例如仅发送实体的属性子集。手动执行这些转换可能很繁琐且容易出错,并且可能让您不确定是否已涵盖所有情况。

概述

Nest 提供了内置功能,可帮助确保以简单的方式执行这些操作。ClassSerializerInterceptor 拦截器使用强大的 class-transformer 包来提供一种声明性和可扩展的对象转换方式。它执行的基本操作是获取方法处理程序返回的值并应用 class-transformer 中的 instanceToPlain() 函数。在此过程中,它可以将 class-transformer 装饰器表达的规则应用于实体/DTO 类,如下所述。

提示

序列化不适用于 StreamableFile 响应。

排除属性

假设我们想要自动从用户实体中排除 password 属性。我们对实体进行如下注释:

ts
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)
  }
}

现在考虑一个带有方法处理程序的控制器,该方法处理程序返回此类的一个实例。

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

我们必须返回该类的一个实例。如果返回一个普通的 JavaScript 对象,例如 {{ '{' }} user: new UserEntity() {{ '}' }},则该对象将无法正确序列化。

Hint

The ClassSerializerInterceptor is imported from @nestjs/common.

请求此端点时,客户端会收到以下响应:

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

请注意,拦截器可以在整个应用程序范围内应用(如此处所述)。拦截器和实体类声明的组合确保返回UserEntity任何方法都一定会删除password属性。这为您提供了集中执行此业务规则的措施。

公开属性

您可以使用@Expose()装饰器为属性提供别名,或执行函数来计算属性值(类似于getter函数),如下所示。

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

转换

您可以使用 @Transform() 装饰器执行额外的数据转换。例如,以下构造返回 RoleEntity 的 name 属性,而不是返回整个对象。

ts
@Transform(({ value }) => value.name)
role: RoleEntity;

传递选项

您可能想要修改转换函数的默认行为。要覆盖默认设置,请使用 @SerializeOptions() 装饰器将它们传递到 options 对象中。

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

@SerializeOptions() 装饰器从 @nestjs/common 导入。

通过 @SerializeOptions() 传递的选项作为底层 instanceToPlain() 函数的第二个参数传递。在此示例中,我们自动排除所有以 _ 前缀开头的属性。

示例

此处 提供了一个工作示例。

WebSockets 和微服务

虽然本章展示了使用 HTTP 样式应用程序(例如 Express 或 Fastify)的示例,但 ClassSerializerInterceptor 对于 WebSockets 和微服务的作用相同,无论使用哪种传输方法。

了解更多

阅读有关 class-transformer 包提供的可用装饰器和选项的更多信息此处