# بناء تطبيق مصرفي الجزء 3: طرق جلب البيانات واستخدامها تخيل حاسوب السفينة في مسلسل ستار تريك - عندما يسأل الكابتن بيكار عن حالة السفينة، تظهر المعلومات فورًا دون أن يتوقف النظام أو يعيد بناء نفسه. هذا التدفق السلس للمعلومات هو بالضبط ما نسعى لبنائه هنا من خلال جلب البيانات الديناميكي. في الوقت الحالي، تطبيقك المصرفي يشبه الصحيفة المطبوعة - مفيد ولكنه ثابت. سنقوم بتحويله إلى شيء يشبه مركز التحكم في ناسا، حيث تتدفق البيانات باستمرار وتُحدث في الوقت الفعلي دون أن تقاطع سير عمل المستخدم. ستتعلم كيفية التواصل مع الخوادم بشكل غير متزامن، وكيفية التعامل مع البيانات التي تصل في أوقات مختلفة، وكيفية تحويل المعلومات الخام إلى شيء ذو معنى لمستخدميك. هذا هو الفرق بين العرض التوضيحي والبرمجيات الجاهزة للإنتاج. ## ⚡ ما يمكنك القيام به في الـ 5 دقائق القادمة **مسار البداية السريعة للمطورين المشغولين** ```mermaid flowchart LR A[⚡ 5 minutes] --> B[Set up API server] B --> C[Test fetch with curl] C --> D[Create login function] D --> E[See data in action] ``` - **الدقيقة 1-2**: قم بتشغيل خادم API الخاص بك (`cd api && npm start`) واختبر الاتصال - **الدقيقة 3**: أنشئ وظيفة `getAccount()` الأساسية باستخدام fetch - **الدقيقة 4**: قم بتوصيل نموذج تسجيل الدخول بـ `action="javascript:login()"` - **الدقيقة 5**: اختبر تسجيل الدخول وشاهد بيانات الحساب تظهر في وحدة التحكم **أوامر الاختبار السريع**: ```bash # Verify API is running curl http://localhost:5000/api # Test account data fetch curl http://localhost:5000/api/accounts/test ``` **لماذا هذا مهم**: في 5 دقائق، ستشاهد سحر جلب البيانات غير المتزامن الذي يدعم كل تطبيق ويب حديث. هذا هو الأساس الذي يجعل التطبيقات تبدو مستجيبة وحيوية. ## 🗺️ رحلتك التعليمية عبر تطبيقات الويب المعتمدة على البيانات ```mermaid journey title From Static Pages to Dynamic Applications section Understanding the Evolution Traditional page reloads: 3: You Discover AJAX/SPA benefits: 5: You Master Fetch API patterns: 7: You section Building Authentication Create login functions: 4: You Handle async operations: 6: You Manage user sessions: 8: You section Dynamic UI Updates Learn DOM manipulation: 5: You Build transaction displays: 7: You Create responsive dashboards: 9: You section Professional Patterns Template-based rendering: 6: You Error handling strategies: 7: You Performance optimization: 8: You ``` **وجهة رحلتك**: بنهاية هذا الدرس، ستفهم كيف تقوم تطبيقات الويب الحديثة بجلب ومعالجة وعرض البيانات ديناميكيًا، مما يخلق تجارب مستخدم سلسة نتوقعها من التطبيقات الاحترافية. ## اختبار ما قبل المحاضرة [اختبار ما قبل المحاضرة](https://ff-quizzes.netlify.app/web/quiz/45) ### المتطلبات الأساسية قبل الغوص في جلب البيانات، تأكد من أن لديك هذه المكونات جاهزة: - **الدرس السابق**: أكمل [نموذج تسجيل الدخول والتسجيل](../2-forms/README.md) - سنبني على هذا الأساس - **الخادم المحلي**: قم بتثبيت [Node.js](https://nodejs.org) و[تشغيل خادم API](../api/README.md) لتوفير بيانات الحساب - **اتصال API**: اختبر اتصال الخادم الخاص بك باستخدام هذا الأمر: ```bash curl http://localhost:5000/api # Expected response: "Bank API v1.0.0" ``` هذا الاختبار السريع يضمن أن جميع المكونات تتواصل بشكل صحيح: - يتحقق من أن Node.js يعمل بشكل صحيح على نظامك - يؤكد أن خادم API الخاص بك نشط ويستجيب - يتحقق من أن تطبيقك يمكنه الوصول إلى الخادم (مثل التحقق من الاتصال اللاسلكي قبل بدء المهمة) ## 🧠 نظرة عامة على نظام إدارة البيانات ```mermaid mindmap root((Data Management)) Authentication Flow Login Process Form Validation Credential Verification Session Management User State Global Account Object Navigation Guards Error Handling API Communication Fetch Patterns GET Requests POST Requests Error Responses Data Formats JSON Processing URL Encoding Response Parsing Dynamic UI Updates DOM Manipulation Safe Text Updates Element Creation Template Cloning User Experience Real-time Updates Error Messages Loading States Security Considerations XSS Prevention textContent Usage Input Sanitization Safe HTML Creation CORS Handling Cross-Origin Requests Header Configuration Development Setup ``` **المبدأ الأساسي**: تطبيقات الويب الحديثة هي أنظمة تنسيق البيانات - تنسق بين واجهات المستخدم وواجهات برمجة التطبيقات للخادم ونماذج أمان المتصفح لإنشاء تجارب سلسة ومستجيبة. --- ## فهم جلب البيانات في تطبيقات الويب الحديثة طريقة تعامل تطبيقات الويب مع البيانات تطورت بشكل كبير على مدار العقدين الماضيين. فهم هذا التطور سيساعدك على تقدير قوة التقنيات الحديثة مثل AJAX وFetch API ولماذا أصبحت أدوات أساسية لمطوري الويب. دعونا نستكشف كيف كانت تعمل المواقع التقليدية مقارنة بالتطبيقات الديناميكية المستجيبة التي نبنيها اليوم. ### التطبيقات متعددة الصفحات التقليدية (MPA) في الأيام الأولى للويب، كان كل نقرة تشبه تغيير القنوات على تلفزيون قديم - الشاشة تصبح فارغة، ثم تبدأ في عرض المحتوى الجديد ببطء. كانت هذه هي حقيقة التطبيقات الويب القديمة، حيث كانت كل تفاعل يعني إعادة بناء الصفحة بالكامل من البداية. ```mermaid sequenceDiagram participant User participant Browser participant Server User->>Browser: Clicks link or submits form Browser->>Server: Requests new HTML page Note over Browser: Page goes blank Server->>Browser: Returns complete HTML page Browser->>User: Displays new page (flash/reload) ```  **لماذا كان هذا النهج يبدو غير سلس:** - كل نقرة تعني إعادة بناء الصفحة بالكامل من البداية - كان المستخدمون يتعرضون لانقطاع في التفكير بسبب تلك الومضات المزعجة للصفحة - كان اتصال الإنترنت يعمل بجهد إضافي لتحميل نفس الرأس والتذييل مرارًا وتكرارًا - كانت التطبيقات تبدو وكأنها تصفح ملفات بدلاً من استخدام البرمجيات ### التطبيقات أحادية الصفحة الحديثة (SPA) غيرت تقنية AJAX (JavaScript وXML غير المتزامن) هذا النموذج تمامًا. مثل التصميم المعياري لمحطة الفضاء الدولية، حيث يمكن لرواد الفضاء استبدال المكونات الفردية دون إعادة بناء الهيكل بالكامل، يسمح لنا AJAX بتحديث أجزاء محددة من صفحة الويب دون إعادة تحميل كل شيء. على الرغم من أن الاسم يشير إلى XML، إلا أننا نستخدم JSON في الغالب اليوم، لكن المبدأ الأساسي يبقى كما هو: تحديث ما يحتاج إلى التغيير فقط. ```mermaid sequenceDiagram participant User participant Browser participant JavaScript participant Server User->>Browser: Interacts with page Browser->>JavaScript: Triggers event handler JavaScript->>Server: Fetches only needed data Server->>JavaScript: Returns JSON data JavaScript->>Browser: Updates specific page elements Browser->>User: Shows updated content (no reload) ```  **لماذا التطبيقات أحادية الصفحة تبدو أفضل بكثير:** - يتم تحديث الأجزاء التي تغيرت فقط (ذكي، أليس كذلك؟) - لا مزيد من الانقطاعات المزعجة - يبقى المستخدمون في تدفقهم - بيانات أقل تنتقل عبر الشبكة تعني تحميل أسرع - كل شيء يبدو سريعًا ومستجيبًا، مثل التطبيقات على هاتفك ### التطور إلى Fetch API الحديث توفر المتصفحات الحديثة [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API)، الذي يحل محل [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) القديم. مثل الفرق بين تشغيل التلغراف واستخدام البريد الإلكتروني، يستخدم Fetch API الوعود لكتابة كود غير متزامن أنظف ويتعامل مع JSON بشكل طبيعي. | الميزة | XMLHttpRequest | Fetch API | |---------|----------------|----------| | **الصياغة** | معقدة تعتمد على الاستدعاءات | تعتمد على الوعود النظيفة | | **التعامل مع JSON** | يتطلب التحليل اليدوي | طريقة `.json()` مدمجة | | **التعامل مع الأخطاء** | معلومات محدودة عن الأخطاء | تفاصيل شاملة عن الأخطاء | | **الدعم الحديث** | توافق مع الإصدارات القديمة | وعود ES6+ وasync/await | > 💡 **توافق المتصفح**: أخبار جيدة - يعمل Fetch API في جميع المتصفحات الحديثة! إذا كنت فضوليًا بشأن الإصدارات المحددة، [caniuse.com](https://caniuse.com/fetch) يحتوي على القصة الكاملة للتوافق. > **الخلاصة:** - يعمل بشكل رائع في Chrome وFirefox وSafari وEdge (بشكل أساسي في كل مكان يتواجد فيه المستخدمون) - فقط Internet Explorer يحتاج إلى مساعدة إضافية (وبصراحة، حان الوقت للتخلي عن IE) - يجهزك تمامًا لأنماط async/await الأنيقة التي سنستخدمها لاحقًا ### تنفيذ تسجيل الدخول وجلب البيانات الآن دعونا ننفذ نظام تسجيل الدخول الذي يحول تطبيقك المصرفي من عرض ثابت إلى تطبيق وظيفي. مثل بروتوكولات المصادقة المستخدمة في المنشآت العسكرية الآمنة، سنقوم بالتحقق من بيانات المستخدم ثم توفير الوصول إلى بياناته المحددة. سنقوم ببناء هذا تدريجيًا، بدءًا من المصادقة الأساسية ثم إضافة قدرات جلب البيانات. #### الخطوة 1: إنشاء أساس وظيفة تسجيل الدخول افتح ملف `app.js` الخاص بك وأضف وظيفة `login` جديدة. ستتعامل هذه الوظيفة مع عملية مصادقة المستخدم: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **لنقم بتفصيل هذا:** - الكلمة المفتاحية `async`؟ تخبر JavaScript "مرحبًا، هذه الوظيفة قد تحتاج إلى الانتظار لبعض الأشياء" - نحن نحصل على النموذج الخاص بنا من الصفحة (لا شيء فاخر، فقط العثور عليه بواسطة معرفه) - ثم نقوم بسحب ما كتبه المستخدم كاسم مستخدم - إليك خدعة رائعة: يمكنك الوصول إلى أي إدخال نموذج بواسطة خاصية `name` - لا حاجة لاستدعاءات إضافية لـ getElementById! > 💡 **نمط الوصول إلى النموذج**: يمكن الوصول إلى كل عنصر تحكم في النموذج بواسطة اسمه (المحدد في HTML باستخدام خاصية `name`) كخاصية لعنصر النموذج. يوفر هذا طريقة نظيفة وسهلة للحصول على بيانات النموذج. #### الخطوة 2: إنشاء وظيفة جلب بيانات الحساب بعد ذلك، سنقوم بإنشاء وظيفة مخصصة لجلب بيانات الحساب من الخادم. يتبع هذا نفس النمط مثل وظيفة التسجيل الخاصة بك ولكنه يركز على جلب البيانات: ```javascript async function getAccount(user) { try { const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user)); return await response.json(); } catch (error) { return { error: error.message || 'Unknown error' }; } } ``` **ما يحققه هذا الكود:** - **يستخدم** Fetch API الحديث لطلب البيانات بشكل غير متزامن - **يبني** عنوان URL لطلب GET مع معلمة اسم المستخدم - **يطبق** `encodeURIComponent()` للتعامل بأمان مع الأحرف الخاصة في عناوين URL - **يحول** الاستجابة إلى صيغة JSON لتسهيل معالجة البيانات - **يتعامل** مع الأخطاء بشكل جيد عن طريق إرجاع كائن خطأ بدلاً من التعطل > ⚠️ **ملاحظة أمان**: وظيفة `encodeURIComponent()` تتعامل مع الأحرف الخاصة في عناوين URL. مثل أنظمة التشفير المستخدمة في الاتصالات البحرية، تضمن وصول رسالتك بالضبط كما هو مقصود، مما يمنع الأحرف مثل "#" أو "&" من أن يتم تفسيرها بشكل خاطئ. > **لماذا هذا مهم:** - يمنع الأحرف الخاصة من كسر عناوين URL - يحمي من هجمات التلاعب بعناوين URL - يضمن أن الخادم يتلقى البيانات المقصودة - يتبع ممارسات البرمجة الآمنة #### فهم طلبات HTTP GET إليك شيء قد يفاجئك: عندما تستخدم `fetch` بدون أي خيارات إضافية، فإنه ينشئ تلقائيًا طلب [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET). هذا مثالي لما نقوم به - طلب من الخادم "مرحبًا، هل يمكنني رؤية بيانات حساب هذا المستخدم؟" فكر في طلبات GET كطلب استعارة كتاب من المكتبة - تطلب رؤية شيء موجود بالفعل. طلبات POST (التي استخدمناها للتسجيل) تشبه أكثر تقديم كتاب جديد ليتم إضافته إلى المجموعة. | طلب GET | طلب POST | |-------------|-------------| | **الغرض** | استرجاع البيانات الموجودة | إرسال بيانات جديدة إلى الخادم | | **المعلمات** | في مسار/سلسلة استعلام URL | في جسم الطلب | | **التخزين المؤقت** | يمكن تخزينها مؤقتًا بواسطة المتصفحات | لا يتم تخزينها مؤقتًا عادةً | | **الأمان** | مرئية في عنوان URL/السجلات | مخفية في جسم الطلب | ```mermaid sequenceDiagram participant B as Browser participant S as Server Note over B,S: GET Request (Data Retrieval) B->>S: GET /api/accounts/test S-->>B: 200 OK + Account Data Note over B,S: POST Request (Data Submission) B->>S: POST /api/accounts + New Account Data S-->>B: 201 Created + Confirmation Note over B,S: Error Handling B->>S: GET /api/accounts/nonexistent S-->>B: 404 Not Found + Error Message ``` #### الخطوة 3: جمع كل شيء معًا الآن الجزء الممتع - دعونا نربط وظيفة جلب بيانات الحساب بعملية تسجيل الدخول. هنا حيث كل شيء يتكامل: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; const data = await getAccount(user); if (data.error) { return console.log('loginError', data.error); } account = data; navigate('/dashboard'); } ``` تتبع هذه الوظيفة تسلسلًا واضحًا: - استخراج اسم المستخدم من إدخال النموذج - طلب بيانات حساب المستخدم من الخادم - التعامل مع أي أخطاء تحدث أثناء العملية - تخزين بيانات الحساب والانتقال إلى لوحة التحكم عند النجاح > 🎯 **نمط Async/Await**: بما أن `getAccount` هي وظيفة غير متزامنة، نستخدم الكلمة المفتاحية `await` لإيقاف التنفيذ حتى يستجيب الخادم. هذا يمنع الكود من الاستمرار مع بيانات غير معرفة. #### الخطوة 4: إنشاء مكان لبياناتك تطبيقك يحتاج إلى مكان لتذكر معلومات الحساب بمجرد تحميلها. فكر في هذا كمكان ذاكرة قصيرة المدى لتطبيقك - مكان للحفاظ على بيانات المستخدم الحالي في متناول اليد. أضف هذا السطر في أعلى ملف `app.js` الخاص بك: ```javascript // This holds the current user's account data let account = null; ``` **لماذا نحتاج هذا:** - يحافظ على بيانات الحساب متاحة من أي مكان في تطبيقك - البدء بـ `null` يعني "لا أحد مسجل الدخول بعد" - يتم تحديثه عندما يسجل شخص ما الدخول أو التسجيل بنجاح - يعمل كمصدر واحد للحقيقة - لا يوجد ارتباك حول من هو مسجل الدخول #### الخطوة 5: توصيل النموذج الخاص بك الآن دعونا نربط وظيفة تسجيل الدخول الجديدة الخاصة بك بنموذج HTML الخاص بك. قم بتحديث علامة النموذج الخاصة بك على هذا النحو: ```html
``` **ما يفعله هذا التغيير الصغير:** - يوقف النموذج من القيام بسلوك "إعادة تحميل الصفحة بالكامل" الافتراضي - يستدعي وظيفة JavaScript المخصصة الخاصة بك بدلاً من ذلك - يحافظ على كل شيء سلسًا ومشابهًا لتطبيق الصفحة الواحدة - يمنحك التحكم الكامل في ما يحدث عندما يضغط المستخدمون على "تسجيل الدخول" #### الخطوة 6: تحسين وظيفة التسجيل الخاصة بك للحفاظ على التناسق، قم بتحديث وظيفة `register` الخاصة بك لتخزين بيانات الحساب أيضًا والانتقال إلى لوحة التحكم: ```javascript // Add these lines at the end of your register function account = result; navigate('/dashboard'); ``` **يوفر هذا التحسين:** - **انتقال سلس** من التسجيل إلى لوحة التحكم - **تجربة مستخدم متسقة** بين تدفقات تسجيل الدخول والتسجيل - **وصول فوري** إلى بيانات الحساب بعد التسجيل الناجح #### اختبار التنفيذ الخاص بك ```mermaid flowchart TD A[User enters credentials] --> B[Login function called] B --> C[Fetch account data from server] C --> D{Data received successfully?} D -->|Yes| E[Store account data globally] D -->|No| F[Display error message] E --> G[Navigate to dashboard] F --> H[User stays on login page] ``` **حان الوقت لتجربته:** 1. أنشئ حسابًا جديدًا للتأكد من أن كل شيء يعمل 2. حاول تسجيل الدخول باستخدام نفس بيانات الاعتماد 3. ألقِ نظرة على وحدة التحكم في المتصفح الخاص بك (F12) إذا كان هناك أي شيء يبدو غير صحيح 4. تأكد من أنك تصل إلى لوحة التحكم بعد تسجيل الدخول بنجاح إذا كان هناك شيء لا يعمل، لا داعي للذعر! معظم المشاكل يمكن حلها بسهولة مثل الأخطاء الإملائية أو نسيان تشغيل خادم API. #### كلمة سريعة عن السحر عبر الأصل قد تتساءل: "كيف يتحدث تطبيق الويب الخاص بي إلى خادم API هذا بينما يعملان على منافذ مختلفة؟" سؤال رائع! هذا يتعلق بشيء يواجهه كل مطور ويب في النهاية. > 🔒 **أمان عبر الأصل**: المتصفحات تفرض "سياسة الأصل نفسه" لمنع الاتصالات غير المصرح بها بين المجالات المختلفة. مثل نظام نقاط التفتيش في البنتاغون، يتحققون من أن الاتصال مصرح به قبل السماح بنقل البيانات. > **في إعدادنا:** - تطبيق الويب الخاص بك يعمل على `localhost:3000` (خادم التطوير) - خادم API الخاص بك يعمل على `localhost:5000` (الخادم الخلفي) - يتضمن خادم API [رؤوس CORS](https://developer.mozilla.org/docs/Web/HTTP/CORS) التي تسمح صراحةً بالاتصال من تطبيق الويب الخاص بك هذا التكوين يعكس تطوير العالم الحقيقي حيث تعمل التطبيقات الأمامية والخلفية عادةً على خوادم منفصلة. > 📚 **تعلم المزيد**: تعمق في واجهات برمجة التطبيقات وجلب البيانات مع هذا [الوحدة التعليمية الشاملة من Microsoft Learn حول واجهات برمجة التطبيقات](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## إحياء بياناتك في HTML الآن سنجعل البيانات التي تم جلبها مرئية للمستخدمين من خلال التلاعب بـ DOM. مثل عملية تطوير الصور في غرفة مظلمة، نحن نحول البيانات غير المرئية إلى شيء يمكن للمستخدمين رؤيته والتفاعل معه. التعامل مع DOM هو التقنية التي تحول صفحات الويب الثابتة إلى تطبيقات ديناميكية تقوم بتحديث محتواها بناءً على تفاعلات المستخدم واستجابات الخادم. ### اختيار الأداة المناسبة للعمل عندما يتعلق الأمر بتحديث HTML باستخدام JavaScript، لديك عدة خيارات. فكر في هذه الخيارات كأدوات مختلفة في صندوق الأدوات - كل واحدة مثالية لمهام معينة: | الطريقة | ما هي ممتازة له | متى تستخدمها | مستوى الأمان | |--------|---------------------|----------------|--------------| | `textContent` | عرض بيانات المستخدم بأمان | في أي وقت تعرض فيه نصًا | ✅ موثوق للغاية | | `createElement()` + `append()` | إنشاء تخطيطات معقدة | إنشاء أقسام/قوائم جديدة | ✅ آمن تمامًا | | `innerHTML` | إعداد محتوى HTML | ⚠️ حاول تجنب هذه الطريقة | ❌ محفوفة بالمخاطر | #### الطريقة الآمنة لعرض النص: textContent خاصية [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent) هي أفضل صديق لك عند عرض بيانات المستخدم. إنها مثل الحارس الشخصي لصفحتك على الويب - لا شيء ضار يمكن أن يمر: ```javascript // The safe, reliable way to update text const balanceElement = document.getElementById('balance'); balanceElement.textContent = account.balance; ``` **فوائد textContent:** - تعامل كل شيء كنص عادي (تمنع تنفيذ السكربتات) - تقوم بمسح المحتوى الموجود تلقائيًا - فعالة لتحديث النصوص البسيطة - توفر أمانًا مدمجًا ضد المحتوى الضار #### إنشاء عناصر HTML ديناميكية للحصول على محتوى أكثر تعقيدًا، اجمع بين [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) وطريقة [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append): ```javascript // Safe way to create new elements const transactionItem = document.createElement('div'); transactionItem.className = 'transaction-item'; transactionItem.textContent = `${transaction.date}: ${transaction.description}`; container.append(transactionItem); ``` **فهم هذا النهج:** - **ينشئ** عناصر DOM جديدة برمجيًا - **يحافظ** على التحكم الكامل في سمات العنصر ومحتواه - **يسمح** بإنشاء هياكل عناصر متداخلة ومعقدة - **يحافظ** على الأمان بفصل الهيكل عن المحتوى > ⚠️ **اعتبارات الأمان**: بينما تظهر خاصية [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) في العديد من الدروس، يمكنها تنفيذ السكربتات المضمنة. مثل بروتوكولات الأمان في CERN التي تمنع تنفيذ الأكواد غير المصرح بها، استخدام `textContent` و `createElement` يوفر بدائل أكثر أمانًا. > **مخاطر innerHTML:** - تنفذ أي علامات `