توسعه فرانت‌اند

Zod: اعتبارسنجی Type-safe در TypeScript

آموزش Zod 4؛ تفاوت نوع TypeScript با بررسی زمان اجرا، parse و safeParse، تبدیل ورودی، پیام خطا و مرز مجوز دسترسی با مثال کد.

1405/01/02 1 دقیقه مطالعه 1,164 بازدید
Zod: اعتبارسنجی Type-safe در TypeScript

پاسخ یک API ممکن است با نوعی که در TypeScript نوشته‌اید فرق داشته باشد. فیلدی حذف شده، عدد به شکل رشته آمده یا مقدار نامعتبر از فرم ارسال شده است. اعلام نوع در کد، شکل داده‌ای را که در زمان اجرا دریافت می‌کنید بررسی نمی‌کند. Zod برای همین مرز کاربرد دارد: داده نامطمئن را با یک ساختار مشخص بررسی می‌کنید و پس از موفقیت، مقدار خروجی را در برنامه به کار می‌برید.

این راهنما بر APIهای رایج Zod 4 تکیه دارد و مستندات آن در ۹ اکتبر ۲۰۲۶ بازبینی شده‌اند. مثال‌ها آموزشی‌اند و پروژه آماده تولید نیستند. کاربرد اصلی مقاله، روشن کردن محل اعتبارسنجی، نوع خطا و رابطه schema با نوع TypeScript است. نام یک کتابخانه به‌تنهایی امنیت برنامه را تضمین نمی‌کند؛ هنوز باید درباره دسترسی، قواعد کسب‌وکار و نحوه نمایش خطا تصمیم بگیرید.

نوع ایستا و داده زمان اجرا را جدا ببینید

TypeScript هنگام بررسی کد درباره استفاده از نوع‌ها کمک می‌کند، اما پاسخ شبکه در زمان اجرای برنامه وارد می‌شود. نوشتن یک ادعای نوع با as به معنی بررسی داده نیست. اگر داده خارجی را مستقیم به نوع مورد انتظار نسبت بدهید، ممکن است خطا دیرتر در بخش دیگری ظاهر شود. برای مرز ورودی، بهتر است نامطمئن بودن داده آشکار بماند و نتیجه بررسی پیش از استفاده در منطق برنامه مشخص شود.

راهنمای پایه Zod ساخت schema، بررسی داده و استخراج نوع را توضیح می‌دهد. schema توصیف می‌کند ورودی قابل قبول چه ساختاری دارد. نوع استخراج‌شده برای کار با خروجی در کد استفاده می‌شود. این ارتباط می‌تواند تکرار بعضی تعریف‌ها را کم کند، اما به معنی قابل استفاده بودن یک schema برای تمام موقعیت‌های برنامه نیست. فرم ساخت حساب و پاسخ عمومی حساب، الزاماً فیلدهای یکسانی ندارند.

از یک schema کوچک و روشن شروع کنید

فرض کنید یک فرم آموزشی نام کاربر و تعداد اعضای تیم را دریافت می‌کند. نام نباید خالی باشد و تعداد باید عدد صحیح مثبت باشد. ابتدا همین قواعد را بنویسید، بدون اینکه همه نیازهای احتمالی آینده را وارد کنید. محدودیت باید از نیاز محصول بیاید. انتخاب یک سقف دلخواه برای طول نام، بدون توضیح کاربرد آن، ممکن است ورودی معتبر را رد کند و پشتیبانی را با مسئله تازه‌ای روبه‌رو سازد.

import { z } from "zod";

const TeamInput = z.object({
  name: z.string().trim().min(1),
  members: z.number().int().positive(),
});

type Team = z.infer;
const result = TeamInput.safeParse({ name: "Design", members: 3 });

if (result.success) {
  const team: Team = result.data;
  console.log(team.members);
} else {
  console.log(result.error.issues);
}

در این نمونه، رشته بودن نام و عدد بودن تعداد هر دو بررسی می‌شوند. فاصله‌های ابتدا و انتهای نام پیش از شرط طول حذف می‌شوند. اگر تعداد به شکل رشته ارسال شود، این schema آن را عدد نمی‌داند. این رفتار را باید با شیوه ارسال فرم تطبیق دهید. مثال از console برای کوتاهی استفاده می‌کند؛ در برنامه واقعی، نمایش خطا و ثبت رخداد باید متناسب با محیط باشد.

