# בניית אפליקציית בנקאות חלק 3: שיטות לשליפת נתונים ושימוש בהם תחשבו על המחשב של האנטרפרייז ב"מסע בין כוכבים" - כשקפטן פיקארד מבקש מידע על מצב הספינה, המידע מופיע מיד בלי שהממשק כולו יקרוס ויבנה את עצמו מחדש. הזרימה החלקה הזו של מידע היא בדיוק מה שאנחנו בונים כאן עם שליפת נתונים דינמית. כרגע, אפליקציית הבנקאות שלכם היא כמו עיתון מודפס - אינפורמטיבית אבל סטטית. אנחנו הולכים להפוך אותה למשהו יותר כמו מרכז הבקרה של נאס"א, שבו נתונים זורמים באופן רציף ומתעדכנים בזמן אמת בלי להפריע למשתמש. תלמדו איך לתקשר עם שרתים בצורה אסינכרונית, להתמודד עם נתונים שמגיעים בזמנים שונים, ולהפוך מידע גולמי למשהו משמעותי עבור המשתמשים שלכם. זה ההבדל בין דמו לתוכנה מוכנה לייצור. ## שאלון לפני ההרצאה [שאלון לפני ההרצאה](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 פעיל ומגיב - מוודאת שהאפליקציה שלכם יכולה להגיע לשרת (כמו בדיקת קשר רדיו לפני משימה) --- ## הבנת שליפת נתונים באפליקציות ווב מודרניות האופן שבו אפליקציות ווב מתמודדות עם נתונים השתנה באופן דרמטי בעשרים השנים האחרונות. הבנת האבולוציה הזו תעזור לכם להעריך מדוע טכניקות מודרניות כמו 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) ```  **למה SPA מרגישות כל כך טוב:** - רק החלקים שבאמת השתנו מתעדכנים (חכם, נכון?) - אין יותר הפרעות פתאומיות - המשתמשים שלכם נשארים בזרימה שלהם - פחות נתונים עוברים ברשת, מה שאומר טעינה מהירה יותר - הכל מרגיש מהיר ותגובתי, כמו האפליקציות בטלפון שלכם ### האבולוציה ל-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 "היי, הפונקציה הזו עשויה להזדקק להמתנה לדברים" - אנחנו שולפים את הטופס מהעמוד (לא משהו מפואר, פשוט מוצאים אותו לפי ה-ID שלו) - ואז אנחנו שולפים את מה שהמשתמש הקליד בתור שם המשתמש שלו - הנה טריק נחמד: אתם יכולים לגשת לכל קלט טופס לפי תכונת `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/יומנים | מוסתר בגוף הבקשה | #### שלב 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. #### מילה מהירה על קסם בין-מקורי אולי אתם תוהים: "איך האפליקצ לשימוש בתוכן מורכב יותר, שלבו את [`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:** - מריץ כל תג `