有没有办法将两个joi架构合并为一个架构?
架构1
{
alpha: Joi.number().required(),
beta: Joi.string().required(),
chalie: Joi.object({
xray: Joi.number().required(),
}).required()
}
架构1
{
delta: Joi.string().required(),
echo: Joi.number().required(),
charlie: Joi.object({
zulu: Joi.string().required(),
}).required()
}
合并架构:
{
alpha: Joi.number().required(),
beta: Joi.string().required(),
chalie: Joi.object({
xray: Joi.number().required(),
zulu: Joi.string().required(),
}).required()
delta: Joi.string().required(),
echo: Joi.number().required(),
}
没有嵌套对象,可以使用Object.assign
轻松完成,但即使深层对象合并也不能与嵌套对象一起使用,因为嵌套对象是一个函数调用。
答案 0 :(得分:5)
使用普通的javascript对象不是我的选择。我尝试使用.keys
方法进行扩展,但它会覆盖现有密钥(在本例中为查理)。
我确定的解决方案是使用.reach
:
例如:
const Joi = require('joi');
const originalSchema = Joi.object({
a: {
deep: {
b: Joi.string()
}
},
c: Joi.string()
});
const extendedSchema = Joi.object({
a: {
deep: Joi
.reach(originalSchema, 'a.deep')
.keys({ anotherB: Joi.string() })
},
c: Joi.reach(originalSchema, 'c')
});
// No errors
extendedSchema.validate({ a: { deep: { b: 'hi', anotherB: 'hi' } }, c: 'wow' })
答案 1 :(得分:1)
您尝试过Joi.append吗?
https://github.com/hapijs/joi/blob/v13.5.2/API.md#objectkeysschema
// Validate key a
const base = Joi.object().keys({
a: Joi.number()
});
// Validate keys a, b.
const extended = base.append({
b: Joi.string()
});
答案 2 :(得分:1)
Joi.object()
和扩展运算符 ...
帮我解决了这个问题。 (Joi 17 版)
import * as Joi from 'joi'
const childSchema: {
PORT: Joi.number(),
}
const parentSchema = Joi.object({
NODE_ENV: Joi.string(),
APP_NAME: Joi.string(),
...childSchema,
})
答案 3 :(得分:1)
这是@szanata 答案的扩展,这是合并用于验证请求正文的多个模式的工作示例。我将它创建为路由的中间件,有时最多有 3 个模式来验证请求正文。您可以传递单个架构或架构数组。
const validateRequest = (schema) => {
return (req, res, next) => {
if(Array.isArray(schema)){
let schemas = schema;
schema = schemas[0]
schemas.forEach((s, idx) => {
if (idx > 0) schema = schema.concat(s);
});
}
let data = { ...req.body, ...req.query, ...req.params };
const { error } = schema.validate(data, options);
if (error) res.status(422).json({msg:`${error.details.map((x) => x.message).join(", ")}`})
else next();
}
}
用作路由中间件的示例:
const { query, mongoDbId, test } = require("../utils/validation-schema");
const router = express.Router();
router.post("/test", protect, validateInput([mongoDbId, test, query]),
(req, res) => {
res.json({ msg: "OK" });
});
concat 后 console.log(schema._ids) 的输出。
{
_byId: Map {},
_byKey: Map {
'_id' => { schema: [Object], id: '_id' },
'databaseType' => { schema: [Object], id: 'databaseType' },
'host' => { schema: [Object], id: 'host' },
'database' => { schema: [Object], id: 'database' },
'user' => { schema: [Object], id: 'user' },
'password' => { schema: [Object], id: 'password' },
'datasource' => { schema: [Object], id: 'datasource' },
'sql' => { schema: [Object], id: 'sql' },
'modifier' => { schema: [Object], id: 'modifier' },
'sqlType' => { schema: [Object], id: 'sqlType' },
'format' => { schema: [Object], id: 'format' },
'timeout' => { schema: [Object], id: 'timeout' }
},
_schemaChain: false
}
答案 4 :(得分:0)
我想知道同一件事,因为我想合并两个不同的模式,并发现了这一点:https://github.com/hapijs/joi/blob/v9.0.4/API.md#anyconcatschema
const a = Joi.string().valid('a');
const b = Joi.string().valid('b');
const ab = a.concat(b);
希望对您有帮助
答案 5 :(得分:0)
我不喜欢这里的任何答案,所以我找到了另一种方法。我创建了一个类,以便可以为一个项目设置一条规则,例如电子邮件地址或密码,该规则具有针对需求的单一起点,而不是在不同文件中设置多个架构。甚至单个文件/类中的多个半冗余架构。
值得一提的是,如果第一个规则为空,则.append无效。这就是.concat出现的地方。
首先,我建立了一个包含几个单项规则的类
//an email address
static emailAddress = Joi.object({
emailAddress: Joi.string()
.email({ tlds: { allow: false } })
.required()
.label("Email Address"),
});
static passwordRegex = /^(?=.*[A-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])\S{8,}$/;
static passwordError =
"Password must be at least 8 characters long, and have at least one uppercase letter, one lowercase letter, one number, and one special character.";
//a password
static password = Joi.object({
password: Joi.string()
.min(8)
.regex(this.passwordRegex)
.message(this.passwordError)
.label("Password"),
});
然后,我为需要检查的特定对象创建了一些规则。
static registerUserSchema() {
let schema = Joi.object()
.concat(this.yourNameSchema)
.concat(this.emailAddress)
.concat(this.password)
.concat(this.confirmPassword);
return schema;
}
永远带我去弄清楚,但这无可挑剔。
答案 6 :(得分:-1)
虽然您可以使用Javascript' Object.assign()
,但我认为您正在寻找的是Joi的.keys()
功能。
在您的代码中,我会:
const schema1 = Joi.object({
alpha: Joi.number().required(),
beta: Joi.string().required(),
charlie: Joi.object({
xray: Joi.number().required(),
}).required()
});
const schema2 = Joi.object({
delta: Joi.string().required(),
echo: Joi.number().required(),
charlie: Joi.object({
zulu: Joi.string().required(),
}).required()
});
const mergedSchema = schema1.keys(schema2);
还有一个interesting note关于使用直接JS对象与将它们包装在Joi.object()
中;
使用{}表示法时,您只是定义一个普通的JS对象,它不是一个架构对象。您可以将它传递给验证方法,但是您不能调用该对象的validate()方法,因为它只是一个普通的JS对象。
此外,每次将{}对象传递给validate()方法,都会在每次验证时执行昂贵的模式编译操作。
当你使用Joi.object([schema])时,它会在第一次被编译,所以你可以多次将它传递给validate()方法,并且不会增加任何开销。
所以你可以采用Ankh's建议并使用直接的JS对象:
const schema1 = {
alpha: Joi.number().required(),
beta: Joi.string().required(),
charlie: Joi.object({
xray: Joi.number().required(),
}).required()
};
const schema2 ={
delta: Joi.string().required(),
echo: Joi.number().required(),
charlie: Joi.object({
zulu: Joi.string().required(),
}).required()
};
const mergedSchema = Object.assign({}, schema1, schema2);
但是存在相关的性能损失。
答案 7 :(得分:-2)
https://github.com/hapijs/joi/blob/v15.0.1/API.md#objectappendschema
object.append([schema]) 在以下位置附加允许的对象键:
schema-可选对象,其中为每个键分配了一个joi类型的对象。如果架构为null,undefined或{},则不会应用任何更改。使用object.keys([schema])附加键。
// Validate key a const base = Joi.object().keys({ a: Joi.number() }); // Validate keys a, b. const extended = base.append({ b: Joi.string() });