# Rakenna pankkisovellus, osa 3: Tietojen hakeminen ja käyttäminen Ajattele Star Trekin Enterprise-aluksen tietokonetta - kun kapteeni Picard kysyy aluksen tilasta, tiedot ilmestyvät välittömästi ilman, että koko käyttöliittymä sulkeutuu ja rakentuu uudelleen. Juuri tällaista saumattoman tiedonkulun järjestelmää olemme rakentamassa dynaamisella tiedonhakumenetelmällä. Tällä hetkellä pankkisovelluksesi on kuin painettu sanomalehti - informatiivinen mutta staattinen. Muutamme sen NASA:n ohjauskeskuksen kaltaiseksi, jossa tiedot virtaavat jatkuvasti ja päivittyvät reaaliajassa keskeyttämättä käyttäjän työskentelyä. Opit kommunikoimaan palvelimien kanssa asynkronisesti, käsittelemään eri aikoina saapuvia tietoja ja muuntamaan raakadataa käyttäjille merkitykselliseksi. Tämä erottaa demoversion tuotantovalmiista ohjelmistosta. ## ⚡ Mitä voit tehdä seuraavien 5 minuutin aikana **Nopea aloitus kiireisille kehittäjille** ```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] ``` - **Minuutit 1-2**: Käynnistä API-palvelin (`cd api && npm start`) ja testaa yhteys - **Minuutti 3**: Luo yksinkertainen `getAccount()`-funktio käyttäen fetchiä - **Minuutti 4**: Yhdistä kirjautumislomake `action="javascript:login()"` - **Minuutti 5**: Testaa kirjautuminen ja katso, kuinka tilitiedot ilmestyvät konsoliin **Nopeat testikomennot**: ```bash # Verify API is running curl http://localhost:5000/api # Test account data fetch curl http://localhost:5000/api/accounts/test ``` **Miksi tämä on tärkeää**: Viidessä minuutissa näet asynkronisen tiedonhakumenetelmän taian, joka on jokaisen modernin verkkosovelluksen voimanlähde. Tämä on perusta, joka saa sovellukset tuntumaan responsiivisilta ja eläviltä. ## 🗺️ Oppimispolkusi dataohjattujen verkkosovellusten parissa ```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 ``` **Oppimispolkusi päämäärä**: Tämän oppitunnin lopussa ymmärrät, kuinka modernit verkkosovellukset hakevat, käsittelevät ja näyttävät tietoja dynaamisesti, luoden saumattomia käyttäjäkokemuksia, joita odotamme ammattimaisilta sovelluksilta. ## Ennakkokysely [Ennakkokysely](https://ff-quizzes.netlify.app/web/quiz/45) ### Esivaatimukset Ennen kuin sukellat tiedonhakuun, varmista, että sinulla on nämä komponentit valmiina: - **Edellinen oppitunti**: Suorita [Kirjautumis- ja rekisteröintilomake](../2-forms/README.md) - rakennamme tämän pohjalta - **Paikallinen palvelin**: Asenna [Node.js](https://nodejs.org) ja [käynnistä palvelin-API](../api/README.md) tilitietojen tarjoamiseksi - **API-yhteys**: Testaa palvelinyhteys tällä komennolla: ```bash curl http://localhost:5000/api # Expected response: "Bank API v1.0.0" ``` Tämä nopea testi varmistaa, että kaikki komponentit kommunikoivat kunnolla: - Varmistaa, että Node.js toimii oikein järjestelmässäsi - Vahvistaa, että API-palvelimesi on aktiivinen ja vastaa - Tarkistaa, että sovelluksesi voi tavoittaa palvelimen (kuten radiokontaktin tarkistus ennen tehtävää) ## 🧠 Tiedonhallinnan ekosysteemin yleiskatsaus ```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 ``` **Keskeinen periaate**: Modernit verkkosovellukset ovat tiedon orkestrointijärjestelmiä - ne koordinoivat käyttäjäliittymien, palvelin-API:iden ja selaimen turvallisuusmallien välillä luodakseen saumattomia, responsiivisia kokemuksia. --- ## Tiedonhaku modernissa verkkosovelluksessa Tapa, jolla verkkosovellukset käsittelevät tietoja, on kehittynyt dramaattisesti viimeisten kahden vuosikymmenen aikana. Tämän kehityksen ymmärtäminen auttaa sinua arvostamaan, miksi modernit tekniikat, kuten AJAX ja Fetch API, ovat niin tehokkaita ja miksi ne ovat tärkeitä työkaluja verkkokehittäjille. Tutkitaan, miten perinteiset verkkosivustot toimivat verrattuna dynaamisiin, responsiivisiin sovelluksiin, joita nykyään rakennamme. ### Perinteiset monisivuiset sovellukset (MPA) Verkon alkuvaiheessa jokainen klikkaus oli kuin kanavan vaihtaminen vanhassa televisiossa - ruutu meni tyhjäksi ja sitten hitaasti virittyi uuteen sisältöön. Tämä oli todellisuutta varhaisissa verkkosovelluksissa, joissa jokainen vuorovaikutus tarkoitti koko sivun uudelleenrakentamista alusta alkaen. ```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) ```  **Miksi tämä lähestymistapa tuntui kömpelöltä:** - Jokainen klikkaus tarkoitti koko sivun uudelleenrakentamista - Käyttäjät keskeytyivät kesken ajatuksen ärsyttävien sivuvälähdysten takia - Internet-yhteytesi teki ylitöitä ladatessaan samaa otsikkoa ja alatunnistetta toistuvasti - Sovellukset tuntuivat enemmän arkistokaapin selaamiselta kuin ohjelmiston käyttämiseltä ### Modernit yksisivuiset sovellukset (SPA) AJAX (Asynchronous JavaScript and XML) muutti tämän paradigman täysin. Kuten kansainvälisen avaruusaseman modulaarinen suunnittelu, jossa astronautit voivat korvata yksittäisiä komponentteja ilman koko rakenteen uudelleenrakentamista, AJAX mahdollistaa tiettyjen verkkosivun osien päivittämisen ilman, että koko sivua ladataan uudelleen. Vaikka nimi mainitsee XML:n, käytämme nykyään enimmäkseen JSON:ia, mutta perusperiaate pysyy samana: päivitä vain se, mikä tarvitsee muuttua. ```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) ```  **Miksi SPA:t tuntuvat niin paljon paremmilta:** - Vain ne osat, jotka oikeasti muuttuivat, päivitetään (fiksua, eikö?) - Ei enää häiritseviä keskeytyksiä - käyttäjät pysyvät flow-tilassa - Vähemmän dataa siirtyy verkon yli, mikä tarkoittaa nopeampaa latausta - Kaikki tuntuu nopealta ja responsiiviselta, kuten puhelimen sovellukset ### Kehitys kohti modernia Fetch API:ta Modernit selaimet tarjoavat [`Fetch` API:n](https://developer.mozilla.org/docs/Web/API/Fetch_API), joka korvaa vanhemman [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Kuten ero lennättimen ja sähköpostin välillä, Fetch API käyttää lupauksia siistimpään asynkroniseen koodiin ja käsittelee JSON:ia luonnollisesti. | Ominaisuus | XMLHttpRequest | Fetch API | |------------|----------------|-----------| | **Syntaksi** | Monimutkainen, callback-pohjainen | Siisti, promise-pohjainen | | **JSON-käsittely** | Vaatii manuaalista jäsentämistä | Sisäänrakennettu `.json()`-metodi | | **Virheenkäsittely** | Rajoitettu virhetieto | Kattavat virhetiedot | | **Moderni tuki** | Yhteensopiva vanhojen järjestelmien kanssa | ES6+ promises ja async/await | > 💡 **Selainten yhteensopivuus**: Hyviä uutisia - Fetch API toimii kaikissa moderneissa selaimissa! Jos olet utelias tiettyjen versioiden suhteen, [caniuse.com](https://caniuse.com/fetch) tarjoaa täydellisen yhteensopivuustiedon. > **Yhteenveto:** - Toimii erinomaisesti Chromessa, Firefoxissa, Safarissa ja Edgessä (käytännössä kaikkialla, missä käyttäjäsi ovat) - Vain Internet Explorer tarvitsee lisäapua (ja rehellisesti, on aika päästää IE menemään) - Valmistaa sinut täydellisesti elegantteihin async/await-malleihin, joita käytämme myöhemmin ### Käyttäjän kirjautumisen ja tiedonhakemisen toteuttaminen Nyt toteutamme kirjautumisjärjestelmän, joka muuttaa pankkisovelluksesi staattisesta näytöstä toimivaksi sovellukseksi. Kuten turvallisuusprotokollat, joita käytetään sotilaslaitoksissa, varmistamme käyttäjän tunnistetiedot ja tarjoamme sitten pääsyn heidän erityisiin tietoihinsa. Rakennamme tämän vaiheittain, alkaen perusautentikoinnista ja lisäämällä sitten tiedonhakutoiminnallisuudet. #### Vaihe 1: Luo kirjautumisfunktion perusta Avaa `app.js`-tiedostosi ja lisää uusi `login`-funktio. Tämä käsittelee käyttäjän autentikointiprosessin: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **Puretaan tämä osiin:** - `async`-avainsana kertoo JavaScriptille "hei, tämä funktio saattaa joutua odottamaan asioita" - Etsimme lomakkeen sivulta (ei mitään monimutkaista, vain ID:n perusteella) - Sitten otamme talteen käyttäjän kirjoittaman käyttäjänimen - Tässä on näppärä niksi: voit käyttää mitä tahansa lomakekenttää sen `name`-attribuutin avulla - ei tarvitse erikseen käyttää getElementById-kutsuja! > 💡 **Lomakkeen käyttömalli**: Jokainen lomakekenttä voidaan hakea sen nimellä (asetettu HTML:ssä `name`-attribuutilla) lomake-elementin ominaisuutena. Tämä tarjoaa siistin ja luettavan tavan saada lomakedata. #### Vaihe 2: Luo tilitietojen hakufunktio Seuraavaksi luomme erillisen funktion tilitietojen hakemiseksi palvelimelta. Tämä noudattaa samaa kaavaa kuin rekisteröintifunktiosi, mutta keskittyy tiedonhakuun: ```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' }; } } ``` **Tämä koodi tekee seuraavaa:** - **Käyttää** modernia `fetch` API:a tietojen hakemiseen asynkronisesti - **Rakentaa** GET-pyynnön URL:n käyttäjänimen parametrilla - **Käyttää** `encodeURIComponent()`-funktiota käsittelemään erikoismerkkejä URL:ssa turvallisesti - **Muuntaa** vastauksen JSON-muotoon helppoa datan käsittelyä varten - **Käsittelee** virheet siististi palauttamalla virheobjektin sen sijaan, että kaatuisi > ⚠️ **Turvallisuusvinkki**: `encodeURIComponent()`-funktio käsittelee erikoismerkkejä URL:ssa. Kuten koodausjärjestelmät merivoimien viestinnässä, se varmistaa, että viestisi saapuu juuri sellaisena kuin oli tarkoitettu, estäen merkit kuten "#" tai "&" tulkitsemasta väärin. > **Miksi tämä on tärkeää:** - Estää erikoismerkkejä rikkomasta URL:ia - Suojaa URL-manipulaatiohyökkäyksiltä - Varmistaa, että palvelimesi vastaanottaa tarkoitetut tiedot - Noudattaa turvallisen koodauksen käytäntöjä #### HTTP GET -pyyntöjen ymmärtäminen Saatat yllättyä: kun käytät `fetch`-funktiota ilman lisäasetuksia, se luo automaattisesti [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET)-pyynnön. Tämä sopii täydellisesti siihen, mitä teemme - pyydämme palvelinta "hei, voinko nähdä tämän käyttäjän tilitiedot?" Ajattele GET-pyyntöjä kuin kohteliasta kirjan lainaamista kirjastosta - pyydät nähdäksesi jotain, joka jo olemassa. POST-pyynnöt (joita käytimme rekisteröinnissä) ovat enemmän kuin uuden kirjan lähettämistä lisättäväksi kokoelmaan. | GET-pyyntö | POST-pyyntö | |------------|-------------| | **Tarkoitus** | Hakea olemassa olevaa dataa | Lähettää uutta dataa palvelimelle | | **Parametrit** | URL-polussa/kyselymerkkijonossa | Pyynnön rungossa | | **Välimuisti** | Selaimet voivat välimuistittaa | Ei yleensä välimuistia | | **Turvallisuus** | Näkyy URL:ssa/lokeissa | Piilotettu pyynnön rungossa | ```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 ``` #### Vaihe 3: Yhdistä kaikki yhteen Nyt tyydyttävä osa - yhdistetään tilitietojen hakufunktio kirjautumisprosessiin. Tässä kaikki loksahtaa paikoilleen: ```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'); } ``` Tämä funktio seuraa selkeää järjestystä: - Ottaa käyttäjänimen lomakekentästä - Pyytää käyttäjän tilitietoja palvelimelta - Käsittelee mahdolliset virheet prosessin aikana - Tallentaa tilitiedot ja siirtyy onnistuneen kirjautumisen jälkeen etusivulle > 🎯 **Async/Await-malli**: Koska `getAccount` on asynkroninen funktio, käytämme `await`-avainsanaa keskeyttääksemme suorituksen, kunnes palvelin vastaa. Tämä estää koodia jatkamasta määrittelemättömillä tiedoilla. #### Vaihe 4: Luo paikka tiedoillesi Sovelluksesi tarvitsee paikan, jossa se muistaa tilitiedot, kun ne on ladattu. Ajattele tätä sovelluksesi lyhytaikaisena muistina - paikkana, jossa nykyisen käyttäjän tiedot pidetään käden ulottuvilla. Lisää tämä rivi `app.js`-tiedoston alkuun: ```javascript // This holds the current user's account data let account = null; ``` **Miksi tämä on tarpeen:** - Pitää tilitiedot saatavilla missä tahansa sovelluksessasi - Aloittaminen `null`-arvolla tarkoittaa "kukaan ei ole vielä kirjautunut sisään" - Päivitetään, kun joku kirjautuu tai rekisteröityy onnistuneesti - Toimii yhtenä totuuden lähteenä - ei sekaannusta siitä, kuka on kirjautunut sisään #### Vaihe 5: Yhdistä lomakkeesi Yhdistetään nyt uusi hieno kirjautumisfunktiosi HTML-lomakkeeseen. Päivitä lomaketunnisteesi näin: ```html
``` **Mitä tämä pieni muutos tekee:** - Estää lomaketta tekemästä oletusarvoista "lataa koko sivu uudelleen" -toimintoa - Kutsuu mukautettua JavaScript-funktiotasi sen sijaan - Pitää kaiken sujuvana ja yksisivuisen sovelluksen kaltaisena - Antaa sinulle täydellisen hallinnan siitä, mitä tapahtuu, kun käyttäjät painavat "Kirjaudu sisään" #### Vaihe 6: Paranna rekisteröintifunktiotasi Johdonmukaisuuden vuoksi päivitä `register`-funktiosi myös tallentamaan tilitiedot ja siirtymään etusivulle: ```javascript // Add these lines at the end of your register function account = result; navigate('/dashboard'); ``` **Tämä parannus tarjoaa:** - **Saumattoman** siirtymän rekisteröinnistä etusivulle - **Johdonmukaisen** käyttäjäkokemuksen kirjautumis- ja rekisteröintivaiheiden välillä - **Välittömän** pääsyn tilitietoihin onnistuneen rekisteröinnin jälkeen #### Toteutuksen testaaminen ```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] ``` **Aika kokeilla käytännössä:** 1. Luo uusi tili varmistaaksesi, että kaikki toimii 2. Kokeile kirjautua sisään samoilla tunnuksilla 3. Kurkista selaimesi konsoliin (F12), jos jokin vaikuttaa oudolta 4. Varmista, että päädyt etusivulle onnistuneen kirjautumisen jälkeen Jos jokin ei toimi, älä panikoi! Useimmat ongelmat ovat yksinkertaisia korjattavia, kuten kirjoitusvirheitä tai API-palvelimen käynnistämisen unohtaminen. #### Pieni sana Cross-Origin-taikuudesta Saatat miettiä: "Kuinka verkkosovellukseni voi kommunikoida tämän API-palvelimen kanssa, kun ne toimivat eri porteilla?" Hyvä kysymys! Tämä koskettaa jotain, mihin jokainen verkkokehittäjä törmää lopulta. > 🔒 **Cross-Origin-turvallisuus**: Selaimet noudattavat "saman alkuperän politiikkaa" estääkseen luvattoman viestinnän eri verkkotunnusten välillä. Kuten Pentagonin tarkastuspistejärjestelmä, ne varmistavat, että viestintä on valtuutettua ennen kuin sallivat tiedonsiirron. > **Meidän asetuksessamme:** - Verkkosovelluksesi toimii `localhost:3000` (kehityspalvelin) - API-palvelimesi toimii `localhost:5000` (taustapalvelin) - API-palvelin sisältää [CORS- DOM-manipulointi on tekniikka, joka muuttaa staattiset verkkosivut dynaamisiksi sovelluksiksi, jotka päivittävät sisältöään käyttäjän toimien ja palvelimen vastausten perusteella. ### Valitse oikea työkalu tehtävään Kun päivität HTML:ää JavaScriptillä, sinulla on useita vaihtoehtoja. Ajattele näitä kuin työkaluja työkalupakissa - jokainen sopii täydellisesti tiettyyn tehtävään: | Menetelmä | Mihin se sopii | Milloin käyttää | Turvallisuustaso | |-----------|----------------|-----------------|------------------| | `textContent` | Käyttäjädatan turvallinen näyttäminen | Aina kun näytät tekstiä | ✅ Erittäin turvallinen | | `createElement()` + `append()` | Monimutkaisten rakenteiden luominen | Uusien osioiden/listojen luominen | ✅ Luotettava | | `innerHTML` | HTML-sisällön asettaminen | ⚠️ Vältä tätä mahdollisuuksien mukaan | ❌ Riskialtis #### Turvallinen tapa näyttää teksti: textContent [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent)-ominaisuus on paras ystäväsi, kun näytät käyttäjädataa. Se toimii kuin portinvartija verkkosivullesi - mikään haitallinen ei pääse läpi: ```javascript // The safe, reliable way to update text const balanceElement = document.getElementById('balance'); balanceElement.textContent = account.balance; ``` **textContentin edut:** - Käsittelee kaiken tavallisena tekstinä (estää skriptien suorittamisen) - Tyhjentää automaattisesti olemassa olevan sisällön - Tehokas yksinkertaisten tekstipäivitysten tekemiseen - Tarjoaa sisäänrakennetun suojan haitalliselta sisällöltä #### Dynaamisten HTML-elementtien luominen Monimutkaisempaa sisältöä varten yhdistä [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) ja [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append)-menetelmä: ```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); ``` **Tämän lähestymistavan ymmärtäminen:** - **Luo** uusia DOM-elementtejä ohjelmallisesti - **Säilyttää** täyden hallinnan elementtien ominaisuuksista ja sisällöstä - **Mahdollistaa** monimutkaiset, sisäkkäiset elementtirakenteet - **Säilyttää** turvallisuuden erottamalla rakenne sisällöstä > ⚠️ **Turvallisuushuomio**: Vaikka [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) näkyy monissa opetusohjelmissa, se voi suorittaa upotettuja skriptejä. Kuten CERNin turvallisuusprotokollat, jotka estävät luvattoman koodin suorittamisen, `textContent` ja `createElement` tarjoavat turvallisempia vaihtoehtoja. > **innerHTML:n riskit:** - Suorittaa käyttäjädatan sisältämät `