web-dev-qa-db-ja.com

Joi.object()と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()
});
_

2つの違いは何ですか?

4
Berry

@ hapi/joiのドキュメント は、これについてはあまり明確ではありません(v17.1.0)。結果のスキーマは同じ値を持ち、同じ検証を行います。ソースを見ると、オブジェクトタイプはKeysタイプであり、オブジェクトが定義されている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
_
1
Marko Kohtala

次のように、key()を使用せずにスキーマを定義することもできます。

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()を使用

前述したように、単一のキーセットを定義する場合、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の値を期待するチェックボックスやその他のスイッチのテストに役立ちます。

0
Avid Programmer