How to set Joi validations with custom messages? - node.js

I was trying to set some validations with some custom messages in Joi. So, for example, I have discovered that when a string must have at least 3 characters we can use "string.min" key and associate this to a custom message. Example:
username: Joi.string().alphanum().min(3).max(16).required().messages({
"string.base": `Username should be a type of 'text'.`,
"string.empty": `Username cannot be an empty field.`,
"string.min": `Username should have a minimum length of 3.`,
"any.required": `Username is a required field.`,
}),
Now here is my question:
Question
// Code for question
repeat_password: Joi.ref("password").messages({
"string.questionHere": "Passwords must match each other...",
}),
What method (questionHere) name need to set to repeat_password to be able to notify the user that passwords must match? I don't even know if Join.ref("something") accept .messages({...})...
If someone could please show me some help in the Joi docs, I haven't find anything yet by there...

What you are trying to find here is the error type. It can be found in the error object that the joi validate function returns. eg: error.details[0].type will give you what you are looking for.
Regarding your second question, Join.ref("something") doesn't accept .messages({...}). Here you can use valid in conjunction with ref.
eg:
const Joi = require('joi');
const schema = Joi.object({
username: Joi.string().alphanum().min(3).max(16).required().messages({
"string.base": `Username should be a type of 'text'.`,
"string.empty": `Username cannot be an empty field.`,
"string.min": `Username should have a minimum length of 3.`,
"any.required": `Username is a required field.`,
}),
password: Joi.string().required(),
password_repeat: Joi.any().valid(Joi.ref('password')).required().messages({
"any.only" : "Password must match"
})
});
const result = schema.validate({ username: 'abc', password: 'pass', password_repeat: 'pass1'});
// In this example result.error.details[0].type is "any.only"

Related

How to set Unique value in mongodb using node express both uper and lower case

Well I have already done in mongoose schema by setting my property with unique:true like below
mongoose.Schema({ userName: { type: String, unique: true }})
this time i want to do it through my router api's
User.findOne({userName: req.body.userName})
it only works when i enter same string as save already in database.like
userName: ranatouseef
but if i enter userName: ranaTouseef it fails,
well regix don't work here like regix also have issue like that well if i search for userName: rana regix find it ranatouseef. well same goes for touseef to well my issu is find same string but without casesensitive,
how can i do that.
In this case, you should set the username in lower case.
new User({ username: req.body.userName.toLowerCase() });
User.save()
And when you want retrieve it, use the toLowerCase method on the argument.
User.findOne({ userName: req.body.userName.toLowerCase() })
You should always avoid to duplicate your data in your DB. Here, you are about to save a string in lowercase and in uppercase. I don't know your use case but it makes no sense to me.
Also, my solution solves the issue of "RanaTouseef" and "ranaTouseef" being 2 unique username

How do I use joi to validate phone numbers in Node.js?

