website-logomedcode

Next.js form validation using "zod" server-action

Enter Zod and Next.js Server Actions—a formidable alliance reshaping the paradigm of form validation within the React ecosystem. 🚀 Envision a landscape where forms are seamlessly validated, errors are gracefully managed, and instantaneous feedback delights your users—all underpinned ...
ali wazani| January 18, 2025
tools
Next.js form validation using "zod" server-action

#typescript #zod #server-side #form

Introduction to Zod and Its Role in Next.js:

Modern web applications demand precise data validation to ensure a seamless user experience and robust backend processes. This is where Zod, a powerful TypeScript-first schema declaration and validation library, comes into play. In this article, we’ll explore how to integrate Zod into a Next.js project, ensuring efficient validation for both client and server.

Overview of Zod and Its Benefits

Zod is a lightweight and intuitive library that allows developers to define schemas for data validation. Unlike traditional libraries like Yup or Joi, Zod is fully compatible with TypeScript, enabling strong type safety alongside runtime validation.

Here are some benefits of using Zod:

  • Seamless TypeScript integration.
  • Concise and readable syntax.
  • Support for nested schemas and advanced validations.
  • Auto-generated TypeScript types from schemas.

Comparison with Other Validation Libraries

While other libraries like Yup or Joi are popular, they often require additional effort to integrate with TypeScript. Zod, on the other hand, is designed with TypeScript in mind, making it a go-to choice for projects that prioritize type safety.

Installing Zod

Steps to Integrate Zod

To add Zod to your project, run the following command:

npm i zod

Testing the Installation

To confirm that Zod is installed, you can create a simple user schema


 export const createAccountSchema=z.object({
  name:z
    .string({ message:"name is required" })
    .min(6"name must be more then 6 characters")
    .max(50"name must be leas then 50 characters"),
  email:z
    .string({ message:"Email is required" })
    .min(16"Email is required ")
    .email("Invalid email"),
  password:z
    .string({ message:"Password is required" })
    .min(1"Password is required")
    .min(8"Password must be more than 8 characters")
    .max(32"Password must be less than 32 characters")
    .transform(hashPassword),
});

Install this package for more settings :

npm install @conform-to/react @conform-to/zod --save

Create User sign-up component using typescript


 "use client";
 import React, { useActionState } from "react";
 import { CreateButton } from "../components/SearchButton";
 import { parseWithZod } from "@conform-to/zod";
 import { createAccountSchema } from "@/src/utils/ZodSchema";
 import { useForm } from "@conform-to/react";
   const Page = () => {  
  const [lastResultaction= useActionState(addUserundefined); 
  const [formfields= useForm({
    lastResult,
    onValidate({ formData }) { 
     
return parseWithZod(formData, {
       
schema: createAccountSchema,})},
       shouldValidate: "onBlur", 
       
shouldRevalidate: "onInput",
    });
    
      return ( 
           <form id={form.id} onSubmit={form.onSubmit} action={action} noValidate
                 
className="mt-4">
            <div className="flex flex-col justify-center items-center">
            <input className="w-full dark:bg-dark px-8 py-3 rounded-lg font-medium bg-gray-100
                              border border-gray-200 placeholder-gray-500 text-sm
                              focus:outline-none focus:border-gray-400 focus:bg-white"

             type="text" placeholder="full name" name={fields.name.name}
             defaultValue={fields.name.initialValue as string} 
             key={fields.name.keymaxLength={40} required/>
             <p className="text-red-600 text-sm">{fields.name.errors}</p>
             
<input className="w-full px-8 dark:bg-dark py-3 mt-2 rounded-lg font-medium bg-gray-100
                               border border-gray-200 placeholder-gray-500 text-sm focus:outline-none
                               focus:border-gray-400 focus:bg-white" 
type="email" placeholder="Email"
              name={fields.email.name} defaultValue={fields.email.initialValue as string} 
              
key={fields.email.keyrequired/>
              <p className="text-red-600 text-sm">{fields.email.errors}</p>
              <input className="w-full px-8 dark:bg-dark ml-2 sm:ml-0 py-3 mt-2 rounded-lg font-medium
                                bg-gray-100 border border-gray-200 placeholder-gray-500 text-sm
                                focus:outline-none focus:border-gray-400 focus:bg-white"
 type="password"
               
placeholder="Password" name={fields.password.name} key={fields.password.key} /> 
                <p className="text-red-600 text-sm">{fields.password.errors}</p> </div>
                 <CreateButton />
                 </form>
)}
       export default Page;


Create CreateButton.tsx

 "use client";
 import { useFormStatus } from "react-dom";

 export function CreateButton() {
   const status = useFormStatus();
   return (
    <button type="submit" className="mt-5 tracking-wide  font-semibold bg-[#2b7aa6] text-white-500 w-full py-2 rounded-lg
            hover:bg-[#2b9aa2] transition-all duration-300 ease-in-out flex items-center justify-center
            focus:shadow-outline focus:outline-none"
><span className="text-light">
            {status.pending ? "Creating..." : "Create Account"}</span>
    </button>
  )}

Create addUser as a server function 

import { redirect } from"next/navigation";
import { revalidatePath } from"next/cache";


import { connect } from"./ConnectDB";


import { parseWithZod } from"@conform-to/zod";


import { createAccountSchema } from"./ZodSchema";


export const addUser=async (prevState:unknownformData:FormData=> {
  const submission=parseWithZod(formData, {
    schema:createAccountSchema,
  });
  if (submission.status!=="success") {
    return submission.reply();
  }
  try {
    connect();
    const newUser=newUser({
      name:submission.value.name,
      email:submission.value.email,
      password:submission.value.password,
    });
    await newUser.save();
    console.log("user is save");
  } catch (error) {
    console.log(error);
  }
  revalidatePath("/create-account");
  redirect("/login");
};

Create connect mongoDb Function:

  • install mongoDb and mongoose
  • npm install mongoose && npm install mongoose --save
    create MongoDB connect.tsx

// Importing mongoose library along with Connection type from it
importmongoose, { Connection } from"mongoose";

// Declaring a variable to store the cached database connection
let cachedConnection:Connection|null=null;

// Function to establish a connection to MongoDB
export asyncfunction connect() {
  // If a cached connection exists, return it
  if (cachedConnection) {
    console.log("Using cached db connection");
    return cachedConnection;
  }
  try {
    // If no cached connection exists, establish a new connection to MongoDB
    if (!process.env.MONGO) {
      throw new Error("MONGO environment variable is not defined");
    }
    const cnx=await mongoose.connect(process.env.MONGO);
    // Cache the connection for future use
    cached Connection=cnx.connection;
    // Log message indicating a new MongoDB connection is established
    console.log("New mongodb connection established");
    // Return the newly established connection
    return cached Connection;
  } catch (error) {
    // If an error occurs during connection, log the error and throw it
    console.log(error);
    throw error;
  }
}

Conclusion

Zod, combined with TypeScript and Next.js, is a game-changer for modern web development. It simplifies validation, improves type safety, and ensures your applications are robust and maintainable. Whether you're validating API requests or form inputs, Zod makes it a breeze to keep your codebase clean and error-free.



Login to write a comment

Loading...

Explore the latest insights, articles,free components, and expert advice on programming and software development

© Copyright 2024 MED DAKIR. All rights reserved./privacy policyTerms & Conditions