# Δημιουργία Εφαρμογής Τραπεζικής Πλατφόρμας Μέρος 3: Μέθοδοι Ανάκτησης και Χρήσης Δεδομένων Σκεφτείτε τον υπολογιστή του Enterprise στο Star Trek - όταν ο Captain Picard ζητά την κατάσταση του πλοίου, οι πληροφορίες εμφανίζονται άμεσα χωρίς να διακόπτεται η λειτουργία της διεπαφής ή να χρειάζεται να ξαναχτιστεί. Αυτή η ομαλή ροή πληροφοριών είναι ακριβώς αυτό που χτίζουμε εδώ με δυναμική ανάκτηση δεδομένων. Αυτή τη στιγμή, η τραπεζική σας εφαρμογή μοιάζει με μια τυπωμένη εφημερίδα - ενημερωτική αλλά στατική. Θα τη μεταμορφώσουμε σε κάτι που μοιάζει περισσότερο με το κέντρο ελέγχου της NASA, όπου τα δεδομένα ρέουν συνεχώς και ενημερώνονται σε πραγματικό χρόνο χωρίς να διακόπτεται η ροή εργασίας του χρήστη. Θα μάθετε πώς να επικοινωνείτε ασύγχρονα με διακομιστές, να χειρίζεστε δεδομένα που φτάνουν σε διαφορετικές χρονικές στιγμές και να μετατρέπετε ακατέργαστες πληροφορίες σε κάτι ουσιαστικό για τους χρήστες σας. Αυτή είναι η διαφορά μεταξύ μιας επίδειξης και ενός λογισμικού έτοιμου για παραγωγή. ## Ερωτηματολόγιο πριν τη διάλεξη [Ερωτηματολόγιο πριν τη διάλεξη](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 (Asynchronous JavaScript and 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). Όπως η διαφορά μεταξύ της λειτουργίας ενός τηλεγράφου και της χρήσης email, το Fetch API χρησιμοποιεί υποσχέσεις για καθαρότερο ασύγχρονο κώδικα και χειρίζεται το JSON φυσικά. | Χαρακτηριστικό | XMLHttpRequest | Fetch API | |----------------|----------------|-----------| | **Σύνταξη** | Πολύπλοκη με callbacks | Καθαρή με υποσχέσεις | | **Χειρισμός 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` attribute - δεν χρειάζονται επιπλέον κλήσεις getElementById! > 💡 **Μοτίβο Πρόσβασης Φόρμας**: Κάθε στοιχείο φόρμας μπορεί να προσπελαστεί μέσω του ονόματός του (ορισμένο στο HTML με το `name` attribute) ως ιδιότητα του στοιχείου φόρμας. Αυτό παρέχει έναν καθαρό, ευανάγνωστο τρόπο για την απόκτηση δεδομένων φόρμας. #### Βήμα 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()` για ασφαλή χειρισμό ειδικών χαρακτήρων σε URLs - **Μετατρέπει** την απάντηση σε μορφή JSON για εύκολη διαχείριση δεδομένων - **Χειρίζεται** σφάλματα με χάρη επιστρέφοντας ένα αντικείμενο σφάλματος αντί να καταρρεύσει > ⚠️ **Σημείωση Ασφαλείας**: Η λειτουργία `encodeURIComponent()` χειρίζεται ειδικούς χαρακτήρες σε URLs. Όπως τα συστήματα κωδικοποίησης στις ναυτικές επικοινωνίες, διασφαλίζει ότι το μήνυμά σας φτάνει ακριβώς όπως προοριζόταν, αποτρέποντας χαρακτήρες όπως "#" ή "&" από το να ερμηνευτούν λανθασμένα. > **Γιατί έχει σημασία:** - Αποτρέπει ειδικούς χαρακτήρες από το να σπάσουν τα URLs - Προστατεύει από επιθέσεις χειραγώγησης URLs - Διασφαλίζει ότι ο διακομιστής λαμβάνει τα δεδομένα όπως προοριζόταν - Ακολουθεί ασφαλείς πρακτικές κωδικοποίησης #### Κατανόηση Αιτήσεων HTTP GET Μια έκπληξη: όταν χρησιμοποιείτε το `fetch` χωρίς επιπλέον επιλογές, δημιουργεί αυτόματα μια αίτηση [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET). Αυτό είναι τέλειο για αυτό που κάνουμε - ζητάμε από τον διακομιστή "μπορώ να δω τα δεδομένα λογαριασμού αυτού του χρήστη;" Σκεφτείτε τις αιτήσεις GET σαν να ζητάτε ευγενικά να δανειστείτε ένα βιβλίο από τη βιβλιοθήκη - ζητάτε να δείτε κάτι που ήδη υπάρχει. Οι αιτήσεις POST (που χρησιμοποιήσαμε για την εγγραφή) μοιάζουν περισσότερο με την υποβολή ενός νέου βιβλίου για να προστεθεί στη συλλογή. | Αίτηση GET | Αίτηση POST | |------------|------------| | **Σκοπός** | Ανάκτηση υπαρχόντων δεδομένων | Αποστολή νέων δεδομένων στον διακομιστή | | **Παράμετροι** | Στο URL path/query string | Στο σώμα της αίτησης | | **Caching** | Μπορεί να αποθηκευτεί από περιηγητές | Συνήθως δεν αποθηκεύεται | | **Ασφάλεια** | Ορατό στο 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'); ``` **Αυτή η βελτίωση παρέχει:** - **Ομαλή** μετάβαση από την εγγραφή στον πίνακα ελέγχου - **Συνεπή** εμπειρία χρήστη μεταξύ των ροών εισόδου και εγγραφής - **Άμεση** πρόσβαση στα δεδομένα λογαριασμού μετά από επιτυχή εγγραφή #### Δοκιμή της Υλοποίησής σας @@CODE_BLOCK Για πιο σύνθετο περιεχόμενο, συνδυάστε τη μέθοδο [`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) εμφανίζεται σε πολλά μαθήματα, μπορεί να εκτελέσει ενσωματωμένα scripts. Όπως τα πρωτόκολλα ασφαλείας στο CERN που αποτρέπουν την εκτέλεση μη εξουσιοδοτημένου κώδικα, η χρήση των `textContent` και `createElement` παρέχει ασφαλέστερες εναλλακτικές λύσεις. > **Κίνδυνοι του innerHTML:** - Εκτελεί οποιαδήποτε `