Raise validation when recive extra key in yup object - javascript

I am using yup for object validations. I have the following schema
const schema = yup.object().shape({
name: yup.string().required(),
});
I am validating it with object
{
"name": "Foo",
"desc": "Lorem ipsum"
}
Yup validates this object although it has an extra key desc. I want to raise the error for extra keys in the object.
I have tried with abortEarly and stripUnknown in .validate but it doesn't work.
schema.validateSync(data, { strict: true, stripUnknown: true })

You need to append the .strict() to the object you are validating. This makes the validation fail and then you can handle the error however you wish to do that.
So, in your case, change your schema to this:
const schema = yup.object().shape({
name: yup.string().required()
}).noUnknown(true).strict();
await schema.validate(data, { abortEarly: false });

Related

Validation to prevent brand names being in the email field?

So, I have this list of some brandnames:
const blackListedDomains = [
'facebook',
'google',
'amazon',
'netflix',
'hotmail',
'microsoft',
'gmail',
'yahoo',
]
which I need to prevent users to enter in the email field, what Schema could be built using Yup Package.
For example, I am trying this way:
const DomainSchema = Yup.object().shape({
subdomain: Yup.string()
.required('Required')
.lowercase()
.notOneOf(
blackListedDomains,
'Cannot use trademarked names in domain!',
),
})
But, I don't know how to get it from the email string, for example, if user inputs xyz#google.xyz, then how to extract google from the email string and then iterate it over the domain names list to find if it exists there and then show an error message ?
You can use test function of yup library to create a custom validation rule like this:
const DomainSchema = Yup.object().shape({
email: Yup.string()
.required("Required")
.lowercase()
.email("Not a valid mail")
.test(
"is-not-blacklist",
"Cannot use trademarked names in domain!",
(value) => {
if (value) {
const currentDomain = value.substring(
value.indexOf("#") + 1,
value.indexOf(".")
);
return !blackListedDomains.includes(currentDomain);
}
}
)
});
You can take a look at this sandbox for a live working example of this solution.

Node.JS - #hapi/joi - any.when() - not able to add .validate() at the "then condition"

I'm not able to set the joi-schema that it is working as expected...
This is what I try to do:
'role' is an array and can contain items as string. Any value is allowed.
But when 'internal' is set to 'true', only certain values in 'role' are allowed.
This is the code, which is not working as expected.
let Joi = require("#hapi/joi");
const schema = Joi.object({
internal: Joi.boolean(),
role:
Joi.array()
.items(Joi.string().trim())
.required()
// the when condition is not replacing properly
.when('internal', {
is: true,
then: Joi.array()
.items(Joi.string().valid("Admin"))
.required()
}),
});
console.log(schema.validate({role: ["Any Role"]})) // OK
console.log(schema.validate({internal: false, role: ["Any role allowed"]})) // OK
console.log(schema.validate({internal: true, role: ["WRONG"]})) // FAIL, should have thrown error
... while the replacing array function by itself works fine:
const passingschema = Joi.object({
role: Joi.array()
.items(Joi.string().valid("Admin"))
.required()
})
console.log(passingschema.validate({role: ["Admin"]})) // OK
console.log(passingschema.validate({role: ["WRONG"]})) // OK - throws error as expected
});
Please let me know, how to replace the role validation accordingly, once internal is set to true.
Maybe try is: valid(true).required() in the documentation it says you need required() on the is in order to make this work.
According to this link, this is the solution:
Joi.array().required()
.when('internal', {
is: true,
then: Joi.array().items(Joi.string().valid("Admin")),
otherwise: Joi.array().items(Joi.string())
})

Yup how to validate mandatory fields on null object

I have a problem regarding the validation of mandatory fields which are properties of a (possibly) null object.
Here is an example schema :
object().shape({
catalog: {
brand: string().required()
}
})
If I try to validate the following object against this schema, I get the expected error : brand is required. From what I understood, there is a default value created for undefined object which mimics the shape of the object in the schema. This is the behavior I expected and what I want.
{ catalog: undefined }
// "catalog.brand is a required field"
But in my case, I don't receive an object with undefined, but with null. And I can't figure out how to manage the same result with a null value.
{ catalog: null }
// No error on catalog.brand
Manually casting null to undefined is out of the question as there is a good reason why I receive null.
Here is a codesandbox which reproduces my use case :
https://codesandbox.io/s/yup-playground-tbfcj
I would really appreciate a bit of help on this, thanks :)
The solution is to include both nullable() and required() to the shape.
Example
const requiredOption = Yup.object()
.shape({
value: Yup.string(),
label: Yup.string(),
})
.nullable()
.required('This field is required.');
Try adding strict() on your object schema
object().shape({
catalog: {
brand: string().required()
}
}).strict();
Here's a less mindbending way to do it than the other answer. This allows you to keep the required directive on the subfield whether or not the parent schema/field containing it is empty at validation time.
yup.object().shape({
field: yup.object().shape({
subfield: string().required(),
}).default(undefined),
});
// Or...
yup.object().shape({
field: yup.object().shape({
subfield: string().required(),
}).default(null).nullable(),
});
One difference between the two is that when you validate data over each of these schemas and field is missing, if you also pass in stripUnknown, in the first case the field will be totally removed from the validated result, but in the second case the field will still show up but with value null.
Adding the .default(null) method along with .nullable() worked for me.
const parentValidator = Yup.object({
personData: personDataValidator,
data: Yup.object({
workshift: Yup.array()
.of(Yup.string().matches(/x|-/g, "Local de trabalho inválido"))
.required("Turno de trabalho obrigatório")
.typeError("Turno de trabalho inválido"),
workplace: Yup.string()
.required("Local de trabalho obrigatório")
.typeError("Local de trabalho inválido"),
email: Yup.string()
.required("Email obrigatório")
.typeError("Email inválido"),
}),
})
.default(null)
.nullable();

