# Rakenna pankkisovellus, osa 3: Tietojen hakeminen ja käyttö Ajattele Enterprise-aluksen tietokonetta Star Trekissä - 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ää rakennamme tässä dynaamisella tietojen hakemisella. Tällä hetkellä pankkisovelluksesi on kuin painettu sanomalehti - informatiivinen mutta staattinen. Muutamme sen joksikin NASA:n ohjauskeskuksen kaltaiseksi, jossa tiedot virtaavat jatkuvasti ja päivittyvät reaaliajassa keskeyttämättä käyttäjän työnkulkua. 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. ## Ennakkokysely [Ennakkokysely](https://ff-quizzes.netlify.app/web/quiz/45) ### Esivaatimukset Ennen kuin sukellat tietojen hakemiseen, 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 palvelinyhteytesi 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 oikein: - Varmistaa, että Node.js toimii oikein järjestelmässäsi - Vahvistaa, että API-palvelimesi on aktiivinen ja vastaa - Varmistaa, että sovelluksesi voi tavoittaa palvelimen (kuten tarkistettaisiin radiokontakti ennen tehtävää) --- ## Tietojen hakemisen ymmärtäminen moderneissa verkkosovelluksissa 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 niistä on tullut välttämättömiä työkaluja verkkokehittäjille. Tutkitaan, miten perinteiset verkkosivustot toimivat verrattuna dynaamisiin, responsiivisiin sovelluksiin, joita nykyään rakennamme. ### Perinteiset monisivuiset sovellukset (MPA) Verkon alkuaikoina jokainen klikkaus oli kuin kanavan vaihtaminen vanhassa televisiossa - ruutu meni pimeä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) ``` ![Päivitysprosessi monisivuisessa sovelluksessa](../../../../translated_images/mpa.7f7375a1a2d4aa779d3f928a2aaaf9ad76bcdeb05cfce2dc27ab126024050f51.fi.png) **Miksi tämä lähestymistapa tuntui kömpelöltä:** - Jokainen klikkaus tarkoitti koko sivun uudelleenrakentamista alusta - Käyttäjät keskeytyivät ä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äytöltä ### 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, että koko rakennetta tarvitsee rakentaa uudelleen, 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äivitetään 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) ``` ![Päivitysprosessi yksisivuisessa sovelluksessa](../../../../translated_images/spa.268ec73b41f992c2a21ef9294235c6ae597b3c37e2c03f0494c2d8857325cc57.fi.png) **Miksi SPA:t tuntuvat paremmilta:** - Vain ne osat, jotka oikeasti muuttuivat, päivitetään (fiksua, eikö?) - Ei enää häiritseviä keskeytyksiä - käyttäjät pysyvät työnsä parissa - Vähemmän dataa siirtyy verkon yli, mikä tarkoittaa nopeampaa latausta - Kaikki tuntuu sulavalta 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, perustuu takaisinsoittoihin | Selkeä, perustuu lupauksiin | | **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+ lupaukset 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 hyvin 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 tyylikkäisiin async/await-malleihin, joita käytämme myöhemmin ### Käyttäjän kirjautumisen ja tietojen hakemisen 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 annamme sitten pääsyn heidän erityisiin tietoihinsa. Rakennamme tämän vaiheittain, alkaen perusautentikoinnista ja lisäämällä sitten tietojen hakutoimintoja. #### Vaihe 1: Luo kirjautumistoiminnon 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:** - Tuo `async`-avainsana? Se kertoo JavaScriptille "hei, tämä funktio saattaa joutua odottamaan asioita" - Etsimme lomakkeen sivulta (ei mitään erikoista, vain etsimme sen ID:n perusteella) - Sitten otamme talteen sen, mitä käyttäjä kirjoitti käyttäjänimeksi - Tässä on näppärä temppu: voit käyttää mitä tahansa lomakekenttää sen `name`-attribuutin avulla - ei tarvitse tehdä ylimääräisiä getElementById-kutsuja! > 💡 **Lomakkeen käyttömalli**: Jokainen lomakekenttä voidaan käyttää sen nimen (HTML:ssä asetettu `name`-attribuutti) avulla lomake-elementin ominaisuutena. Tämä tarjoaa selkeän ja luettavan tavan saada lomaketiedot. #### Vaihe 2: Luo tilitietojen hakutoiminto Seuraavaksi luomme erillisen funktion tilitietojen hakemiseksi palvelimelta. Tämä noudattaa samaa mallia kuin rekisteröintifunktiosi, mutta keskittyy tietojen hakemiseen: ```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 asynkroniseen hakemiseen - **Muodostaa** GET-pyynnön URL:n käyttäjänimen parametrilla - **Käyttää** `encodeURIComponent()`-funktiota käsittelemään turvallisesti erikoismerkkejä URL-osoitteissa - **Muuntaa** vastauksen JSON-muotoon helppoa tietojen käsittelyä varten - **Käsittelee** virheet siististi palauttamalla virheobjektin kaatumisen sijaan > ⚠️ **Turvallisuusvinkki**: `encodeURIComponent()`-funktio käsittelee erikoismerkkejä URL-osoitteissa. Kuten koodausjärjestelmät merivoimien viestinnässä, se varmistaa, että viestisi saapuu juuri sellaisena kuin oli tarkoitus, estäen merkkien kuten "#" tai "&" väärinkäytön. > **Miksi tämä on tärkeää:** - Estää erikoismerkkejä rikkomasta URL-osoitteita - 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 Tässä on jotain, mikä saattaa yllättää sinut: 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ä on täydellinen siihen, mitä teemme - pyydämme palvelimelta "hei, voinko nähdä tämän käyttäjän tilitiedot?" Ajattele GET-pyyntöjä kuin kohteliaana tapana pyytää lainata kirjaa kirjastosta - pyydät nähdä jotain, mikä jo on 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 olevia tietoja | Lähettää uusia tietoja palvelimelle | | **Parametrit** | URL-polussa/kyselymerkkijonossa | Pyynnön sisällössä | | **Välimuisti** | Selaimet voivat välimuistittaa | Ei yleensä välimuistia | | **Turvallisuus** | Näkyy URL:ssa/lokeissa | Piilotettu pyynnön sisällössä | #### 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 tilitiedot palvelimelta - Käsittelee prosessin aikana mahdollisesti ilmenevät virheet - Tallentaa tilitiedot ja siirtyy onnistuneen kirjautumisen jälkeen hallintapaneeliin > 🎯 **Async/Await-malli**: Koska `getAccount` on asynkroninen funktio, käytämme `await`-avainsanaa pysäyttää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 voi muistaa ladatut tilitiedot. Ajattele tätä kuin sovelluksesi lyhytaikaisena muistina - paikka, 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 mistä 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 kirjautuneena #### Vaihe 5: Yhdistä lomakkeesi Nyt yhdistetään uusi hieno kirjautumisfunktiosi HTML-lomakkeeseesi. 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 sulavana 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öintifunktiota Johdonmukaisuuden vuoksi päivitä `register`-funktiosi myös tallentamaan tilitiedot ja siirtymään hallintapaneeliin: ```javascript // Add these lines at the end of your register function account = result; navigate('/dashboard'); ``` **Tämä parannus tarjoaa:** - **Saumattoman** siirtymän rekisteröinnistä hallintapaneeliin - **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:** 1. Luo uusi tili varmistaaksesi, että kaikki toimii 2. Kokeile kirjautua sisään samoilla tunnuksilla 3. Kurkista selaimesi konsoliin (F12), jos jokin vaikuttaa olevan pielessä 4. Varmista, että päädyt hallintapaneeliin onnistuneen kirjautumisen jälkeen Jos jokin ei toimi, älä panikoi! Useimmat ongelmat ovat yksinkertaisia korjata, kuten kirjoitusvirheet tai API-palvelimen käynnistämisen unohtaminen. #### Pieni sana Cross-Origin-taikuudesta Saatat miettiä: "Miten verkkosovellukseni voi kommunikoida tämän API-palvelimen kanssa, kun ne toimivat eri porteilla?" Hyvä kysymys! Tämä koskee asiaa, johon 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 tarkistuspistejä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-otsikot](https://developer.mozilla.org/docs/Web/HTTP/CORS), jotka nimenomaisesti valtuuttavat viestinnän verkkosovelluksestasi Tämä kokoonpano heijastaa todellista kehitystä, jossa frontend- ja backend-sovellukset toimivat tyypillisesti erillisillä palvelimilla. > 📚 **Lisätietoa**: Sukella syvemmälle API:hin ja tietojen hakemiseen tämän kattavan [Microsoft Learn -moduulin avulla](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## Tietojen tuominen eloon HTML:ssä Nyt teemme haetut tiedot näkyviksi käyttäjille DOM-manipulaation avulla. Kuten valokuvien kehittäminen pimiössä, otamme näkymättömän datan ja muutamme sen joksikin, mitä käyttäjät voivat nähdä ja käyttää. DOM-manipulaatio on tekniikka, joka muuttaa staattiset verkkosivut dynaamisiksi sovelluksiksi, jotka päivittävät sisältöään käyttäjän vuorovaikutuksen 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 eri työkaluja työkalupakissa - jokainen sopii täydellisesti tiettyihin tehtäviin: | Menetelmä | Missä se on hyvä | Milloin käyttää | Turvallisuustaso | |-----------|------------------|-----------------|------------------| | `textContent` | Käyttäjätietojen turvallinen näyttäminen | Aina kun näytät tekstiä | ✅ Erittäin turvallinen Yhdistä monimutkaisempaa sisältöä varten [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) -metodi [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append) -metodiin: ```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 - **Tarjoaa** täyden hallinnan elementtien attribuuteista 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) esiintyy monissa opetusohjelmissa, se voi suorittaa upotettuja skriptejä. Kuten CERNin turvallisuusprotokollat estävät luvattoman koodin suorittamisen, `textContent` ja `createElement` tarjoavat turvallisempia vaihtoehtoja. > **innerHTML:n riskit:** - Suorittaa käyttäjän datassa olevat `