ورودی خارجی را با دادهٔ داخلی یکی نگیرید

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

نوع را پیش از عملیات بررسی کنید

فراخوانی strip روی مقدار null یا عدد باعث خطا می‌شود. ابتدا مطمئن شوید نام و ایمیل رشته‌اند و سپس پاک‌سازی محدود دو سر را انجام دهید. تبدیل خودکار هر مقدار به str ممکن است دادهٔ غلط را معتبر جلوه دهد؛ عدد ۱۲۳ نام معتبر نمی‌شود فقط چون به متن تبدیل شده است. قرارداد باید تفاوت اصلاح قابل‌پذیرش و پذیرش بی‌قاعدهٔ نوع اشتباه را روشن کند.

دام پنهان bool و int

در Python نوع bool زیرکلاس int است، پس isinstance(True, int) درست برمی‌گرداند. اگر سن باید فقط عدد صحیح واقعی در قرارداد JSON باشد، این آزمون به‌تنهایی کافی نیست. در پروژه از type(age) is int استفاده می‌کنیم تا True یا False به‌عنوان سن پذیرفته نشود. این تصمیم یک مرز نوعی صریح است و نشان می‌دهد شناخت زبان برای اعتبارسنجی از نوشتن چند شرط ظاهری مهم‌تر است.

بررسی سادهٔ ایمیل چه چیزی را ثابت می‌کند؟

در این مثال، ایمیل باید یک @ با دو طرف غیرخالی داشته باشد و فاصلهٔ سفید داخل آن نباشد. این قاعده، بررسی کامل استاندارد ایمیل، وجود دامنه یا مالکیت نشانی را ثابت نمی‌کند. برای محصول واقعی از ابزار معتبر و فرایند تأیید مناسب استفاده کنید. تبدیل چنین شرط ساده‌ای به پیام «ایمیل تأیید شد» ادعایی بیش از چیزی است که کد واقعاً بررسی کرده است.

خروجی را از فیلدهای مجاز بسازید

اگر payload کلیدهای اضافی داشته باشد، همهٔ آن را به نتیجه منتقل نکنید. خروجی معتبر فقط نام پاک‌شده، ایمیل پاک‌شده، سن و پرچم valid دارد. این الگو از انتشار ناخواستهٔ فیلدهای غیرمرتبط جلوگیری می‌کند. در ورودی نامعتبر نیز تنها valid=false برمی‌گردد تا مصرف‌کننده به مقدارهای نیمه‌پاک‌شده تکیه نکند. این قرارداد کوچک برای تست و توسعهٔ بعدی بسیار روشن‌تر است.

کلید گمشده، مقدار خالی و نوع غلط

این سه وضعیت را در تست جدا کنید. نبودن age با سن صفر برابر نیست؛ نام فقط‌فاصله با نام چندبخشی فرق دارد؛ ایمیل عددی نباید با تبدیل به رشته پذیرفته شود. get برای خواندن امن کلید گمشده مناسب است، اما خود مقدار بازگشتی هنوز باید بررسی شود. تست‌هایی که فقط یک payload کامل دارند، شاخه‌های مهم اعتبارسنجی را نادیده می‌گیرند و اعتماد کاذب ایجاد می‌کنند.

مسیر حرفه‌ای توسعهٔ قرارداد

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

نمونه‌کد و قرارداد پروژه

payload: دیکشنری با فیلدهای احتمالی name, email, age. نام و ایمیل باید رشته باشند؛ سن فقط int غیرمنفی باشد نه bool. کلیدهای اضافی نادیده گرفته شوند.

ورودی معتبر: valid=true و نام و ایمیل strip‌شده و سن؛ نام خالی یا ایمیل فاقد @ یا دو طرف خالی نامعتبر است. نامعتبر: فقط valid=false. این قاعده تأیید مالکیت یا اعتبار کامل ایمیل نیست.

def solve(data):
    payload = data['payload']
    if not isinstance(payload.get('name'), str) or not isinstance(payload.get('email'), str):
        return {'valid': False}
    name, email = payload['name'].strip(), payload['email'].strip()
    parts = email.split('@')
    valid = (bool(name) and len(parts) == 2 and all(parts)
             and not any(c.isspace() for c in email)
             and type(payload.get('age')) is int and payload['age'] >= 0)
    if not valid:
        return {'valid': False}
    return {'valid': True, 'name': name, 'email': email, 'age': payload['age']}

print(solve({'payload': {'name': 'سارا', 'email': 'sara@example.com', 'age': 21}}))

خروجی مورد انتظار

{
  "valid": true,
  "name": "سارا",
  "email": "sara@example.com",
  "age": 21
}

پرسش‌های متداول

آیا وجود @ یعنی ایمیل معتبر است؟

خیر. این فقط یکی از قواعد سادهٔ تمرین است و وجود یا مالکیت صندوق را تأیید نمی‌کند.

چرا کلیدهای اضافی در خروجی نمی‌آیند؟

چون خروجی باید قرارداد مجاز و حداقل دادهٔ لازم را داشته باشد؛ بازگرداندن کل payload ممکن است اطلاعات ناخواسته منتشر کند.

تمرین عملی و قدم بعدی

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

منابع و مطالعهٔ بیشتر

برای بررسی جزئیات و ادامهٔ مطالعه؛ متن این راهنما مستقلاً برای نوونتیکس نوشته شده است.