I'd like to use joi in node.js to validate the user's phone number in a schema.
The schema is as follows:
phone: {
type: Number,
unique:true,
},
country code will be default: INDIA(+91). The number will change.
You can use an additional package like that https://www.npmjs.com/package/joi-phone-number
or
You can validate a phone number as a string with a regex like that :
joi.string().regex(/^[0-9]{10}$/).messages({'string.pattern.base': `Phone number must have 10 digits.`}).required()
or
You can extend joi to have an custom validator for phone number validation like that :
Joi.object({
phone: Joi
.string()
.custom((value, helper) => {
// you can use any libs for check phone
if (!checkPhone(value)) {
return helper.message("phone is incorrect")
return value
})
}).validate({
phone: '+79002940163'
});
For more information on custom validations please check : https://joi.dev/api/?v=17.6.0#anycustommethod-description

Remove generated string from Mongoose schema with custom validation

I have a schema with a custom validation.
const schema = new mongoose.Schema({
username: {
type: String,
required: true,
validate: {
validator: /^[a-zA-Z0-9_]{3,16}$/,
message: "Usernames must be 3 to 16 characters long and contain only alphanumeric characters and underscores (_)."
},
},
// ...other things
});
However, the validation message comes out like this when I type an invalid username:
User validation failed: username: Usernames must be 3 to 16 characters long and contain only alphanumeric characters and underscores (_).
How do I get rid of the part of the string at the start that says User validation failed: username: ?
The format is embedded into the ValidationError class. Short of monkey patching that class, I can't see a way to easily change the format.
One option could be to run validation before being thrown by the model:
const user = new User({ username: 'ab' })
const error = user.validateSync()
console.log(error.errors['username'].message)
Or handle ValidationError when caught:
try {
const user = new User({ username: 'ab' })
await user.save()
} catch (error) {
if (error instanceOf mongoose.Document.ValidationError ) {
console.log(error.errors['username'].message)
}
}
To get rid of the initial string , you could simply use a split method on the string returned before displaying it. Here is a sample code:
let stringa = "User validation failed: username: Usernames must be 3 to 16 characters long and contain only alphanumeric characters and underscores (_)."; //replace this with error message
let stringb = (stringa.split(":")[2]);
console.log(stringb);//This displays the needed output string with Usernames
Your error object has another nested object called properties that has a field called message.
(example: properties.message) This gives you the exact string you wrote in the mongoose schema

Message from Yup custom validator returns undefined for the names of path and reference

I am trying to write a custom test for the yup validation library for use in a node/express app that tests whether two fields are the same - use case e.g. testing whether password and confirm password fields match. The logic is working, however the message provided from the method is not.
Custom validator code modified from: https://github.com/jquense/yup/issues/97#issuecomment-306547261
Custom validator
yup.addMethod(yup.string, 'isMatch', function (ref, msg) {
return this.test({
name: 'isMatch',
message: msg || `${this.path} must be equal to ${this.reference}`,
params: {
reference: ref.path
},
test: function (value) {
return value === this.resolve(ref);
}
});
});
Example use
const schema = yup.object().shape({
password: yup.string().min(8),
passwordConfirm: yup.string().isMatch(yup.ref('password'))
})
const payload = {
password: 'correctPassword',
passwordConfirm: 'incorrectPassword'
}
schema.validate(payload)
The above method works as expected from a logic perspective. However, in the error message returned, the value of this.path and this.reference are both undefined (i.e. undefined must be equal to undefined). It should read passwordConfirm must be equal to password.
I had to add this. in front of path and reference, otherwise node crashes with a ReferenceError that path/reference is not defined.
You do not need to write a custom validation function to check if two fields match, you can use the built in validator.oneOf
Whitelist a set of values. Values added are automatically removed
from any blacklist if they are in it. The ${values} interpolation can
be used in the message argument.
Note that undefined does not fail this validator, even when undefined
is not included in arrayOfValues. If you don't want undefined to be a
valid value, you can use mixed.required.
See here ref: oneOf(arrayOfValues: Array, message?: string | function): Schema Alias: equals
So you could re-write your schema as follows (I've added required also to the password fields):
const schema = yup.object().shape({
password: yup.string().min(8).required('Required!'),
passwordConfirm: yup.string().oneOf([Yup.ref('password')], 'Password must be the same!').required('Required!')
})

Nodejs - Joi Check if string is in a given list

I'm using Joi package for server side Validation. I want to check if a given string is in a given list or if it is not in a given list.(define black list or white list for values)
sth like an "in" or "notIn" function. How can I do that?
var schema = Joi.object().keys({
firstname: Joi.string().in(['a','b']),
lastname : Joi.string().notIn(['c','d']),
});
You are looking for the valid and invalid functions.
v16: https://hapi.dev/module/joi/api/?v=16.1.8#anyvalidvalues---aliases-equal
v17: https://hapi.dev/module/joi/api/?v=17.1.1#anyvalidvalues---aliases-equal
As of Joi v16 valid and invalid no longer accepts arrays, they take a variable number of arguments.
Your code becomes
var schema = Joi.object().keys({
firstname: Joi.string().valid(...['a','b']),
lastname: Joi.string().invalid(...['c','d']),
});
Can also just pass in as .valid('a', 'b') if not getting the values from an array (-:
How about:
var schema = Joi.object().keys({
firstname: Joi.string().valid(['a','b']),
lastname : Joi.string().invalid(['c','d']),
});
There are also aliases: .allow and .only
and .disallow and .not
Update from 10 Oct 2022
Now valid function requires Object
Joi.string().valid({ ...values_array }),

Resources