有没有办法将默认值设置为缺少/可选的 JSON 属性?
Posted
技术标签:
【中文标题】有没有办法将默认值设置为缺少/可选的 JSON 属性?【英文标题】:Is there a way to set default value to missing/optional JSON attribute? 【发布时间】:2019-05-30 08:50:24 【问题描述】:我使用 NodeJs/NestJs 来构建一个 RESTful 服务。我创建了一些对象来匹配请求 JSON。在这些对象中有一些可选属性,但如果客户端不通过 JSON 发送它们,我想为它们设置默认值。
实现目标的最佳方法是什么?
这是我与 JSON 匹配的 DTO。
import IsDefined, IsNumber, Min from 'class-validator';
import ApiModelProperty, ApiModelPropertyOptional from '@nestjs/swagger';
export class RequestDto
@IsDefined()
@IsNumber()
@Min(0)
@ApiModelProperty(description: 'The current age.')
public CurrentAge: number;
@ApiModelPropertyOptional(description: 'The existing saving amount.')
public ExistingSavingAmount: number = 0;
这是我的 NestJs 控制器
import Controller, Post, Body, Param from '@nestjs/common';
import RequestDto from './Dto/Request.Dto';
import ApiResponse, ApiOperation from '@nestjs/swagger';
@Controller('mycontroller')
export class MyController
@Post('MyEndPoint')
@ApiOperation( title: 'Do something' )
@ApiResponse( status: 201, description: 'Something is done' )
public doSomething(@Body() request: RequestDto)
// do more jobs
我启动服务,并将以下 JSON 发布到我的终点
"CurrentAge": 40,
在我的控制器中,我看到 ExistingSavingAmount
是空白的,而不是值为 0。但如果我直接实例化 RequestDto
,我可以看到 ExistingSavingAmount
的值为 0。
【问题讨论】:
您能否以您现有的端点之一为例,甚至可以使用示例 JSON 向我们展示您的意思? @Paul 我已经用代码示例更新了我的帖子。 【参考方案1】:好的,如果没有来自 OP 的代码示例,此响应的保真度可能需要改进。也就是说,执行此操作的“嵌套”方式是通过TransformPipe。
他们给出的典型例子是 ParseIntPipe:
import Injectable, BadRequestException from '@nestjs/common';
@Injectable()
export class ParseIntPipe
transform(value, metadata)
const val = parseInt(value, 10);
if (isNaN(val))
throw new BadRequestException('Validation failed');
return val;
在不知道你的默认值是什么样子的情况下,我会假设它就像一个产品,你想默认一些东西并将一些东西作为一个空字符串:
import Injectable, BadRequestException from '@nestjs/common';
// we will assume you have your own validation for the non-optional bits
const optionalDefaults =
description: '',
category: 'Miscelleneous'
@Injectable()
export class ProductDefaultsPipe
transform(value, metadata)
const val = Object.assign(optionalDefaults, value);
return val;
现在,您可能正在使用提供模式和模型定义的东西(例如 Joi 或 Mongoose)。如果您是,那么我建议在该架构中设置所有默认值和验证,然后在您的 TransformPipe 中应用该架构,而不是编写太多自定义代码。例如,如果你有一个 ProductSchema,这对你有用:
@Injectable()
export class ProductDefaultsPipe
async transform(value, metadata)
const val = new Product(value);
const isValid = await val.validate();
if (!isValid)
throw new BadRequestException('Validation failed');
return val;
【讨论】:
【参考方案2】:只有当RequestDto
实际实例化为一个类时,您的默认值才会适用。由于您已经在使用 class-validator 进行验证,因此您可以使用 classTransformer.plainToClass()
来实例化该类。
如果您使用内置的ValidationPipe
,您可以使用 transform: true
选项自动实例化您的RequestDto
类:
@UsePipes(new ValidationPipe( transform: true ))
@Post('MyEndPoint')
public doSomething(@Body() request: RequestDto)
或作为全局管道:
async function bootstrap()
const app = await NestFactory.create(ApplicationModule);
app.useGlobalPipes(new ValidationPipe( transform: true ));
await app.listen(3000);
bootstrap();
【讨论】:
非常感谢您的意见。进一步的问题,不使用classTransformer.plainToClass()
或@UsePipes(new ValidationPipe( transform: true ))
,DTO类没有实例化,那么它来自哪里?由于我来自 C# 背景,在这种情况下,对象是从 JSON 反序列化的,因此它由序列化程序实例化。 javascript/TypeScript 在这种情况下有很大不同?
如果没有类转换器,它将不会从 JSON 反序列化,而是保持一个普通的 Javascript 对象。由于这发生在运行时,因此没有类型检查。事实上,在运行时你不会有 RequestDto 对象,而是会有一个普通对象(希望没有人检查)符合你的 RequestDto 接口。以上是关于有没有办法将默认值设置为缺少/可选的 JSON 属性?的主要内容,如果未能解决你的问题,请参考以下文章