How to write a Front End and Back End (Server side validation). It is really important to provide both client-side and server-side validation. The code below shows how to implement a form that provides both using react hook form and Zod.
Next JS – React Hook Form with Zod Complete
Creation of React Hook Form [Front End Validation]
Just create a page at app/Second/page.tsx
‘use client’
import { useForm, SubmitHandler } from “react-hook-form”
import { zodResolver } from “@hookform/resolvers/zod”
import {SignupSchema, TSignUpSchema} from “@/lib/signupschema”
export default function second() {
const {
register,
handleSubmit,
setError,
formState:{errors},
} = useForm<TSignUpSchema>({
resolver:zodResolver(SignupSchema)
});
const onSubmit = async (data: TSignUpSchema) => {
const result = await fetch(‘/api/signup’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’,
},
body: JSON.stringify(data),
});
const responseData = await result.json();
if(!responseData.success){
alert(‘The form has mistakes’)
}
if(responseData.errors){
const error = responseData.errors;
if(error.username){
setError(‘username’, {
message: error.username,
type:’server’,
})
}
else if(error.password){
setError(‘password’, {
message:error.password,
type:’server’,
})
}
else if(error.confirmpassword){
setError(‘confirmpassword’, {
message:error.confirmpassword,
type:’server’,
})
}
else{
alert(‘something is wrong over here’)
}
}
return true;
}
return (
<div>
<h1 className=’text-2xl’>Second Registration Form</h1>
<form className=’max-w-sm mx-auto’ onSubmit = {handleSubmit(onSubmit)}>
<div className=’m-5′>
<input className=’bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500′ placeholder= “username” {…register(“username”)} />
{errors.username && <p className=’text-red-500′>{errors.username.message}</p>}
</div>
<div className=’m-5′>
<input className=’bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500′ placeholder= “password” {…register(“password”)} />
{errors.password && <p className=’text-red-500′>{errors.password.message}</p>}
</div>
<div className=’m-5′>
<input className=’bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500′ placeholder= “confirmpassword” {…register(“confirmpassword”)} />
{errors.confirmpassword && <p className=’text-red-500′>{errors.confirmpassword.message}</p>}
</div>
<div className=’m-5′>
<input className=’bg-black text-orange-200 w-auto p-2′ type=”submit” />
</div>
</form>
</div>
)
}
Zod and Schema
lib/signupschema.ts
import { z } from “zod”
export const SignupSchema = z.object({
username: z.string().min(6,{message:”Username must be atleast 6 characters”}),
password: z.string().min(6,{message:”Password must be atleast 6 characters”}),
confirmpassword: z.string().min(6, {message:”Password must be atleast 6 characters”}),
}).refine(data => data.password === data.confirmpassword, {
message: “Passwords do not match”,
path: [“confirmpassword”]
});
export type TSignUpSchema = z.infer<typeof SignupSchema>
Creation of API End Point [Back End Server-Side Validation]
/app/api/signup/route.ts
import {NextResponse} from ‘next/server’
import {SignupSchema} from “@/lib/signupschema”
export async function POST(request:Request){
const body: unknown = await request.json();
const result = SignupSchema.safeParse(body)
let zodErrors = {};
if(!result.success){
const listErrors= result.error.issues
listErrors.forEach((err) => {
zodErrors = {…zodErrors, [err.path[0]]:err.message} // This will add new property into the zod Errors object
});
}
return NextResponse.json(
Object.keys(zodErrors).length > 0 ? {errors: zodErrors} :{success : true}
);
}