parse و safeParse دو شیوه رسیدگی به نتیجه‌اند

وقتی parse ورودی نامعتبر دریافت کند، خطا ایجاد می‌کند و باید در مسیر مناسب مدیریت شود. safeParse نتیجه‌ای برمی‌گرداند که شاخه موفق یا ناموفق آن را می‌توانید بررسی کنید. انتخاب بین این دو به ساختار برنامه مربوط است. برای یک فرم که خطا نتیجه عادی تعامل کاربر است، رسیدگی روشن به شاخه ناموفق می‌تواند خواناتر باشد. در مسیر دیگری، شاید سازوکار مشترک مدیریت خطا از قبل وجود داشته باشد.

مسیر ناموفق را به بعد موکول نکنید. اگر نتیجه بررسی را نادیده بگیرید و همچنان ورودی اصلی را مصرف کنید، اعتبارسنجی در رفتار برنامه اثر لازم را ندارد. پس از موفقیت، از خروجی بررسی‌شده استفاده کنید. این موضوع زمانی مهم‌تر می‌شود که schema تبدیل یا پاک‌سازی دارد؛ مقدار خروجی ممکن است با ورودی اولیه فرق داشته باشد. نگه داشتن نام‌های روشن برای این دو، خواندن کد را آسان‌تر می‌کند.

ورودی فرم را بدون تصمیم تبدیل نکنید

داده فرم HTML معمولاً به شکل رشته وارد می‌شود. تیم باید مشخص کند رشته خالی، فاصله یا عدد دارای قالب محلی چه معنایی دارد. تبدیل عمومی با Number رفتارهایی مثل تبدیل رشته خالی به صفر دارد؛ شاید این نتیجه برای فیلد مورد نظر مناسب نباشد. پیش از انتخاب تبدیل، حالت‌های قابل قبول را بنویسید. برای تعداد اعضا، خالی بودن احتمالاً با وارد کردن صفر فرق دارد و پیام جداگانه می‌خواهد.

مرجع تعریف schema در Zod امکانات تبدیل، شرط و ترکیب ساختارها را معرفی می‌کند. استفاده از coercion باید آگاهانه باشد، نه راهی برای قبول کردن هر ورودی. اگر محصول شماره تلفن یا شناسه‌ای با صفر ابتدایی می‌گیرد، تبدیل آن به عدد می‌تواند بخشی از اطلاعات را حذف کند. انتخاب نوع، بخشی از مدل‌سازی داده است. همه چیزی که از رقم تشکیل شده، مقدار عددی برای محاسبه نیست.

نوع ورودی و خروجی همیشه یکسان نیست

اگر schema مقدار را تغییر دهد، درباره ورودی و خروجی دو تعریف متفاوت لازم دارید. برای نمونه آموزشی، متنی را دریافت می‌کنید و طول آن را به‌عنوان عدد برمی‌گردانید. این schema رشته می‌گیرد و عدد می‌دهد. در چنین وضعیتی، نام متغیر و نوعی که در بخش بعدی استفاده می‌شود باید با خروجی هماهنگ باشد. استفاده از نوع ورودی برای خروجی، هدف بررسی را در کد مبهم می‌کند.

const TextLength = z.string().transform((value) => value.length);
type TextInput = z.input;
type LengthOutput = z.output;

برای تبدیل یا شرط ناهمگام، مسیر بررسی ناهمگام را نیز انتخاب کنید. این موضوع در مستندات پایه و مرجع API توضیح داده شده است. در طراحی برنامه، تصمیم بگیرید کدام بررسی ساختاری است و کدام به دریافت اطلاعات از سرویس دیگر نیاز دارد. پاسخ کند یا ناموجود یک سرویس را نباید بی‌توضیح به خطای «مقدار نامعتبر» تبدیل کرد؛ کاربر و تیم پشتیبانی به تفاوت این دو نیاز دارند.

فیلدهای اضافی و قرارداد API را روشن کنید

