Joi.object() 和 Joi.object().keys() 有啥区别?
Posted
技术标签:
【中文标题】Joi.object() 和 Joi.object().keys() 有啥区别?【英文标题】:What is the difference between Joi.object() and Joi.object().keys()?Joi.object() 和 Joi.object().keys() 有什么区别? 【发布时间】:2020-03-07 17:45:04 【问题描述】:根据 Joi 文档,您可以像这样使用Joi.object()
:
const object = Joi.object(
a: Joi.number().min(1).max(10).integer(),
b: Joi.any()
);
但您也可以使用Joi.object().keys()
编写等效代码,如下所示:
const object = Joi.object().keys(
a: Joi.number().min(1).max(10).integer(),
b: Joi.any()
);
两者有什么区别?
【问题讨论】:
两者不等价。第一个示例定义了一个只允许a
和b
的模式。使用object()
的第二个示例使用Joi.any()
作为初始模式,然后通过添加a
和b
的定义来扩展它,同时可能继承any
的许可模式定义。你可能不想扩展any
,除非你知道你正在处理开放式输入。
【参考方案1】:
如果您只编写一次架构,则无需使用.keys()
。正如他们的文档所说,在向对象添加更多行(键)时使用 .keys()
是“有用的”。
Joi.object().keys([schema]) notation
这与
Joi.object([schema])
基本相同,但是当您想添加更多键时使用Joi.object().keys([schema])
更有用(例如多次调用keys()
)。如果只添加一组键,可以跳过keys()
方法,直接使用object()
即可。有些人喜欢使用
keys()
使代码更明确(这只是样式)。
取自:https://github.com/hapijs/joi/blob/v8.0.3/API.md#joiobjectkeysschema-notation
我还发现了这个:
有很多方法可以使用 joi。 hapi 文档无法显示所有内容。仅在向对象添加键时才建议调用 keys(),因为它会创建另一个模式
取自:https://github.com/hapijs/hapi/issues/2222
【讨论】:
【参考方案2】:如文档所述:
object.keys([schema])
设置 OR 扩展允许的对象键,其中:
schema - 可选对象,其中每个键都分配有一个 joi 类型对象。如果架构是 ,则不允许使用任何键。如果 schema 为 null 或未定义,则允许任何键。 如果架构是一个带有键的对象,则这些键将添加到任何先前定义的键中(但如果先前允许所有键,则会缩小选择范围)。
因此,通过调用Joi.object()
,您首先创建一个允许任何键的架构,然后通过调用.keys([schema])
,您扩展该架构(基本上与使用Joi.object([schema])
定义新架构相同)
所以这两个是等价的:
const a = Joi.object( firstName: Joi.string() );
const b = Joi.object().keys( firstName: Joi.string() );
您还可以扩展上面创建的两个模式:
const aExtended = a.keys( lastName: Joi.string() )
const bExtended = b.keys( lastName: Joi.string() )
那该用哪一个呢?
如前面的答案所述,出于代码一致性原因,有时也使用.keys()
创建***架构,但最后我认为这是个人喜好问题。
【讨论】:
【参考方案3】:@hapi/joi documentation 对此不是很清楚(在 v17.1.0 中)。生成的模式具有相同的值,并且它们验证相同。查看源代码,Object 类型是 Keys 类型,只有一个更改,即 object 不需要从定义它的 Any 类型复制键。
Welcome to Node.js v12.16.1.
Type ".help" for more information.
> const Joi = require('@hapi/joi')
undefined
> const util = require('util')
undefined
> const object1 = Joi.object(
... a: Joi.number().min(1).max(10).integer(),
... b: Joi.any()
... );
undefined
> const object2 = Joi.object().keys(
... a: Joi.number().min(1).max(10).integer(),
... b: Joi.any()
... );
undefined
> util.format(object1) == util.format(object2)
true
> object1.validate(a: 1, b: 1)
value: a: 1, b: 1
> object2.validate(a: 1, b: 1)
value: a: 1, b: 1
> object1.validate(a: 0)
value: a: 0 ,
error: [Error [ValidationError]: "a" must be larger than or equal to 1]
_original: a: 0 ,
details: [ [Object] ]
> object2.validate(a: 0)
value: a: 0 ,
error: [Error [ValidationError]: "a" must be larger than or equal to 1]
_original: a: 0 ,
details: [ [Object] ]
> object1.validate(a: 1, b: 1, c:1)
value: a: 1, b: 1, c: 1 ,
error: [Error [ValidationError]: "c" is not allowed]
_original: a: 1, b: 1, c: 1 ,
details: [ [Object] ]
> object2.validate(a: 1, b: 1, c:1)
value: a: 1, b: 1, c: 1 ,
error: [Error [ValidationError]: "c" is not allowed]
_original: a: 1, b: 1, c: 1 ,
details: [ [Object] ]
> object1.validate(a: 1)
value: a: 1
> object2.validate(a: 1)
value: a: 1
> object1.validate(b: 1)
value: b: 1
> object2.validate(b: 1)
value: b: 1
> object1.validate()
value:
> object2.validate()
value:
.append(schema)
和 .keys(schema)
之间的区别在文档中也不清楚。如果架构为空,.append(schema)
不会创建新副本,否则它只会返回来自.keys(schema)
的值。我没有发现这会产生影响的示例。
> util.format(Joi.object().keys(a:1)) == util.format(Joi.object().append(a:1))
true
> util.format(Joi.object().unknown().keys(a:1)) == util.format(Joi.object().unknown().append(a:1))
true
【讨论】:
【参考方案4】:当只有一组键时,我们也可以不使用 keys() 来定义模式 直接在 object() 生成中定义我们的模式,如下所示:
const schema = Joi.object(
username: Joi.string().alphanum().min(3).max(16).required(),
password: Joi.string().regex(/^[a-zA-Z0-9]3,30$/).min(6).required()
).with('username', 'password');
那么为什么要将 keys() 与单个键集一起使用?
保持您的代码一致。在整个 Joi 文档中,甚至在单个键对象上都使用了 keys()。
使用键()
正如我们之前提到的,如果我们定义单个键集,则不必使用 keys()。此外,如果在 Joi.object() 上没有定义任何键,那么任何键都是有效的:没有规则可以使我们使用 Joi 模式测试的任何对象无效。 我们还可以选择在模式的原始定义之后添加键。以下来自 Joi 文档的示例演示了这一点:
//define base object
const base = Joi.object().keys(
a: Joi.number(),
b: Joi.string()
);
// add a c key onto base schema
const extended = base.keys(
c: Joi.boolean()
);
您可能已经注意到,我们在这里定义了常量。 Joi 对象是不可变的,因此扩展基本模式将产生一个全新的对象。在这里,我们将该对象保存为扩展的常量。 我们还引入了上面的 Joi.boolean() 规则,该规则在测试复选框和其他开关时非常方便,我们希望在这些开关中使用 true 或 false 值。
【讨论】:
base.keys()
和base.append()
有什么区别?
所以要明确一点,@Dai 留下的评论是完全错误的?以上是关于Joi.object() 和 Joi.object().keys() 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章