Password confirmation and password are equal but validation is still triggering JOI in React component

I creating a register form and the problems accurs while try validating password confirmation. I am using the last version of JOI-Browser.
I tried the code below and the validation error was triggered even though password and password confirmation have the same values.
password: Joi.string()
.min(5)
.required(),
passwordConfirmation: Joi.ref("password")
Here is my state object:
password: "12345"
passwordConfirmation: "12345"
username: ""
errors: {…}
passwordConfirmation: "\"passwordConfirmation\" must be one of [ref:password]"
I passed several hours trying several approaches and reading the documentation, but still no luck, the validation is still triggering,
I have other validations in this form and they work fine.
I don't think Joi.ref should be used that way.
I usually tend to do this way:
const passwordConfirmation = Joi.string()
.required()
.valid(Joi.ref('password'))
.options({
language: {
any: {
allowOnly: '!!Passwords do not match',
}
}
})
If you refer to the docs, you will see:
Note that references can only be used where explicitly supported such as in valid() or invalid() rules. If upwards (parents) references are needed, use object.assert().
If anyone has encountered a similar problem, this is the solution I have used:
validateProperty = (input) => {
let obj = { [input.name]: input.value };
let schema = { [input.name]: this.schema[input.name] };
if (input.name.endsWith("_confirm")) {
const dependentInput = input.name.substring(
0,
input.name.indexOf("_confirm")
);
obj[dependentInput] = this.state.data[dependentInput];
schema[dependentInput] = this.schema[dependentInput];
}
const { error } = Joi.validate(obj, schema);
return error ? error.details[0].message : null;
};
In my case, I have looked for _confirm because I have the field names as password and password_confirm. You need to make changes here as per your requirements.
Main logic, you just need to add value and schema of password when you are validating password_confirm
I find out what was happening. My code above was right, the problem was in my validate function.
Gabriele's Petrioli comment help me out. this is the function that cause me problems:
validateProperty = ({ name: propertyName, value }) => {
const obj = { [propertyName]: value };
const schema = { [propertyName]: this.schema[propertyName] };
const { error } = Joi.validate(obj, schema);
return error ? error.details[0].message : null;};
Has you can see i tried validate each property individually, so i can make the form more dynamic.
This trigger the validation error because when i try to validate confirmPassword there was no value in password because i passed only the value the correspond to confirmaPassword, it also needed the password value to make the comparison.
Rookie mistake

Joi Validations: Capture the value passed in Custom Error Message

I am using Joi Library with NodeJs/Typescript for validations.
Validating a request body for a Post Operation.
I am using the language option to provide custom messages for respective field validations.
Below is the code
const bodySchema = Joi.object().keys({
// had to change from string to any so as to avoid multiple messages when empty
field1: Joi.any().required().valid('Dummy').options({
language: {
any: {
// wrt empty: specific error message not displaying with any but empty error is handled by allowOnly custom message. Anways there is no custom message for empty in requirements
// empty: '!!The parameter \'field1\' cannot be empty. It must be \'Dummy\'',
required: '!!The parameter \'field1\' is mandatory and must be the value \'Dummy\'',
allowOnly: '!!Invalid value for parameter \'field1\'. It must be \'Dummy\''
// how to capture value passed for field1 in the message?
}
}
}),
How to Capture the wrong field value passed as requestBody in the custom error message
For eg if I pass request body for the POST endpoint
{
"field1": "wrongvalue",
}
Expected custom message
Invalid value 'wrongvalue' for parameter \'field1\'. It must be \'Dummy\''
I have gone through JOI API but could not find any reference to doing this.
While regex option has the facility to capture the value passed.
{{value}} works in regex but not in other options.
Please let me know if there is a way to capture the value.
try this ......
const typeSchema = Joi.object({field1: Joi
any()
.required()
.valid('Dummy')
.error(errors => {
errors.forEach(err => {
switch (err.type) {
case "string.base":
case "required":
err.message = "field 1 is mandatory and must be the value";
break;
case "any.allowOnly":
err.message = "field1 must be Dummy";
break;
default:
console.log('validate error type missing', err.type);
break;
}
});
return errors;
}),
})

Categories