首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用NestJS正确设置序列化?

如何使用NestJS正确设置序列化?
EN

Stack Overflow用户
提问于 2019-12-24 02:52:26
回答 2查看 9.3K关注 0票数 2

我开始在一个新的NestJ项目中工作,但当我尝试实现序列化时,我面临一个问题。我希望实现序列化,在对象被发送到网络响应之前转换它们。我的项目工作正常,但是当我试图在控制器中实现ClassSerializerInterceptor时,我得到了以下错误:

代码语言:javascript
运行
复制
[Nest] 27010   - 12/23/2019, 8:20:53 PM   [ExceptionsHandler] Maximum call stack size exceeded +29851ms
RangeError: Maximum call stack size exceeded
    at Object.Console.<computed> (internal/console/constructor.js:241:9)
    at Object.log (internal/console/constructor.js:282:26)
    at Object.consoleCall (<anonymous>)
    at _loop_1 (/path/to/my/project/node_modules/class-transformer/TransformOperationExecutor.js:146:47)

我更改了ClassSerializerInterceptor的范围以解决问题,但错误仍然存在。根据文档,我需要在控制器中使用拦截器,在实体中使用相应的装饰器来实现序列化。我的序列化实现如下:

billing-statement.controller.ts

代码语言:javascript
运行
复制
import { ClassSerializerInterceptor, Controller, Get, Query, UseInterceptors } from '@nestjs/common';
import { BillingStatementService } from './billing-statement.service';
import { BillingStatementDto } from './billing-statement.dto';
import { BillingStatement } from './billing-statement.entity';

@Controller('billing-statement')
export class BillingStatementController {
  constructor(private readonly billingStatementService: BillingStatementService) {}

  @Get()
  @UseInterceptors(ClassSerializerInterceptor)
  async getBillingStatement(
    @Query() query: BillingStatementDto,
  ): Promise<BillingStatement> {
    return this.billingStatementService.findBillingStatementByUser(+query.id);
  }
}

billing-statement.entity.ts

代码语言:javascript
运行
复制
import { AutoIncrement, BelongsTo, Column, ForeignKey, HasMany, Model, PrimaryKey, Table } from 'sequelize-typescript';
import { User } from '../users/user.entity';
import { Payment } from './payment.entity';
import { Exclude } from 'class-transformer';

@Table({
  tableName: 'billing_statement_tbl',
  timestamps: false,
})
export class BillingStatement extends Model<BillingStatement> {
  @AutoIncrement
  @PrimaryKey
  @Column({field: 'billing_statement_id_pk'})
  id: number;

  @Column
  currency: string;

  @Column({field: 'total_amount'})
  totalAmount: number;

  @Exclude()
  @Column({field: 'contract_start'})
  contractStart: Date;

  @Exclude()
  @Column({field: 'contract_end'})
  contractEnd: Date;

  @HasMany(() => Payment)
  payments: Payment[];
}

我不知道我做错了什么,或者错误的根源是什么。

EN

回答 2

Stack Overflow用户

发布于 2019-12-24 13:16:07

据我迄今所见,有两件事突然浮现在我的脑海中。

  1. 扩展对class-transformer的使用,并在实体类中使用class-validator,以排除整个类的属性,并且只在所得到的序列化对象中公开所需的属性。

代码如下:

billing-statement.entity.ts

代码语言:javascript
运行
复制
import { AutoIncrement, BelongsTo, Column, ForeignKey, HasMany, Model, PrimaryKey, Table } from 'sequelize-typescript';
import { User } from '../users/user.entity';
import { Payment } from './payment.entity';
import { Exclude, Expose, Type } from 'class-transformer';
import { IsArray, IsNumber, IsString } from 'class-validator';

@Exclude()
@Table({
  tableName: 'billing_statement_tbl',
  timestamps: false,
})
export class BillingStatement extends Model<BillingStatement> {
  @AutoIncrement
  @PrimaryKey
  @Column({field: 'billing_statement_id_pk'})
  @Expose()
  @IsNumber()
  id: number;

  @Column
  @Expose()
  @IsString()
  currency: string;

  @Column({field: 'total_amount'})
  @Expose()
  @IsNumber()
  totalAmount: number;

  @Column({field: 'contract_start'})
  contractStart: Date;

  @Column({field: 'contract_end'})
  contractEnd: Date;

  @HasMany(() => Payment)
  @IsArray()
  @Expose()
  @Type(() => Payment)
  payments: Payment[];
}
  1. 另一种方法是将您的实体定义与返回的dto定义分开,这样您就可以扩展实体的定义,在返回的dto中添加或减去要的和不想要的属性。例如,假设您已经将响应命名为dto BillingStatementResponseDto,您将在控制器响应类型中使用此响应。BillingStatementResponseDto可以包含外部api对象的属性(例如,从一些外部api获取属性、一些实体属性以及一些传入请求dto的属性)。您还可以扩展class-transformer的使用,并使用class-validator,如上面BillingStatementResponseDto定义中的第一个建议中所示。

代码将如下所示:

billing-statement.entity.ts (保持不变,没有类转换器的东西)

代码语言:javascript
运行
复制
import { AutoIncrement, BelongsTo, Column, ForeignKey, HasMany, Model, PrimaryKey, Table } from 'sequelize-typescript';
import { User } from '../users/user.entity';
import { Payment } from './payment.entity';

@Table({
  tableName: 'billing_statement_tbl',
  timestamps: false,
})
export class BillingStatement extends Model<BillingStatement> {
  @AutoIncrement
  @PrimaryKey
  @Column({field: 'billing_statement_id_pk'})
  id: number;

  @Column
  currency: string;

  @Column({field: 'total_amount'})
  totalAmount: number;

  @Column({field: 'contract_start'})
  contractStart: Date;

  @Column({field: 'contract_end'})
  contractEnd: Date;

  @HasMany(() => Payment)
  payments: Payment[];
}

billing-statement-response.dto.ts (目标返回对象的新文件定义,使用class-transformerclass-validator) -将导入并在控制器中使用

代码语言:javascript
运行
复制
import { Exclude, Expose, Type } from 'class-transformer';
import { IsArray, IsNumber, IsString, ValidateNested } from 'class-validator';

@Exclude()
export class BillingStatementResponseDto {
  @Expose()
  @IsNumber()
  id: number;

  @Expose()
  @IsString()
  currency: string;

  @Expose()
  @IsNumber()
  totalAmount: number;

  @IsArray()
  @ValidateNested()
  @Expose()
  @Type(() => Payment)
  payments: Payment[];
}

billing-statement.controller.ts

代码语言:javascript
运行
复制
import { ClassSerializerInterceptor, Controller, Get, Query, UseInterceptors } from '@nestjs/common';
import { BillingStatementService } from './billing-statement.service';
import { BillingStatementDto } from './billing-statement.dto';
import { BillingStatementResponseDto } from './billing-statement-response.dto'; // <= import your newly defined dto 

@Controller('billing-statement')
export class BillingStatementController {
  constructor(private readonly billingStatementService: BillingStatementService) {}

  @Get()
  @UseInterceptors(ClassSerializerInterceptor)
  async getBillingStatement(
    @Query() query: BillingStatementDto,
  ): Promise<BillingStatementResponseDto> { // <= here you go for the use of BillingStatementResponseDto
    return this.billingStatementService.findBillingStatementByUser(+query.id);
  }
}

第二个解决方案在层分离、灵活性、模块化和可维护性方面会更好:)

(如果有帮助,请告诉我;)

票数 3
EN

Stack Overflow用户

发布于 2019-12-25 12:18:26

根据错误信息,我认为您有一个循环引用问题。只需注释掉billing_statement对象所引用的其他对象,然后再试一次。如果这是您获得此错误的原因,则应从子对象中移除对父对象的引用,或尝试不序列化这些引用。

祝你好运。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59463288

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档