使用Joi
验证用户在Node.js RESTapi中的输入似乎非常简单。
但问题是我的应用程序不是用英文写的。 这意味着我需要向前端用户发送自定义书面消息。
我已经搜索过此内容并且只发现了问题。
也许有人可以为此提供解决方案?
这是我用来验证Joi
系统的代码:
var schema = Joi.object().keys({
firstName: Joi.string().min(5).max(10).required(),
lastName: Joi.string().min(5).max(10).required()
..
});
Joi.validate(req.body, schema, function(err, value) {
if (err) {
return catched(err.details);
}
});
function catched(reject) {
res.json({
validData: false,
errors: reject
});
}
另外,有没有办法在客户端使用Joi
?
谢谢!
答案 0 :(得分:12)
我找到的解决方案是设置:
var schema = Joi.object().keys({
firstName: Joi.string().min(5).max(10).required().label("Your error message in here"),
lastName: Joi.string().min(5).max(10).required()
..
});
然后从回调label
变量
error
答案 1 :(得分:11)
Joi版本14.0.0
const SchemaValidation = {
coins: Joi.number()
.required()
.error(errors => {
return {
message: "Coins is required."
};
}),
challenge_name: Joi.string()
.required()
.error(errors => {
return {
message: "Challenge name is required."
};
}),
challengeType: Joi.string()
.required()
.error(errors => {
return {
message: "Challenge type is required."
};
}),
challengeDescription: Joi.string()
.required()
.error(errors => {
return {
message: "Challenge description is required."
};
})
};
在错误对象中,您可以获取,错误类型和更改消息。
答案 2 :(得分:8)
您可以使用 .error(新错误('消息')),并为我工作
var schema = Joi.object().keys({
firstName: Joi.string().min(5).max(10).required().error(new Error('Give your error message here for first name')),
lastName: Joi.string().min(5).max(10).required().error(new Error('Give your error message here for last name'))
..
});
Joi.validate(req.body, schema, function(err, value) {
if (err) {
console.log(err.message)
return catched(err.message);
}
});
答案 3 :(得分:7)
扩展到Ashish Kadam's answer上,如果您有许多不同的错误类型,则可以检查存在的错误类型,并相应地设置其消息:
var schema = Joi.object().keys({
firstName: Joi.string().min(5).max(10).required().error(errors => {
errors.forEach(err => {
switch (err.type) {
case "any.empty":
err.message = "Value should not be empty!";
break;
case "string.min":
err.message = `Value should have at least ${err.context.limit} characters!`;
break;
case "string.max":
err.message = `Value should have at most ${err.context.limit} characters!`;
break;
default:
break;
}
});
return errors;
}),
// ...
});
您可以在此处查看错误列表:Joi 14.3.1 API Reference > Errors > List of errors
您还可以查看any.error
参考资料以获取更多信息。引用文档:
如果规则在以下位置失败,则使用自定义错误覆盖默认的joi错误:
err
可以是:
Error
的实例-覆盖错误。- 一个
function(errors)
,以错误数组作为参数,它必须是:
- 返回
string
-用该文本替换错误消息- 返回单个
object
或其中的Array
,其中:
type
-提供错误类型的可选参数(例如number.min
)。message
-可选参数,如果提供了template
,则包含错误文本。template
-可选参数,如果提供了message
,其中包含模板字符串,其格式与通常的joi语言错误相同。context
-可选参数,用于在使用template
时为错误提供上下文。- 返回
Error
-与直接提供Error
时相同,但是您可以根据错误来自定义错误消息。options
:
self
-布尔值,指示是将错误处理程序用于所有错误还是仅用于此属性上发生的错误(true
值)。该概念仅对array
或object
模式有意义,因为其他值没有子代。默认为false
。
答案 4 :(得分:3)
let schema = Joi.object({ foo:Joi.number()。min(0) .error(()=>'" foo"需要正数') });
文档link
答案 5 :(得分:3)
当前的方法(我个人认为更好)是使用.messages()
(或.prefs({messages})
)。
const Joi = require('@hapi/joi');
const joiSchema = Joi.object({
a: Joi.string()
.min(2)
.max(10)
.required()
.messages({
'string.base': `"a" should be a type of 'text'`,
'string.empty': `"a" cannot be an empty field`,
'string.min': `"a" should have a minimum length of {#limit}`,
'any.required': `"a" is a required field`
})
});
const validationResult = joiSchema.validate({ a: 2 }, { abortEarly: false });
console.log(validationResult.error); // expecting ValidationError: "a" should be a type of 'text'
.errors()
的使用是not recommended,仅用于使用自定义消息更新默认消息。
.prefs({ messages })
是提供更多选项作为首选项的一种精心设计的方法。首选项的其他选项直接来自.validate()
进一步阅读:https://github.com/hapijs/joi/issues/2158
更新:我看到上述解释对某些人没有用,所以我提供了一些代码来测试自己。在这里检查:https://runkit.com/embed/fnfaq3j0z9l2
还更新了以前共享的代码段,以提供从包包含,使用到调用实际验证方法的详细信息。
答案 6 :(得分:3)
您还可以显示特定属性的消息
const Joi = require('Joi');
const schema = Joi.object({
username: Joi.string()
.min(2)
.max(30)
.required()
.pattern(new RegExp(/^(?!.*\.\.)(?!.*\.$)[^\W][\w.]{0,29}$/))
.message({"string.pattern.base":"Invalid username",
"string.min":"minimum 2 character required",
"string.max":"maximum 30 characters allowed"})
});
您可以参考此消息对象键。
messages: {
'any.custom': [Object],
'any.default': [Object],
'any.failover': [Object],
'any.invalid': [Object],
'any.only': [Object],
'any.ref': [Object],
'any.required': [Object],
'any.unknown': [Object],
'string.alphanum': [Object],
'string.base': [Object],
'string.base64': [Object],
'string.creditCard': [Object],
'string.dataUri': [Object],
'string.domain': [Object],
'string.email': [Object],
'string.empty': [Object],
'string.guid': [Object],
'string.hex': [Object],
'string.hexAlign': [Object],
'string.hostname': [Object],
'string.ip': [Object],
'string.ipVersion': [Object],
'string.isoDate': [Object],
'string.isoDuration': [Object],
'string.length': [Object],
'string.lowercase': [Object],
'string.max': [Object],
'string.min': [Object],
'string.normalize': [Object],
'string.token': [Object],
'string.pattern.base': [Object],
'string.pattern.name': [Object],
'string.pattern.invert.base': [Object],
'string.pattern.invert.name': [Object],
'string.trim': [Object],
'string.uri': [Object],
'string.uriCustomScheme': [Object],
'string.uriRelativeOnly': [Object],
'string.uppercase': [Object]
}
答案 7 :(得分:1)
添加自定义消息的解决方案: 只需添加另一个链式函数即可在定义架构时抛出错误 在你的情况下
firstName: Joi.string().min(5).max(10).required().error(new Error('I am a custom error and I know it!')),
休息将保持不变。
在客户端使用Joi的解决方案(您的第二个问题)
Joi-Browser 是允许在客户端使用相同模式的包。
Here是一个有趣的讨论,你可以看看。
干杯!
答案 8 :(得分:1)
在最新版本中,将消息用作。
var schema = Joi.object().keys({
firstName: Joi.string().min(5).max(10).required().messages({
"string.base": `"username" should be a type of 'text'`,
"string.empty": `"username" cannot be an empty field`,
"any.required": `"username" is a required.`,
}),
lastName: Joi.string().min(5).max(10).required().messages({
"string.base": `"lastName" should be a type of 'text'`,
"string.empty": `"lastName" cannot be an empty field`,
"any.required": `"lastName" is a required.`,
}),
[...]
});
答案 9 :(得分:0)
let schema = Joi.object().keys({
Joi.string().required().options({language: {any: {required: "First name is required"}}})
});
答案 10 :(得分:0)
对于任何人
有问题...消息不是功能
错误,必须将joi
与npm install @hapi/joi
一起安装,并使用@hapi/joi
导入。我在安装joi
时未加上前缀@hapi/
时犯了一个错误,花了我一段时间才找到错误。
答案 11 :(得分:0)
只需调用“ message()”函数:
firstName: Joi.string().message("Your custom message")
答案 12 :(得分:0)
我发现的最佳解决方案是:
创建用于JOI验证的中间件
Validator.js-您可以创建自定义错误对象
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'Update by Extendoffice: 2020/01/16
Dim xCombox As OLEObject
Dim xStr As String
Dim xWs As Worksheet
Dim xArr
'Combobox
Set xWs = Application.ActiveSheet
On Error Resume Next
Set xCombox = xWs.OLEObjects("ComboBox1")
With xCombox
.ListFillRange = ""
.LinkedCell = ""
.Visible = False
End With
If Target.Validation.Type = 3 Then
Target.Validation.InCellDropdown = False
Cancel = True
xStr = Target.Validation.Formula1
xStr = Right(xStr, Len(xStr) - 1)
If xStr = "" Then Exit Sub
With xCombox
.Visible = True
.Left = Target.Left
.Top = Target.Top
.Width = Target.Width + 5
.Height = Target.Height + 5
.ListFillRange = xStr
If .ListFillRange = "" Then
xArr = Split(xStr, ",")
Me.ComboBox1.List = xArr
End If
.LinkedCell = Target.Address
End With
xCombox.Activate
Me.ComboBox1.DropDown
End If
End Sub
Private Sub ComboBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case 9 'Tab
Application.ActiveCell.Offset(0, 1).Activate
Case 13 'Enter
Application.ActiveCell.Offset(1, 0).Select
Exit Sub
End Select
End Sub
Private Sub ComboBox2_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case 9
Application.ActiveCell.Offset(0, 1).Activate
Case 13
Application.ActiveCell.Offset(1, 0).Activate
End Select
End Sub
Private Sub ComboBox2Description(Target As Range)
Dim xCombox As OLEObject
Dim xStr As String
Dim xWs As Worksheet
Dim xArr
Set xWs = Application.ActiveSheet
On Error Resume Next
Set xCombox = xWs.OLEObjects("ComboBox2")
With xCombox
.ListFillRange = ""
.LinkedCell = ""
.Visible = False
End With
If Target.Validation.Type = 3 Then
Target.Validation.InCellDropdown = False
Cancel = True
With xCombox
.Visible = True
.Left = Target.Left
.Top = Target.Top
.Width = Target.Width + 5
.Height = Target.Height + 5
.ListFillRange = "UniqueForDescriptionDropdown"
.LinkedCell = Target.Address
End With
xCombox.Activate
Me.ComboBox2.DropDown
End If
End Sub
'Private Sub ComboBox1_LostFocus()
'Me.ComboBox1.Visible = False
'End Sub
Private Sub ComboBox2_LostFocus()
Me.ComboBox2.Visible = False
End Sub
在路由或控制器中传递此中间件功能
const Joi = require('Joi');
module.exports = schema => (req, res, next) => {
const result = Joi.validate(req.body, schema);
if (result.error) {
return res.status(422).json({
errorCause: result.error.name,
missingParams: result.error.details[0].path,
message: result.error.details[0].message
});
}
next();
};
答案 13 :(得分:0)
我不得不深入研究 source 以找到一个示例,说明如何对消息进行上下文相关模板/格式设置,因为它似乎没有记录:
messages: {
'string.alphanum': '{{#label}} must only contain alpha-numeric characters',
'string.base': '{{#label}} must be a string',
'string.base64': '{{#label}} must be a valid base64 string',
'string.creditCard': '{{#label}} must be a credit card',
'string.dataUri': '{{#label}} must be a valid dataUri string',
'string.domain': '{{#label}} must contain a valid domain name',
'string.email': '{{#label}} must be a valid email',
'string.empty': '{{#label}} is not allowed to be empty',
'string.guid': '{{#label}} must be a valid GUID',
'string.hex': '{{#label}} must only contain hexadecimal characters',
'string.hexAlign': '{{#label}} hex decoded representation must be byte aligned',
'string.hostname': '{{#label}} must be a valid hostname',
'string.ip': '{{#label}} must be a valid ip address with a {{#cidr}} CIDR',
'string.ipVersion': '{{#label}} must be a valid ip address of one of the following versions {{#version}} with a {{#cidr}} CIDR',
'string.isoDate': '{{#label}} must be in iso format',
'string.isoDuration': '{{#label}} must be a valid ISO 8601 duration',
'string.length': '{{#label}} length must be {{#limit}} characters long',
'string.lowercase': '{{#label}} must only contain lowercase characters',
'string.max': '{{#label}} length must be less than or equal to {{#limit}} characters long',
'string.min': '{{#label}} length must be at least {{#limit}} characters long',
'string.normalize': '{{#label}} must be unicode normalized in the {{#form}} form',
'string.token': '{{#label}} must only contain alpha-numeric and underscore characters',
'string.pattern.base': '{{#label}} with value {:[.]} fails to match the required pattern: {{#regex}}',
'string.pattern.name': '{{#label}} with value {:[.]} fails to match the {{#name}} pattern',
'string.pattern.invert.base': '{{#label}} with value {:[.]} matches the inverted pattern: {{#regex}}',
'string.pattern.invert.name': '{{#label}} with value {:[.]} matches the inverted {{#name}} pattern',
'string.trim': '{{#label}} must not have leading or trailing whitespace',
'string.uri': '{{#label}} must be a valid uri',
'string.uriCustomScheme': '{{#label}} must be a valid uri with a scheme matching the {{#scheme}} pattern',
'string.uriRelativeOnly': '{{#label}} must be a valid relative uri',
'string.uppercase': '{{#label}} must only contain uppercase characters'
}
使用模板化消息的示例:
const Joi = require("joi");
const schema = Joi.object({
nested: Joi.object({
name: Joi.string().required().messages({
"any.required": "{{#label}} is required!!",
"string.empty": "{{#label}} can't be empty!!",
}),
}),
});
const result = schema.validate({
nested: {
// comment/uncomment to see the other message
// name: "",
},
});
console.log(result.error.details);
使用模板语法时,似乎传递的上下文值类似于以下内容,但特定规则/验证器可能会传递更多上下文:
{
key: "name", // this key, without ancestry
label: `"nested.name"`, // full path with dots as separators, in quotes
value: "", // the value that was validated
}