أكيد قابلت forms كتير وانت أونلاين، سواء بتسجل حساب جديد أو بتطلب حاجة. كمبرمج، مهمتك مش بس تجمع البيانات دي من اليوزر عن طريق الـ HTML forms، لأ الأهم إنك تتأكد إن البيانات دي صحيحة، قابلة للاستخدام (usable)، وآمنة.

إنك تاخد البيانات دي حاجة، بس إنك تضمن جودتها وسلامتها دي حاجة تانية خالص، وهنا بيجي دور الـ Application Validation.

إيه هو الـ Application Validation؟

ببساطة، الـ Application Validation هو عملية بنعملها عشان نتأكد إن أي بيانات داخلة للـ application بتاعنا (سواء من يوزر عن طريق form، أو من API call، أو أي مصدر تاني) بتكون:

  1. صحيحة (Valid): مطابقة للنوع والشكل المتوقع (مثلًا، ده فعلًا إيميل؟ ده رقم؟ ده تاريخ مظبوط؟).
  2. مكتملة (Complete): مفيش بيانات أساسية ناقصة (زي الحقول الـ required).
  3. متوافقة (Consistent): ماشية مع قواعد البيزنس (business rules) والقيود (constraints) اللي إحنا حاطينها (مثلًا، السن لازم يكون أكبر من 18؟ كلمة السر لازم تكون قوية؟).
  4. آمنة (Secure): مفيهاش أكواد خبيثة أو محاولات اختراق.

ليه الـ Validation ده مهم أوي؟

  1. سلامة البيانات (Data Integrity): دي أهم نقطة. لو دخلت بيانات غلط أو غير متوافقة في الـ database بتاعتك، ده ممكن يسبب كوارث في المستقبل، زي تقارير غلط، حسابات مش مظبوطة، أو حتى الـ application نفسه يـ “يضرب” وميعرفش يشتغل صح.
  2. تجربة المستخدم (User Experience - UX): زي ما شوفنا، الـ validation اللي بيحصل بسرعة (زي الـ client-side) وبيدي فيدباك واضح لليوزر بيخليه يعرف يصلح أغلاطه بسهولة وميحسش بإحباط.
  3. الأمان (Security): دي نقطة حيوية جدًا. الـ Validation (خصوصًا الـ server-side) هو خط الدفاع الأول ضد أنواع كتير من الهجمات زي:
    • الـ SQL Injection: لو مدخلتش validate كويس للمدخلات اللي هتستخدمها في query للـ database.
    • الـ Cross-Site Scripting (XSS): لو سمحت لـ scripts خبيثة تتخزن وتتعرض ليوزرز تانيين.
    • الـ Denial of Service (DoS) DDoS: لو سمحت لبيانات ضخمة أو بتاخد وقت طويل في المعالجة إنها تدخل وتستهلك موارد السيرفر.
  4. الحفاظ على حالة التطبيق (Application State): الـ Validation بيضمن إن الـ application بتاعك ميوصلش لحالة غير منطقية أو غير متوقعة بسبب بيانات غلط.
  5. تقليل الحمل على السيرفر: الـ Client-side validation بيمنع ريكوستات كتير مالهاش لازمة وفيها أخطاء واضحة إنها توصل للسيرفر أصلًا.

أنواع الـ Application Validation: خطوط الدفاع

زي ما ذكرت في النص بتاعك، فيه نوعين أساسيين للـ validation بيكملوا بعض:

1. Client-Side Validation

  • فين بيحصل؟ في جهاز اليوزر، جوه الـ web browser.
  • إمتى؟ غالبًا لحظة الإدخال أو لما اليوزر يتحرك من حقل للتاني أو قبل ما يدوس Submit.
  • مين بيعمله؟
    • الـ HTML5 Attributes: دي أبسط طريقة، زي ما شوفنا في Input Types HTML. الـ browser نفسه بيعمل validate لأنواع زي email, url, number ولـ attributes زي required, minlength, maxlength, min, max, pattern.
    • الـ JavaScript MOC: بنستخدمها لما نحتاج validation logic أعقد أو مخصص مش بتوفره الـ HTML لوحدها (زي مقارنة قيمتين ببعض، أو عمل تشيك معقد بناءً على اختيارات تانية في الفورم).
  • مميزاته:
    • فيدباك فوري (Immediate Feedback): أسرع طريقة نبلغ بيها اليوزر بالغلط.
    • تحسين الـ UX: بيخلي تجربة ملء الفورم أسلس وأقل إحباطًا.
    • تقليل الريكوستات الغلط للسيرفر: بيوفر bandwidth وموارد.
  • عيوبه:
    • غير آمن إطلاقًا! (Not Secure): اليوزر ببساطة ممكن يقفل الـ JavaScript في المتصفح، أو يعدل الـ HTML باستخدام الـ developer tools، أو يبعت الريكوست للسيرفر مباشرة باستخدام أدوات زي Postman أو curl، وبكده يتخطى كل الـ client-side validation ده بسهولة.
    • عشان كده: مينفعش نعتمد عليه لوحده أبدًا لضمان سلامة البيانات أو الأمان.