دریافت یک شیء با فیلدهای بیشتر از انتظار همیشه یک معنی ندارد. گاهی قرارداد باید سخت‌گیرانه باشد و گاهی پاسخ سرویس با فیلد تازه توسعه می‌یابد. در Zod، رفتار شیء معمولی، شیء سخت‌گیرانه و ساختاری که فیلدهای اضافی را می‌پذیرد را از مرجع همان نسخه بررسی کنید. انتخاب را در قرارداد تیم ثبت کنید تا یک توسعه‌دهنده روی حذف فیلد و دیگری روی حفظ آن حساب نکند.

حتی اگر ورودی فیلدهای زیادی دارد، فقط فیلدهای مجاز را به عملیات حساس بفرستید. دریافت مقدار role یا وضعیت حساب از کاربر نباید به معنی اجازه تغییر آن باشد. schema مشخص می‌کند شکل داده چیست؛ تصمیم درباره اینکه چه کسی چه چیزی را تغییر می‌دهد، به مجوز دسترسی مربوط است. این مرز در API به اندازه محدودیت طول یا نوع فیلد اهمیت دارد.

سه بررسی مستقل سرور: ساختار داده، اجازه دسترسی و قواعد کسب‌وکار

خطا را به پیام قابل استفاده تبدیل کنید

کاربر فرم به توضیحی نیاز دارد که نشان دهد کدام قسمت را چگونه اصلاح کند. فهرست فنی issues برای توسعه‌دهنده مفید است، ولی نباید بدون تصمیم به رابط منتقل شود. مسیر فیلد، نوع خطا و متن مناسب را به ساختار نمایش فرم نگاشت کنید. برای خطایی که به رابطه چند فیلد مربوط است، شاید پیام در سطح کل فرم مناسب‌تر باشد. قرار دادن همه خطاها زیر اولین ورودی، رابطه مشکل و اقدام را پنهان می‌کند.

راهنمای تنظیم خطاهای Zod شیوه شخصی‌سازی پیام را توضیح می‌دهد. در برنامه فارسی، پیام‌ها را با واژگان خود محصول هماهنگ کنید و اطلاعات حساس ورودی را بی‌دلیل در گزارش خطا نگه ندارید. «تعداد اعضا را به‌صورت عدد صحیح مثبت وارد کنید» از «ورودی نامعتبر است» روشن‌تر است. پس از اصلاح یک فیلد نیز باید وضعیت آن در رابط به‌روز شود.

اشتراک schema به معنی یکسان بودن همه قراردادها نیست

می‌توان بخشی از قواعد را میان رابط و سرور مشترک نگه داشت، اما سرور همچنان باید داده ورودی را خودش بررسی کند. درخواست الزاماً از همان فرم ساخته نمی‌شود. برای پاسخ API، فیلدهایی را انتخاب کنید که قرار است به مصرف‌کننده برسند؛ ساختار ذخیره‌سازی داخلی نباید خودکار به قرارداد عمومی تبدیل شود. اشتراک کد زمانی مفید است که مرز مسئولیت‌ها روشن بماند.

اگر در کنار مدل داده، ساختار صفحه را طراحی می‌کنید، راهنمای CSS Grid برای چیدمان و راهنمای طراحی موبایل‌نخست برای رفتار فرم در صفحه کوچک ادامه مرتبطی هستند. اعتبارسنجی و نمایش نتیجه باید کنار هم دیده شوند. داده‌ای که درست رد شده اما پیامش پیدا نمی‌شود، از دید کاربر فرایند قابل استفاده‌ای ایجاد نکرده است.

برای تغییر قرارداد، نمونه‌های مرزی را نگه دارید

در تیم، نمونه ورودی معتبر، ورودی ناقص، مقدار مرزی و فیلد اضافی را کنار تعریف schema ثبت کنید. وقتی قرارداد تغییر می‌کند، معلوم می‌شود کدام رفتار باید حفظ و کدام عمداً عوض شود. برای مهاجرت نسخه کتابخانه نیز همین انتظارهای ثبت‌شده را با مستندات جدید تطبیق دهید. از ادعای سرعت یا حجم کمتر بدون اندازه‌گیری در پروژه خود نتیجه معماری نگیرید. ابتدا بدانید کدام داده را در کدام مرز بررسی می‌کنید و شکست آن چگونه به بخش بعدی منتقل می‌شود.

واکنش به این مقاله

اشتراک‌گذاری این مقاله:
دیدگاه‌ها 0
۰ / ۲۰۰۰

هنوز دیدگاهی ثبت نشده

اولین نفری باشید که نظر می‌دهد!