禁止 Nestjs 中 DTO 的特定枚举值
Posted
技术标签:
【中文标题】禁止 Nestjs 中 DTO 的特定枚举值【英文标题】:Forbid specific enum value for DTO in Nestjs 【发布时间】:2020-06-15 17:46:58 【问题描述】:我的“AppState”枚举具有以下可能的枚举值:
export enum AppState
SUCCESS,
ERROR,
RUNNING
我有一个带有appState
的 UpdateAppStateDTO,它应该接受除 RUNNING 之外的所有枚举值。
export class UpdateAppStateDTO
@IsEnum(AppState)
@NotEquals(AppState.RUNNING) // Doesn't work properly
public appState: AppState;
对于路线我有这个例子
@Patch()
public setState(@Body() appState : UpdateAppStateDTO): void
console.log(appState);
如果请求的正文为空或appState
的“foobar”等无效枚举值,我会得到 400,这很好。
问题是当我发送“RUNNING”时,我仍然得到 200 而不是 400。
如何防止这种行为?
【问题讨论】:
【参考方案1】:我假设您发送的是字符串'RUNNING'
,并且您正在尝试确保那是未使用的,对吗?根据您目前所拥有的,您的枚举映射到这些值:
export enum AppState
SUCCESS = 0,
ERROR = 1,
RUNNING = 2
因此,如果您发送字符串'RUNNING'
,验证器会检查RUNNING !== 2
,这实际上是true
,从而导致验证成功。 @IsEnum()
装饰器检查在枚举的有效键中发送的值,因此在 'RUNNING'
中发送通过了该检查,因此您在那里没有收到某种错误。
解决此问题的最详细方法是将您的枚举设置为 string enum
,如下所示:
export enum AppState
SUCCESS = 'SUCCESS',
ERROR = 'ERROR',
RUNNING = 'RUNNING'
这将使每个AppState
值映射到其对应的字符串,但这确实会导致必须输入大量声明并可能导致重复代码。
另一种管理方法是将 @NotEquals()
枚举设置为枚举值提供的键,如下所示:
export class UpdateAppStateDTO
@IsEnum(AppState)
@NotEquals(AppState[AppState.RUNNING])
public appState: AppState;
但请记住,使用这种方法,当您稍后查看appState
时,它仍然是一个数值而不是一个字符串。
您可以使用this stackblitz 我为此制作的以查看一些正在运行的代码。
【讨论】:
【参考方案2】:问题是当我发送“RUNNING”时,我仍然得到 200 而不是 400。
您似乎在请求有效负载中使用字符串(!)“RUNNING”作为值:
appState: "RUNNING"
在这种情况下,IsEnum
和 NotEquals
都认为有效载荷是有效的。
这是为什么呢?
首先numeric enums are reverse mapped by typescript 所以你的枚举在内部(作为javascript对象)表示如下:
'0': 'SUCCESS',
'1': 'ERROR',
'2': 'RUNNING',
'SUCCESS': 0,
'ERROR': 1,
'RUNNING': 2
现在类验证器的isEnum()
is coded as follows:
isEnum(value: unknown, entity: any): boolean
const enumValues = Object.keys(entity)
.map(k => entity[k]);
return enumValues.indexOf(value) >= 0;
由于枚举是反向映射的,isEnum('RUNNNING', AppState)
将返回 true。
同时NotEquals
,其中is coded as such...
notEquals(value: unknown, comparison: unknown): boolean
return value !== comparison;
将字符串“RUNNING”与AppState.RUNNING
(等同于2
)进行比较,并得出结论,自'RUNNING' != 2
以来这是有效的。
所以你知道为什么负载 appState: "RUNNING"
会导致 200 而不是 400 状态代码。
如何防止这种行为?
枚举值AppState.RUNNING
等同于2
,因此当您发出请求时,您应该在有效负载中使用2
的数值:
appState: 2
在上述情况下,类验证器的NotEquals
验证器将正确拒绝请求,响应包含:
"constraints":
"notEquals": "appState should not be equal to 2"
【讨论】:
以上是关于禁止 Nestjs 中 DTO 的特定枚举值的主要内容,如果未能解决你的问题,请参考以下文章