# Bygg en bankapp Del 3: Metoder för att hämta och använda data ## Förkunskapstest [Förkunskapstest](https://ff-quizzes.netlify.app/web/quiz/45) ### Introduktion I kärnan av varje webbapplikation finns *data*. Data kan ta många former, men dess huvudsakliga syfte är alltid att visa information för användaren. Med webbappar som blir alltmer interaktiva och komplexa är hur användaren får tillgång till och interagerar med information nu en nyckeldel av webbutveckling. I den här lektionen kommer vi att se hur man hämtar data från en server asynkront och använder dessa data för att visa information på en webbsida utan att ladda om HTML. ### Förutsättningar Du behöver ha byggt [inloggnings- och registreringsformuläret](../2-forms/README.md) som en del av webbappen för den här lektionen. Du behöver också installera [Node.js](https://nodejs.org) och [köra server-API:et](../api/README.md) lokalt för att få kontodata. Du kan testa att servern fungerar korrekt genom att köra följande kommando i en terminal: ```sh curl http://localhost:5000/api # -> should return "Bank API v1.0.0" as a result ``` --- ## AJAX och datahämtning Traditionella webbplatser uppdaterar innehållet som visas när användaren väljer en länk eller skickar data via ett formulär genom att ladda om hela HTML-sidan. Varje gång nya data behöver laddas returnerar webbservern en helt ny HTML-sida som måste bearbetas av webbläsaren, vilket avbryter användarens aktuella åtgärd och begränsar interaktioner under omladdningen. Detta arbetsflöde kallas också för en *Multi-Page Application* eller *MPA*.  När webbapplikationer började bli mer komplexa och interaktiva uppstod en ny teknik som kallas [AJAX (Asynchronous JavaScript and XML)](https://en.wikipedia.org/wiki/Ajax_(programming)). Denna teknik gör det möjligt för webbappar att skicka och hämta data från en server asynkront med hjälp av JavaScript, utan att behöva ladda om HTML-sidan, vilket resulterar i snabbare uppdateringar och smidigare användarinteraktioner. När nya data tas emot från servern kan den aktuella HTML-sidan också uppdateras med JavaScript med hjälp av [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)-API:et. Med tiden har detta tillvägagångssätt utvecklats till vad som nu kallas en [*Single-Page Application* eller *SPA*](https://en.wikipedia.org/wiki/Single-page_application).  När AJAX först introducerades var det enda API som fanns tillgängligt för att hämta data asynkront [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Men moderna webbläsare implementerar nu också det mer praktiska och kraftfulla [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), som använder promises och är bättre lämpat för att hantera JSON-data. > Även om alla moderna webbläsare stöder `Fetch API`, är det alltid en bra idé att kontrollera [kompatibilitetstabellen på caniuse.com](https://caniuse.com/fetch) först om du vill att din webbapplikation ska fungera på äldre webbläsare. ### Uppgift I [den föregående lektionen](../2-forms/README.md) implementerade vi registreringsformuläret för att skapa ett konto. Nu ska vi lägga till kod för att logga in med ett befintligt konto och hämta dess data. Öppna filen `app.js` och lägg till en ny funktion `login`: ```js async function login() { const loginForm = document.getElementById('loginForm') const user = loginForm.user.value; } ``` Här börjar vi med att hämta formulärelementet med `getElementById()` och sedan hämtar vi användarnamnet från inmatningen med `loginForm.user.value`. Varje formulärkontroll kan nås via sitt namn (angivet i HTML med attributet `name`) som en egenskap av formuläret. På liknande sätt som vi gjorde för registreringen, skapar vi en annan funktion för att utföra en serverförfrågan, men den här gången för att hämta kontodata: ```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' }; } } ``` Vi använder `fetch`-API:et för att begära data asynkront från servern, men den här gången behöver vi inga extra parametrar förutom URL:en att anropa, eftersom vi bara frågar efter data. Som standard skapar `fetch` en [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET)-HTTP-förfrågan, vilket är vad vi söker här. ✅ `encodeURIComponent()` är en funktion som kodar specialtecken för URL:er. Vilka problem skulle vi kunna stöta på om vi inte anropar denna funktion och använder värdet `user` direkt i URL:en? Låt oss nu uppdatera vår `login`-funktion för att använda `getAccount`: ```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'); } ``` Först, eftersom `getAccount` är en asynkron funktion, måste vi använda nyckelordet `await` för att vänta på serverresultatet. Som med alla serverförfrågningar måste vi också hantera fel. För tillfället lägger vi bara till ett loggmeddelande för att visa felet och återkommer till det senare. Sedan måste vi lagra data någonstans så att vi senare kan använda den för att visa information på instrumentpanelen. Eftersom variabeln `account` ännu inte existerar, skapar vi en global variabel för den högst upp i vår fil: ```js let account = null; ``` Efter att användardata har sparats i en variabel kan vi navigera från *login*-sidan till *dashboard* med hjälp av funktionen `navigate()` som vi redan har. Slutligen måste vi anropa vår `login`-funktion när inloggningsformuläret skickas, genom att ändra HTML: ```html