اعتبارسنجی فرم در Next.js با Zod: از کلاینت تا سرور
نویسنده: آرش لطیفی
آموزش عملی اعتبارسنجی فرم با Zod و React Hook Form در Next.js؛ یک اسکیمای مشترک برای کلاینت و Server Actions، مدیریت خطا و تجربه کاربری تمیز.
خلاصه: یک اسکیمای
Zodرا منبع حقیقت قرار دهید و هم در کلاینت باReact Hook Formو هم درServer Actionsاستفاده کنید. نتیجه اعتبارسنجی سریع، پیام خطای یکسان و امنیت سمت سرور بدون تکرار کد است.
چرا Zod برای فرمهای Next.js
اعتبارسنجی فقط در کلاینت کافی نیست و فقط در سرور تجربه کاربری را کند میکند. راه حل منبع واحد است: اسکیمای Zod که هم تایپ میدهد و هم در هر دو سمت اجرا میشود. این الگو با Server Actions و useActionState تمیز جفت میشود و از ناهماهنگی پیام خطا جلوگیری میکند.
اگر روی مرز کلاینت و سرور حساس هستید، مرور مرز use-client و آلودگی RSC و کش و PPR در Next.js 15 کمک میکند تا منطق اعتبارسنجی را در جای درست قرار دهید.
اسکیمای مشترک؛ منبع حقیقت
یک فایل schemas/contact.ts بسازید و فقط همان را همه جا وارد کنید. پیامها را فارسی و کوتاه بنویسید و طول ورودیها را محدود کنید تا از اسپم و ورودیهای غولپیکر جلوگیری شود.
// schemas/contact.ts
import { z } from "zod";
export const contactSchema = z.object({
name: z.string().min(2, "نام حداقل ۲ حرف باشد").max(50),
email: z.string().email("ایمیل معتبر وارد کنید").max(100),
phone: z.string().regex(/^09\d{9}$/, "شماره موبایل معتبر نیست").optional().or(z.literal("")),
message: z.string().min(10, "پیام حداقل ۱۰ حرف باشد").max(1000),
budget: z.enum(["low", "mid", "high"], { message: "بودجه را انتخاب کنید" }),
});
export type ContactInput = z.infer<typeof contactSchema>;
این اسکیما هم تایپ خروجی میدهد و هم با zodResolver و هم در سرور کار میکند. تغییر قانون فقط در یک جا انجام میشود.
کلاینت: React Hook Form + zodResolver
برای تجربه سریع، اعتبارسنجی را در کلاینت با React Hook Form اجرا کنید اما پیام خطا را از همان اسکیما بگیرید.
نکتهها: از mode: "onBlur" برای کاهش نویز استفاده کنید، aria-invalid را ست کنید و دکمه را هنگام isSubmitting غیرفعال کنید.
سرور: اعتبارسنجی مطمئن با Server Actions
هرگز به کلاینت اعتماد نکنید. همان اسکیما را در Server Action دوباره اجرا کنید و خطاها را به فرم برگردانید.
این الگو با بهینهسازی RTL در Next.js 15 هم سازگار است چون پیامهای خطا فارسی و جهت نوشتار درست میماند.
مقایسه ابزارها
انتخاب ابزار به نیاز پروژه بستگی دارد اما برای اکثر فرمهای Next.js ترکیب Zod و React Hook Form کمهزینهترین است.
| ابزار | نقاط قوت | مناسب برای | نکته |
|---|---|---|---|
| Zod + React Hook Form | تایپ قوی، اسکیمای مشترک کلاینت/سرور، اکوسیستم بزرگ | فرمهای معمول تا پیچیده | zodResolver را فراموش نکنید |
| Valibot | حجم کمتر، سرعت بیشتر | پروژههای حساس به باندل | API متفاوت از Zod |
| Yup | سابقه طولانی | مهاجرت از کد قدیمی | تایپ ضعیفتر از Zod |
اگر باندل برایتان حیاتی است، Valibot را تست کنید ولی مستندات و مثالهای Zod در اکوسیستم Next.js بیشتر است.
چکلیست پیادهسازی تمیز
- [ ] اسکیما در یک فایل مشترک تعریف شد و در کلاینت و سرور وارد شد
- [ ] پیامهای خطا کوتاه، فارسی و یکسان در هر دو سمت هستند
- [ ] ورودیها
maxدارند وtrimیاtransformبرای فضاهای اضافی اعمال شد - [ ]
aria-invalidوaria-describedbyبرای دسترسیپذیری ست شد - [ ] دکمه ارسال هنگام
isSubmittingوpendingغیرفعال میشود - [ ] اعتبارسنجی سرور با
safeParseو برگرداندنfieldErrorsانجام شد - [ ] تست دستی با ورودی خالی، ایمیل نامعتبر و پیام خیلی بلند انجام شد
- [ ] لاگ سرور برای خطاهای اعتبارسنجی بدون نشت داده حساس فعال شد
FAQ
Q: آیا فقط اعتبارسنجی کلاینت کافی نیست؟
خیر. کلاینت قابل دور زدن است. همیشه همان اسکیما را در سرور هم اجرا کنید تا امنیت و یکپارچگی داده تضمین شود.
Q: Zod را کجا نگه دارم تا تکرار نشود؟
در schemas/ کنار app و فقط از همان یک خروجی contactSchema در فرم، API Route و Server Action استفاده کنید.
Q: چطور فایل آپلود را هم اعتبارسنجی کنم؟
از z.instanceof(File).refine(f => f.size < 2_000_000, "حجم فایل زیاد است") استفاده کنید و نوع فایل را با refine روی type چک کنید؛ اعتبارسنجی نهایی حجم و نوع را دوباره در سرور تکرار کنید.
منابع
- مستندات رسمی Zod — تعریف اسکیما،
safeParseو پیامهای خطای فارسیسازیشده - راهنمای شروع React Hook Form — الگوی
useFormوhandleSubmitکه در مقاله استفاده شده - راهنمای Server Functions در مستندات Next.js — جایی که اعتبارسنجی سمت سرور اتفاق میافتد
- Zod v4 با فرمها و Server Action در Next.js — راهنمای مستقل و بهروز
- ایشوی resolvers دربارهی فیلدهای شرطی — تجربهی کامیونیتی دربارهی مرزهای resolver