# Rakenna pankkisovellus Osa 3: Datan hakeminen ja käyttäminen ## Ennakkokysely [Ennakkokysely](https://ff-quizzes.netlify.app/web/quiz/45) ### Johdanto Jokaisen verkkosovelluksen ytimessä on *data*. Data voi esiintyä monessa muodossa, mutta sen pääasiallinen tarkoitus on aina esittää tietoa käyttäjälle. Verkkosovellusten muuttuessa yhä vuorovaikutteisemmiksi ja monimutkaisemmiksi, siitä, miten käyttäjä pääsee käsiksi tietoon ja käyttää sitä, on tullut keskeinen osa verkkokehitystä. Tässä oppitunnissa opimme hakemaan dataa palvelimelta asynkronisesti ja käyttämään tätä dataa tiedon näyttämiseen verkkosivulla ilman HTML-sivun uudelleenlatausta. ### Esitiedot Sinun tulee olla rakentanut [Kirjautumis- ja rekisteröintilomake](../2-forms/README.md) -osio verkkosovelluksesta ennen tämän oppitunnin aloittamista. Sinun tulee myös asentaa [Node.js](https://nodejs.org) ja [käynnistää palvelin-API](../api/README.md) paikallisesti, jotta saat tilitietoja. Voit testata, että palvelin toimii oikein suorittamalla tämän komennon terminaalissa: ```sh curl http://localhost:5000/api # -> should return "Bank API v1.0.0" as a result ``` --- ## AJAX ja datan hakeminen Perinteiset verkkosivustot päivittävät näytettävää sisältöä, kun käyttäjä valitsee linkin tai lähettää tietoja lomakkeella, lataamalla koko HTML-sivun uudelleen. Joka kerta, kun uutta dataa täytyy ladata, verkkopalvelin palauttaa täysin uuden HTML-sivun, joka selaimen täytyy käsitellä. Tämä keskeyttää käyttäjän nykyisen toiminnon ja rajoittaa vuorovaikutusta latauksen aikana. Tätä työnkulkua kutsutaan myös *monisivusovellukseksi* tai *MPA:ksi*.  Kun verkkosovellukset alkoivat muuttua monimutkaisemmiksi ja vuorovaikutteisemmiksi, syntyi uusi tekniikka nimeltä [AJAX (Asynchronous JavaScript and XML)](https://en.wikipedia.org/wiki/Ajax_(programming)). Tämä tekniikka mahdollistaa verkkosovellusten lähettää ja vastaanottaa dataa palvelimelta asynkronisesti JavaScriptin avulla ilman HTML-sivun uudelleenlatausta, mikä johtaa nopeampiin päivityksiin ja sujuvampaan käyttäjäkokemukseen. Kun uutta dataa saadaan palvelimelta, nykyistä HTML-sivua voidaan myös päivittää JavaScriptin avulla käyttäen [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)-rajapintaa. Ajan myötä tämä lähestymistapa on kehittynyt siihen, mitä nykyään kutsutaan [*yksisivusovellukseksi* tai *SPA:ksi*](https://en.wikipedia.org/wiki/Single-page_application).  Kun AJAX esiteltiin ensimmäisen kerran, ainoa käytettävissä oleva rajapinta datan asynkroniseen hakemiseen oli [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Modernit selaimet tukevat kuitenkin nykyään myös kätevämpää ja tehokkaampaa [`Fetch` APIa](https://developer.mozilla.org/docs/Web/API/Fetch_API), joka käyttää promiseja ja soveltuu paremmin JSON-datan käsittelyyn. > Vaikka kaikki modernit selaimet tukevat `Fetch APIa`, jos haluat verkkosovelluksesi toimivan vanhoissa selaimissa, on aina hyvä tarkistaa [yhteensopivuustaulukko caniuse.com-sivustolta](https://caniuse.com/fetch). ### Tehtävä [Edellisessä oppitunnissa](../2-forms/README.md) toteutimme rekisteröintilomakkeen tilin luomista varten. Nyt lisäämme koodia kirjautumiseen olemassa olevalla tilillä ja datan hakemiseen. Avaa `app.js`-tiedosto ja lisää uusi `login`-funktio: ```js async function login() { const loginForm = document.getElementById('loginForm') const user = loginForm.user.value; } ``` Aloitamme hakemalla lomake-elementin `getElementById()`-metodilla ja saamme sitten käyttäjänimen syötteestä `loginForm.user.value` avulla. Jokainen lomakekontrolli on saatavilla sen nimen (asetettu HTML:ssä `name`-attribuutilla) perusteella lomakkeen ominaisuutena. Samalla tavalla kuin rekisteröinnissä, luomme toisen funktion palvelinpyyntöä varten, mutta tällä kertaa tilitietojen hakemiseen: ```js 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' }; } } ``` Käytämme `fetch`-APIa pyytääksemme dataa asynkronisesti palvelimelta, mutta tällä kertaa emme tarvitse muita parametreja kuin kutsuttavan URL-osoitteen, koska haemme vain dataa. Oletuksena `fetch` luo [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET)-HTTP-pyynnön, mikä on juuri se, mitä tarvitsemme tässä. ✅ `encodeURIComponent()` on funktio, joka koodaa erikoismerkit URL-osoitetta varten. Mitä ongelmia voisi ilmetä, jos emme kutsu tätä funktiota ja käytämme suoraan `user`-arvoa URL-osoitteessa? Päivitetään nyt `login`-funktiomme käyttämään `getAccount`-funktiota: ```js 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'); } ``` Koska `getAccount` on asynkroninen funktio, meidän täytyy käyttää `await`-avainsanaa odottaaksemme palvelimen vastausta. Kuten kaikissa palvelinpyynnöissä, meidän täytyy myös käsitellä virhetilanteet. Toistaiseksi lisäämme vain lokiviestin virheen näyttämiseksi ja palaamme tähän myöhemmin. Seuraavaksi meidän täytyy tallentaa data johonkin, jotta voimme käyttää sitä myöhemmin kojelaudan tietojen näyttämiseen. Koska `account`-muuttujaa ei vielä ole, luomme globaalin muuttujan tiedoston alkuun: ```js let account = null; ``` Kun käyttäjätiedot on tallennettu muuttujaan, voimme siirtyä *kirjautumissivulta* *kojelaudalle* käyttämällä olemassa olevaa `navigate()`-funktiota. Lopuksi meidän täytyy kutsua `login`-funktiota, kun kirjautumislomake lähetetään, muokkaamalla HTML:ää: ```html