This is my first attempt in trying to use joi in frontend and the issue i am facing is that i am not getting custom errors when i try with bad data.
Here is my code in the validation.js
import Joi from "joi";
export const loginSchema = Joi.object({
email: Joi.string()
.pattern(new RegExp("^[^@\\s]+@[domainName]\\.(com|in)$"))
.email({
minDomainSegments: 2,
tlds: { allow: ["com", "in"] },
})
.required()
.messages({
"string.email": "Email must be a valid email",
"string.pattern.base":
"Email domain must be [domainName] and end with .com or .in",
"any.required": "Email is a required field",
}),
password: Joi.string()
.pattern(new RegExp("^[a-zA-Z0-9]{3,30}$"))
.required()
.messages({
"string.base": "Password should be a type of text",
"string.empty": "Password cannot be an empty field",
"string.pattern.base":
"Password should have a minimum length of 3 and a maximum length of 30, and contain only letters and numbers",
"any.required": "Password is a required field",
}),
});
For the frontend I am using Ionic Vue version 8 and here is the crucial code from that file as it is Too long;
<!-- Email -->
<ion-item>
<ion-input
placeholder="Email Address"
label-placement="stacked"
color="light"
type="email"
v-model.trim="form.email"
@ionBlur="validateField('email')"
:error-text="errors.email"
>
<ion-icon
slot="start"
:icon="mailOutline"
aria-hidden="true"
></ion-icon>
</ion-input>
</ion-item>
<!-- Password -->
<ion-item>
<ion-input
placeholder="Password"
label-placement="stacked"
color="light"
type="password"
v-model.trim="form.password"
@ionBlur="validateField('password')"
:error-text="errors.password"
>
<ion-icon
slot="start"
:icon="keyOutline"
aria-hidden="true"
></ion-icon>
<ion-input-password-toggle
slot="end"
color="dark"
></ion-input-password-toggle>
</ion-input>
</ion-item>
<script setup>
import { loginSchema } from "../../services/Validators";
import { reactive } from "vue";
const form = reactive({
email: "",
password: "",
});
const errors = reactive({
email: null,
password: null,
});
const validateField = (field) => {
const data = { [field]: form[field] };
console.log("Data: ", { ...data });
console.log("datatype: ", typeof data[field]);
const schema = loginSchema.extract(field);
const { error } = schema.validate(
{ email: data[field] },
{ abortEarly: false }
);
console.log(`Validation error for ${field}:`, { ...error });
errors[field] = error ? error.details[0].message : null;
};
</script>
Can someone Guide me as to what is wrong here cause when i log the error with some bad email here is the log that I get
{
"_original": {
"email": "dsfasdf@sdf.asd"
},
"details": [
{
"message": "\"value\" must be a string",
"path": [],
"type": "string.base",
"context": {
"label": "value",
"value": {
"email": "dsfasdf@sdf.asd"
}
}
}
]
}
ideally what should be logged is:
"string.pattern.base": "Email domain must be [domainName] and end with .com or .in",
Initially, i though I might not be sending the right data format or datatype format however when i printed data
and dataType
of the field this is what i see
data
{
"email": "sdfsd@asdf.ds"
}
dataType
datatype: string
Validation error for email:
{
"_original": {
"email": "sdfsd@asdf.ds"
},
"details": [
{
"message": "\"value\" must be a string",
"path": [],
"type": "string.base",
"context": {
"label": "value",
"value": {
"email": "sdfsd@asdf.ds"
}
}
}
]
}
since i am using Joi.object() where the keys match the schema keys and the values are the data to be validated i ruled out that it was due to incorrect data type or value.
When i test this schema with online tools/ sandboxes it works perfectly fine, however it not when i run it in the project. i am sure i am overlooking something, Please help me find that out
You cannot pass object when schema is extracted, so just pass the email string it will work
let email = data[field];
const { error } = schema.validate(
email,
{ abortEarly: false }
);
And some recommendation, you won't need required method in each property if all the properties in a object are required.
Instead use prefs
method like below
const loginSchema = Joi.object({
email: Joi.string()
.pattern(new RegExp('^[^@\\s]+@[domainName]\\.(com|in)$'))
.email({
minDomainSegments: 2,
tlds: { allow: ['com', 'in'] }
})
.messages({
'string.email': 'Email must be a valid email',
'string.pattern.base': 'Email domain must be [domainName] and end with .com or .in',
'any.required': 'Email is a required field'
}),
password: Joi.string().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')).messages({
'string.base': 'Password should be a type of text',
'string.empty': 'Password cannot be an empty field',
'string.pattern.base':
'Password should have a minimum length of 3 and a maximum length of 30, and contain only letters and numbers',
'any.required': 'Password is a required field'
})
}).prefs({ presence: 'required' }); // Here
presence: 'required'
tells that all the properties are required