繁体   English   中英

Joi.object() 和 Joi.object().keys() 有什么区别?

[英]What is the difference between Joi.object() and Joi.object().keys()?

根据 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()
});

两者有什么区别?

如果您编写一次架构,则不需要使用.keys() 正如他们的文档所说,向 object 添加更多行(键)时使用.keys()是“有用的”。

Joi.object().keys([schema]) notation

这与Joi.object([schema])基本相同,但是当您想要添加更多键时(例如多次调用keys() ),使用Joi.object().keys([schema])更有用。 如果只添加一组键,则可以跳过keys()方法,直接使用object()

有些人喜欢使用keys()来使代码更明确(这只是样式)。

取自: https://github.com/hapijs/joi/blob/v8.0.3/API.md#joiobjectkeysschema-notation


我还发现了这个:

使用 joi 的方法有很多。 hapi 文档无法显示所有内容。 仅在将密钥添加到 object 时才建议调用 keys(),因为它会创建另一个模式

取自: https://github.com/hapijs/hapi/issues/2222

@hapi/joi 文档对此不是很清楚(在 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)之间的区别在文档中也不清楚。 如果 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

如文档所述:

object.keys([架构])

设置扩展允许的 object 键,其中:

  • schema - 可选 object,其中每个键都分配有一个 joi 类型 object。 如果架构是 {},则不允许使用任何键。 如果架构是 null 或未定义,则允许任何键。 如果 schema 是带有键的 object,则将键添加到任何先前定义的键(但如果先前允许所有键,则缩小选择范围)。

因此,通过调用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()创建顶级模式,但最后我认为这是个人喜好问题。

当只有一组键直接在 object() 生成中定义我们的模式时,我们也可以在不使用 keys() 的情况下定义模式,如下所示:

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 模式测试的任何 object 无效。 我们还可以选择在模式的原始定义之后添加键。 以下来自 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 对象是不可变的,因此扩展基本模式将产生全新的 object。 在这里,我们将 object 保存为常量扩展。 我们还介绍了上面的 Joi.boolean() 规则,它在测试复选框和其他开关时非常方便,我们需要一个真或假值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM