I have an email input and i want to validate that the user entered a specific email "abcd@fg.com"
and if not to show specific error message "This email is not in our database"
. I am using zod validation to do that, but how can it be done?
const LoginSchema = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
})
});
I can show how to do this, but I don't think this should be done (more later).
You can use refine
to check if the string is exactly some expected value. For example:
const LoginSchema = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
.refine((e) => e === "abcd@fg.com", "This email is not in our database")
});
Then, later if you were going to pull down emails so you can write a validation on the frontend you would use an async
refinement with parseAsync
like:
const login2 = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
.refine(async (e) => {
const emails = await fetchEmails();
return emails.includes(e);
}, "This email is not in our database")
});
Opinion Warning
I would not recommend doing this for 2 reasons:
I would recommend not validating this as part of the data validation. This validation should happen on the backend and return a 4XX error response when logging in.
A comment on this post mentioned that you could instead provide an API to validate an email address. This could be safely used from an async refinement and avoids the issues described above.
That would look like:
const login2 = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
.refine(async (e) => {
// Where checkIfEmailIsValid makes a request to the backend
// to see if the email is valid.
return await checkIfEmailIsValid(e);
}, "This email is not in our database")
});