如何在 nest.js 应用程序的 REST API 上验证动态 属性-name?
How to validate dynamic property-name on REST API in nest.js app?
任务是在管理 nest.js
应用程序之前验证有效负载。
每个负载可以包含 tag
个对象 (1 - 11)。
每个tag object
只能有一个属性和值(属性由请求决定)
应验证标记对象:
- 属性 应该是一个字符串,任何字符都接受
:
并且大小在 1-255 之间
- value 应该是大小在 1-255 之间的字符串
任务看起来很简单。但我不知道如何验证 Tag
对象中动态构造的属性。
DTO 是(使用 class-validator
配置的验证):
import {
ArrayMaxSize,
ArrayMinSize,
IsArray,
IsDefined,
IsNotEmpty,
IsObject,
IsString,
Matches,
MinLength,
ValidateNested
} from 'class-validator';
export class Payload {
...
@IsArray()
@ArrayMinSize(1)
@ArrayMaxSize(11)
@ValidateType(() => Tag)
@ValidateNested()
@ApiProperty()
tags: Tag[];
}
为了使 Tag
灵活(因为未知 属性 名称)它使 Map
扩展
export class Tag extends Map<string, string>{
}
或单个字段对象
export class Tag {
[key: string]: string;
}
如何管理每个 Tag
所需的验证?
(排除带有 :
的输入的正则表达式是 /^[^:]+$/
,应该应用于 key
)
我有解决方案,但比解决方案实施比较可能的方法更好。
1 个场景
是在 tags
字段
上放置额外的自定义验证装饰器
@IsPropertyNameLength(1, 250,{ each: true })
@IsPropertyNameMatches(/^[^:]+$/,{ each: true })
@IsPropertyNameString({ each: true })
@IsKeyNameLength(1, 250,{ each: true })
@IsKeyNameMatches(/\w+|\d+/,{ each: true })
@IsKeyNameString({ each: true })
tags: Tag[];
这可能是个不错的解决方案。按照这种方式,我们会意识到装饰器名称没有带来足够的信息。为了使它们更通用,我们可以添加更多参数。但是这种改进不能改变我们验证的不是当前级别或下一级 属性 的事实。我们在下一个级别(tags[]
-> Tag
-> theProperty
)之后对 属性 进行验证。
2个场景
是管理中间件层的验证。如果你想让报告具有相同的格式并遵循 class-validator
中提供的类似流程,这可能会带来一些困难,但好处是我们可以在构建更复杂的验证树的不同方法上进行验证。也方便测试。
3个场景
是拒绝动态 属性 名称(如果可能的话)并考虑开发替代模型,例如
export class Tag {
key: string;
value: string;
}
它让我们有机会使用 class-validator
提供的装饰器来满足我们的需要,例如
export class Tag {
@Length(1, 250)
@Matches(/^[^:]+$/)
key: string;
@Length(1, 250)
@Matches(/\w+|\d+/)
value: string;
}
P.S.
我已经按照第三种方式管理了我的解决方案。
任务是在管理 nest.js
应用程序之前验证有效负载。
每个负载可以包含 tag
个对象 (1 - 11)。
每个tag object
只能有一个属性和值(属性由请求决定)
应验证标记对象:
- 属性 应该是一个字符串,任何字符都接受
:
并且大小在 1-255 之间
- value 应该是大小在 1-255 之间的字符串
任务看起来很简单。但我不知道如何验证 Tag
对象中动态构造的属性。
DTO 是(使用 class-validator
配置的验证):
import {
ArrayMaxSize,
ArrayMinSize,
IsArray,
IsDefined,
IsNotEmpty,
IsObject,
IsString,
Matches,
MinLength,
ValidateNested
} from 'class-validator';
export class Payload {
...
@IsArray()
@ArrayMinSize(1)
@ArrayMaxSize(11)
@ValidateType(() => Tag)
@ValidateNested()
@ApiProperty()
tags: Tag[];
}
为了使 Tag
灵活(因为未知 属性 名称)它使 Map
扩展
export class Tag extends Map<string, string>{
}
或单个字段对象
export class Tag {
[key: string]: string;
}
如何管理每个 Tag
所需的验证?
(排除带有 :
的输入的正则表达式是 /^[^:]+$/
,应该应用于 key
)
我有解决方案,但比解决方案实施比较可能的方法更好。
1 个场景
是在 tags
字段
@IsPropertyNameLength(1, 250,{ each: true })
@IsPropertyNameMatches(/^[^:]+$/,{ each: true })
@IsPropertyNameString({ each: true })
@IsKeyNameLength(1, 250,{ each: true })
@IsKeyNameMatches(/\w+|\d+/,{ each: true })
@IsKeyNameString({ each: true })
tags: Tag[];
这可能是个不错的解决方案。按照这种方式,我们会意识到装饰器名称没有带来足够的信息。为了使它们更通用,我们可以添加更多参数。但是这种改进不能改变我们验证的不是当前级别或下一级 属性 的事实。我们在下一个级别(tags[]
-> Tag
-> theProperty
)之后对 属性 进行验证。
2个场景
是管理中间件层的验证。如果你想让报告具有相同的格式并遵循 class-validator
中提供的类似流程,这可能会带来一些困难,但好处是我们可以在构建更复杂的验证树的不同方法上进行验证。也方便测试。
3个场景 是拒绝动态 属性 名称(如果可能的话)并考虑开发替代模型,例如
export class Tag {
key: string;
value: string;
}
它让我们有机会使用 class-validator
提供的装饰器来满足我们的需要,例如
export class Tag {
@Length(1, 250)
@Matches(/^[^:]+$/)
key: string;
@Length(1, 250)
@Matches(/\w+|\d+/)
value: string;
}
P.S.
我已经按照第三种方式管理了我的解决方案。