midway
midway copied to clipboard
问题:含有子类的验证和类型转换
- Node Version: 14
- Midway Version(Decorator/Core): 3.4.0
- Component Name/Version: validate 和 core
- Platform: any
- Mini Showcase Repository:
复杂的对象可能需要多个子类来进行不同的验证方式,允许用户传入任何一种合法的格式,例如
// 基类
class Human {
echo() {
return '一个人类';
}
}
// 子类1
class HumanByAge extends Human {
@Rule(RuleType.string().valid('婴儿', '儿童', '成年人', '老人').required()
age: string;
echo() {
return '一个' + this.age;
}
}
// 子类2
class HumanByLocation extends Human {
@Rule(RuleType.string().valid('亚洲', '欧洲', '北美洲', '南美洲', '非洲', '大洋洲').required()
location: stirng;
echo() {
return '一个生活在' + this.location + '的人类';
}
}
问题1:假如子类对象是包含在DTO对象内的
class HumanDTO {
// 这里怎样实现根据实际类型来分别验证,并将human转成正确子类
@Rule()
human: Human;
// 其他
}
@Provide()
@Controller('/')
export class APIController {
@Post('/echo')
@Validate()
async echo(@Body(ALL) human: HumanDTO) {
return human.human.echo();
}
}
问题2:假如子类是直接作为DTO对象传入Controller参数的
@Provide()
@Controller('/')
export class APIController {
@Post('/echo')
@Validate()
async echo(@Body('human') human: Human) {
// 这里如何验证human,并将human转成正确的子类
return human.echo();
}
}
这种例子有很多,比如
- DB Connection可以是host, port的对象,也可以是一个uri连接字符串,或者sqlite那种包含database文件名的
- 用户设备可以是UserAgent格式的字符串,或者包含device, platform, version的对象
- 一本书可以是一个ISBN号码,或者包含国家、出版社、版本、年份、名称、作者的对象
如果是子类,我理解就是面向不同 DTO 的单独校验了,直接在装饰器上做并不是适合了,还是要靠 validateService 的 API 来单独校验了。
对于问题1,我现在有个办法就是给Human增加一个type
字段声明类别,然后用joi.when
判断类型,用getClassMetadata(RULES_KEY, SubClass)
来获取验证规则,以及用class-transformer的discriminator
来转换成实际的子类对象。
class HumanDTO {
@Rule(RuleType.when('human.type', {
switch: [
{
is: 'by-age',
then: RuleType.object(getClassMetadata(RULES_KEY, HumanByAge).meta({ id: HumanByAge.name })
},
{
is: 'by-location',
then: RuleType.object(getClassMetadata(RULES_KEY, HumanByLocation).meta({ id: HumanByLocation.name })
}
],
break: true
}))
@Type(() => Human, {
discriminator: {
property: 'type',
subTypes: [
{ value: HumanByAge, name: 'by-age' },
{ value: HumanByLocation, name: 'by-location' },
]
}
})
human: Human;
}
这个办法有2个问题:
- 必须把
type
内嵌到human
对象里 - 只能使用单一的字段区分子类类型
- 重复写
@Rule
和@Type
规则,分别判断子类,如果@Rule
规则可以自动使用@Type
转换过的子类上的验证规则就好了
如果是子类,我理解就是面向不同 DTO 的单独校验了,直接在装饰器上做并不是适合了,还是要靠 validateService 的 API 来单独校验了。
我觉得Joi已经提供了类似的验证机制,能不能跟class-transformer再整合一下,让DTO的验证更方便一些呢