我正在尝试使用transform将formData的重传请求从字符串转换为json对象,然后使用validationPipe(类验证器)进行验证,但是我得到了
Maximum call stack size exceeded
at cloneObject (E:\projectos\Gitlab\latineo\latineo-apirest\node_modules\mongoose\lib\utils.js:290:21)
at clone (E:\projectos\Gitlab\latineo\latineo-apirest\node_modules\mongoose\lib\utils.js:204:16)
尝试调试后,我进入控制器3次,该对象保存在数据库中,但没有验证,并且内部transformJSONToObject 9次...
我的main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({ transform: true }));
app.use(helmet());
app.enableCors();
app.use(
rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 4000, // limit each IP to 100 requests per windowMs
}),
);
app.use(compression());
app.use('/upload', express.static(join(__dirname, '..', 'upload')));
const options = new DocumentBuilder()
.setTitle('XXX')
.setDescription('XXX')
.setVersion('1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
我的nestjs dto
export class CreateRestaurantDto {
// to do, check the documentation from class-validator for array of objects
@IsString()
@IsNotEmpty()
@ApiModelProperty({ type: String })
@Length(3, 100)
readonly name: string;
@IsString()
@IsNotEmpty()
@ApiModelProperty({ type: String })
@Length(3, 500)
readonly description: string;
@Transform(transformJSONToObject, { toClassOnly: true })
@ValidateNested()
@ApiModelProperty({ type: [RestaurantsMenu] })
readonly menu: RestaurantsMenu[];
@Transform(transformJSONToObject, { toClassOnly: true })
@IsString({
each: true,
})
@IsNotEmpty({
each: true,
})
@Length(3, 50, { each: true })
@ApiModelProperty({ type: [String] })
readonly type: string[];
@Transform(transformJSONToObject, { toClassOnly: true })
@ValidateNested()
@ApiModelProperty({ type: [RestaurantsLocation] })
readonly location: RestaurantsLocation[];
}
这是我的控制人
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@UseInterceptors(FilesInterceptor('imageUrls'))
@ApiConsumes('multipart/form-data')
@ApiImplicitFile({
name: 'imageUrls',
required: true,
description: 'List of restaurants',
})
@Post()
async createRestaurant(
@Body() createRestaurantDto: CreateRestaurantDto,
@UploadedFiles() imageUrls,
@Req() request: any,
): Promise<RestaurantDocument> {
const userId = request.payload.userId;
const user = await this.usersService.findUserById(userId);
const mapUrls = imageUrls.map(element => {
return element.path;
});
const restaurant = {
...createRestaurantDto,
imagesUrls: mapUrls,
creator: user,
};
// just add a resturant to mongodb
const createdRestaurant = await this.restaurantsService.addRestaurant(
restaurant,
);
user.restaurants.push(createdRestaurant);
user.save();
return createdRestaurant;
}
答案 0 :(得分:2)
我知道现在已经太晚了 :) 但也许这可以帮助某人
在 deep-parse-json 的帮助下,我的解决方案是创建一个如下所示的 ParseFormDataJsonPipe
并将其放在 ValidationPipe
之前。
您可以在构造函数中传递表单数据属性的例外列表,以保留一些纯粹的东西,例如图像、二进制、jsonArray...
import { PipeTransform, ArgumentMetadata } from '@nestjs/common';
import { deepParseJson } from 'deep-parse-json';
import * as _ from 'lodash';
type TParseFormDataJsonOptions = {
except?: string[];
};
export class ParseFormDataJsonPipe implements PipeTransform {
constructor(private options?: TParseFormDataJsonOptions) {}
transform(value: any, _metadata: ArgumentMetadata) {
const { except } = this.options;
const serializedValue = value;
const originProperties = {};
if (except?.length) {
_.merge(originProperties, _.pick(serializedValue, ...except));
}
const deserializedValue = deepParseJson(value);
console.log(`deserializedValue`, deserializedValue);
return { ...deserializedValue, ...originProperties };
}
}
这是一个控制器的例子
@Post()
@ApiBearerAuth('admin')
@ApiConsumes('multipart/form-data')
@UseGuards(JwtAuthGuard, RoleGuard)
@Roles(Role.Admin)
@UseInterceptors(
FileInterceptor('image', {
limits: { fileSize: imgurConfig.fileSizeLimit },
}),
)
async createProductByAdmin(
@Body(
new ParseFormDataJsonPipe({ except: ['image', 'categoryIds'] }),
new ValidationPipe(),
)
createDto: CreateProductDto,
@UploadedFile() image: Express.Multer.File,
) {
console.log(`createDto`, createDto);
}