简体   繁体   English

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

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

According to Joi documentation, you can use Joi.object() like so:根据 Joi 文档,您可以像这样使用Joi.object()

const object = Joi.object({
    a: Joi.number().min(1).max(10).integer(),
    b: Joi.any()
});

But you can also write an equivalent code using Joi.object().keys() like so:但是您也可以使用Joi.object().keys()编写等效代码,如下所示:

const object = Joi.object().keys({
    a: Joi.number().min(1).max(10).integer(),
    b: Joi.any()
});

What's the difference between the two?两者有什么区别?

If you're writing your schema once then you do not need to use .keys() .如果您编写一次架构,则不需要使用.keys() As their docs say it is "useful" to use .keys() when added more lines (keys) to your object.正如他们的文档所说,向 object 添加更多行(键)时使用.keys()是“有用的”。

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

This is basically the same as Joi.object([schema]) , but using Joi.object().keys([schema]) is more useful when you want to add more keys (eg call keys() multiple times).这与Joi.object([schema])基本相同,但是当您想要添加更多键时(例如多次调用keys() ),使用Joi.object().keys([schema])更有用。 If you are only adding one set of keys, you can skip the keys() method and just use object() directly.如果只添加一组键,则可以跳过keys()方法,直接使用object()

Some people like to use keys() to make the code more explicit (this is style only).有些人喜欢使用keys()来使代码更明确(这只是样式)。

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


I also found this:我还发现了这个:

There are many ways to use joi.使用 joi 的方法有很多。 The hapi docs can't show everything. hapi 文档无法显示所有内容。 Calling keys() is only recommended when adding keys to an object as it creates another schema仅在将密钥添加到 object 时才建议调用 keys(),因为它会创建另一个模式

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

The @hapi/joi documentation is not very clear on this (at v17.1.0). @hapi/joi 文档对此不是很清楚(在 v17.1.0 中)。 The resulting schemas have the same value, and they validate the same.生成的模式具有相同的值,并且它们验证相同。 Looking at the source, Object type is a Keys type with only a change that object need not copy keys from the Any type it is defined from.查看源代码,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: {} }

Difference between the .append(schema) and .keys(schema) is also unclear in documentation. .append(schema).keys(schema)之间的区别在文档中也不清楚。 The .append(schema) does not create a new copy if schema is empty, but otherwise it just returns the value from .keys(schema) .如果 schema 为空, .append(schema)不会创建新副本,否则它只会返回.keys(schema)的值。 I found no example where this would make a difference.我没有发现这会有所作为的例子。

> 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

Like the documentation states:如文档所述:

object.keys([schema]) object.keys([架构])

Sets OR extends the allowed object keys where:设置扩展允许的 object 键,其中:

  • schema - optional object where each key is assigned a joi type object. schema - 可选 object,其中每个键都分配有一个 joi 类型 object。 If schema is {} no keys allowed.如果架构是 {},则不允许使用任何键。 If schema is null or undefined, any key allowed.如果架构是 null 或未定义,则允许任何键。 If schema is an object with keys, the keys are added to any previously defined keys (but narrows the selection if all keys previously allowed).如果 schema 是带有键的 object,则将键添加到任何先前定义的键(但如果先前允许所有键,则缩小选择范围)。

Thus by calling Joi.object() you first create a schema that allows any keys and then by calling .keys([schema]) you extend that schema (basically the same as defining a new schema with Joi.object([schema]) )因此,通过调用Joi.object()您首先创建一个允许任何键的模式,然后通过调用.keys([schema])扩展该模式(基本上与使用Joi.object([schema]) )

So these two are equivalent:所以这两个是等价的:

const a = Joi.object({ firstName: Joi.string() });
const b = Joi.object().keys({ firstName: Joi.string() });

You can also extend both schemas created above:您还可以扩展上面创建的两个模式:

const aExtended = a.keys({ lastName: Joi.string() })
const bExtended = b.keys({ lastName: Joi.string() })

Which one to use then?那该用哪一个呢?

Like stated in the previous answers, sometimes also top level schemas are created using .keys() for code consistency reasons, but in the end I think it's a matter of personal preference.就像前面的答案中所述,有时出于代码一致性的原因,使用.keys()创建顶级模式,但最后我认为这是个人喜好问题。

We can also define schema without using keys() when there is only one set of keys define our schema directly within the object() generation, like so:当只有一组键直接在 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');

So why use keys() with a single key set?那么为什么要使用带有单个键集的 keys() 呢?

To keep your code consistent.保持你的代码一致。 Throughout the Joi documentation keys() are used throughout, even on single key objects.在整个 Joi 文档中,甚至在单个键对象上都使用了 keys()。

Using keys()使用键()

As we mentioned before, keys() does not have to be used if we are defining a single key set.正如我们之前提到的,如果我们定义单个键集,则不必使用 keys()。 Additionally, if no keys are defined on a Joi.object(), then any key will be valid: there are no rules to invalidate any object we test with our Joi schema.此外,如果在 Joi.object() 上没有定义任何键,那么任何键都是有效的:没有规则可以使我们使用 Joi 模式测试的任何 object 无效。 We also have the option to add keys after the schema's original definition.我们还可以选择在模式的原始定义之后添加键。 The following example taken from the Joi documentation demonstrates this:以下来自 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()
});

As you may have noticed, we are defining constants here.您可能已经注意到,我们在这里定义常量。 Joi objects are immutable, so extending a base schema will result in a completely new object. Joi 对象是不可变的,因此扩展基本模式将产生全新的 object。 Here we have saved that object as the constant extended.在这里,我们将 object 保存为常量扩展。 We have also introduced the Joi.boolean() rule above, which comes in handy for testing checkboxes and other switches, where we expect a true or false value.我们还介绍了上面的 Joi.boolean() 规则,它在测试复选框和其他开关时非常方便,我们需要一个真或假值。

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

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