我开始在一个新的NestJ项目中工作,但当我尝试实现序列化时,我面临一个问题。我希望实现序列化,在对象被发送到网络响应之前转换它们。我的项目工作正常,但是当我试图在控制器中实现ClassSerializerInterceptor时,我得到了以下错误:
[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
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
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[];
}
我不知道我做错了什么,或者错误的根源是什么。
发布于 2019-12-24 13:16:07
据我迄今所见,有两件事突然浮现在我的脑海中。
class-transformer
的使用,并在实体类中使用class-validator
,以排除整个类的属性,并且只在所得到的序列化对象中公开所需的属性。代码如下:
billing-statement.entity.ts
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[];
}
BillingStatementResponseDto
,您将在控制器响应类型中使用此响应。BillingStatementResponseDto
可以包含外部api对象的属性(例如,从一些外部api获取属性、一些实体属性以及一些传入请求dto的属性)。您还可以扩展class-transformer
的使用,并使用class-validator
,如上面BillingStatementResponseDto
定义中的第一个建议中所示。代码将如下所示:
billing-statement.entity.ts (保持不变,没有类转换器的东西)
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-transformer
和class-validator
) -将导入并在控制器中使用
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
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);
}
}
第二个解决方案在层分离、灵活性、模块化和可维护性方面会更好:)
(如果有帮助,请告诉我;)
发布于 2019-12-25 12:18:26
根据错误信息,我认为您有一个循环引用问题。只需注释掉billing_statement对象所引用的其他对象,然后再试一次。如果这是您获得此错误的原因,则应从子对象中移除对父对象的引用,或尝试不序列化这些引用。
祝你好运。
https://stackoverflow.com/questions/59463288
复制相似问题