2. Server-Side Validation

  • فين بيحصل؟ على الـ web server بتاعك، بعد ما البيانات توصل من الـ client.
  • إمتى؟ بعد الـ submission وقبل ما الـ application يبدأ يعالج البيانات دي أو يخزنها في الـ database.
  • مين بيعمله؟ الكود اللي شغال على السيرفر (backend code)، مكتوب بأي لغة بتستخدمها (زي C#, Java, Python, Node.js, PHP, etc.).
  • مميزاته:
    • آمن وموثوق (Secure and Authoritative): ده خط الدفاع الحقيقي اللي مينفعش اليوزر يتخطاه (لأنه بيحصل عندك على السيرفر). هو الضمان الأخير لصحة وأمان البيانات.
    • القدرة على عمل تشيكات معقدة: السيرفر يقدر يعمل حاجات الـ client مينفعش يعملها أو مش آمن إنه يعملها، زي:
      • التشيك في الـ database (الإيميل ده موجود قبل كده؟ اليوزر ده ليه صلاحية يعمل كده؟).
      • التشيك قصاد business rules معقدة.
      • التكامل مع external services.
      • عمل validation بيعتمد على كذا معلومة مع بعض (cross-field validation).
  • عيوبه:
    • أبطأ في الفيدباك: اليوزر لازم يستنى الريكوست يروح ويرجع عشان يعرف لو فيه غلط.
    • بيستهلك موارد السيرفر: كل ريكوست بيحتاج معالجة.
  • عشان كده: هو أساسي ومفيش غنى عنه، بس بنحاول نخفف عنه باستخدام الـ client-side validation.

الأفضل والأصح: نستخدم الاتنين مع بعض!

الخلاصة إن الممارسة الصحيحة (best practice) هي استخدام مزيج من الاتنين:

  • الـ Client-side: عشان نحسن تجربة المستخدم وندي فيدباك سريع ونقلل الحمل غير الضروري.
  • الـ Server-side: عشان نضمن سلامة البيانات وأمان التطبيق بشكل قاطع. لازم دايما تعمل re-validate لكل البيانات اللي جاية من الـ client على السيرفر، حتى لو عملتلها validate في الـ client. قاعدة أساسية: “Never trust user input”.

طرق تطبيق الـ Validation (خصوصًا في الـ Backend)

لما نيجي نطبق الـ server-side validation، فيه كذا طريقة:

  1. الـ Manual Checks: الطريقة التقليدية إنك تكتب if/else statements في الكود بتاعك عشان تتشيك على كل قاعدة validation بنفسك. دي طريقة مباشرة لكن ممكن تبقى متعبة ومكررة لو عندك قواعد كتير.
  2. استخدام الـ Frameworks: معظم الـ web frameworks الحديثة بتقدم طرق أسهل وأكتر تنظيمًا للـ validation.

مثال: الـ Data Annotations في ASP.NET Core

اتكلمنا عنها في الـ 2. Data Annotation

زي ما ذكرت، في frameworks زي ASP.NET Core (MVC, Razor Pages, Blazor, API)، بنستخدم حاجة اسمها Data Annotations. دي عبارة عن attributes بنحطها فوق الـ properties في الـ Model classes بتاعتنا عشان نوصف قواعد الـ validation المطلوبة.

// Example using C# and Data Annotations in ASP.NET Core
public class EmployeeViewModel // Or DTO
{
    public int Id { get; set; }
 
    [Required(ErrorMessage = "اسم الموظف مطلوب")] // Makes this field required
    [StringLength(100, MinimumLength = 3, ErrorMessage = "الاسم لازم يكون بين 3 و 100 حرف")] // Length validation
    public string Name { get; set; }
 
    [Required(ErrorMessage = "الإيميل مطلوب")]
    [EmailAddress(ErrorMessage = "صيغة الإيميل غير صحيحة")] // Validates email format
    public string Email { get; set; }
 
    [Range(18, 60, ErrorMessage = "السن لازم يكون بين 18 و 60")] // Numeric range validation
    public int Age { get; set; }
 
    // Other properties...
}

جمال الـ Data Annotations هنا في فايدتها المزدوجة:

  • الـ Back-end Validation: الـ ASP.NET Core framework بيستخدم الـ Annotations دي تلقائيًا عشان يعمل validate للبيانات اللي جاية في الريكوست (كجزء من عملية الـ Model Binding) قبل ما الـ Action method بتاعتك تتنفذ. لو فيه أي validation errors، بيضيفها للـ ModelState وتقدر تتشيك عليها في الكود بتاعك. ده يعتبر الـ server-side validation الأساسي والرسمي في ASP.NET Core.
  • الـ Client-Side Validation Generation: الـ Framework (بمساعدة tag helpers ومكتبات JavaScript زي jQuery Unobtrusive Validation) بيقدر يقرأ نفس الـ Annotations دي ويعمل generate لـ HTML5 data attributes و JavaScript في الـ front-end عشان يعمل client-side validation بنفس القواعد دي من غير ما تكتب كود JavaScript مخصوص لكل قاعدة!

يعني بتكتب القاعدة مرة واحدة بالـ Annotation، والـ framework بيساعدك تطبقها في الناحيتين.

نقطة مهمة: فين نحط قواعد الـ Validation؟ (Domain Model vs. View Model)

دي نقطة ممتازة. هل صح نحط كل الـ Data Annotations بتاعة الـ validation دي على الـ Domain Model مباشرة (الـ Class اللي بيمثل الجدول في الـ Database، اللي بنقول عليه POCO Class

غالبًا لأ، مش دي أفضل ممارسة. ليه؟

  1. فصل الاهتمامات (Separation of Concerns): الـ Domain Model المفروض يركز على قواعد البيزنس الأساسية (core business logic and invariants) والحالة بتاعة الداتا اللي هتتخزن. أما الـ validation اللي بنحتاجه في الـ UI (زي رسائل الخطأ اللي بتظهر لليوزر، أو قواعد خاصة بفورم معينة) ده يعتبر جزء من اهتمامات الـ Presentation Layer.
  2. عدم تطابق الهياكل: ساعات الـ form اللي اليوزر بيشوفها مش بتبقى نسخة طبق الأصل من الـ Domain Model. ممكن تحتاج تجمع بيانات من كذا model أو تعرضها بشكل مختلف.
  3. الـ Over-posting/Mass Assignment Vulnerability: لو استخدمت الـ Domain Model مباشرة في الـ binding، ممكن اليوزر يبعت قيم لـ properties إنت مش عايزه يعدلها (زي IsAdmin مثلًا).

الحل إيه؟

نستخدم نمط (pattern) زي View Model أو DTO (Data Transfer Object).

  • الـ View Model/DTO: ده class بنعمله مخصوص عشان يمثل الداتا اللي الفورم أو الـ API endpoint محتاجها بالظبط.
  • بنحط الـ Data Annotations بتاعة الـ UI validation على الـ properties بتاعة الـ View Model / DTO ده.
  • في الـ Controller/Action method بتاعنا:
    • بنستقبل الـ View Model / DTO من الريكوست.
    • الـ Framework بيعمل validate للـ View Model / DTO ده باستخدام الـ Annotations بتاعته.
    • لو الـ validation نجح، بناخد الداتا من الـ View Model / DTO ونعمل mapping ليها للـ Domain Model(s) بتاعتنا قبل ما نتعامل مع الـ database أو الـ business logic.
    • الـ Domain Model نفسه ممكن يكون فيه بعض الـ validation الأساسي جدًا اللي بيمثل business invariants حقيقية، لكن معظم الـ validation الخاص بالمدخلات والشاشات بيكون في الـ View Model / DTO.

ده بيخلي الكود بتاعك أنظم، أأمن، وأسهل في الصيانة.

مش بس Forms: الـ API Validation

مهم نفتكر إن الـ validation مش بس للـ HTML forms. أي API endpoint عندك بيستقبل داتا (زي REST API) لازم ولابد يعمل server-side validation قوي جدًا، لأنه غالبًا معندوش UI أو client-side validation يعتمد عليه. نفس مبادئ الـ server-side validation (والـ Data Annotations لو بتستخدم framework زي ASP.NET Core) بتنطبق هنا.

الخلاصة

  • الـ Application Validation أساسي ومفيش غنى عنه لسلامة البيانات، الأمان، وتجربة المستخدم.
  • اعتمد دايمًا على Server-Side Validation كخط دفاع أساسي وموثوق.
  • استخدم Client-Side Validation لتحسين تجربة المستخدم وتقليل الحمل، لكن متعتمدش عليه لوحده.
  • استفيد من الأدوات اللي الـ frameworks بتقدمها (زي الـ Data Annotations) عشان تخلي عملية الـ validation أسهل ومنظمة.
  • فكر كويس فين تحط قواعد الـ validation بتاعتك، وغالبًا الـ View Models / DTOs هي المكان الأنسب لقواعد الـ UI validation.

الـ Validation ممكن يبان شغلانة زيادة، لكن الاستثمار فيه بيوفر عليك مشاكل وصداع كتير جدًا في المستقبل وبيخلي الـ application بتاعك أقوى وأكتر احترافية.