# Bygg en bankapp del 3: Metoder för att hämta och använda data Tänk på Enterprise-datorn i Star Trek – när kapten Picard frågar efter status på skeppet, dyker informationen upp omedelbart utan att hela gränssnittet stängs ner och byggs upp igen. Det sömlösa informationsflödet är exakt vad vi bygger här med dynamisk datahämtning. Just nu är din bankapp som en tryckt tidning – informativ men statisk. Vi ska förvandla den till något mer som NASA:s mission control, där data flödar kontinuerligt och uppdateras i realtid utan att avbryta användarens arbetsflöde. Du kommer att lära dig hur man kommunicerar asynkront med servrar, hanterar data som anländer vid olika tidpunkter och omvandlar rå information till något meningsfullt för dina användare. Det är skillnaden mellan en demo och produktionsredo programvara. ## ⚡ Vad du kan göra under de nästa 5 minuterna **Snabbstart för upptagna utvecklare** ```mermaid flowchart LR A[⚡ 5 minuter] --> B[Ställ in API-server] B --> C[Testa hämtning med curl] C --> D[Skapa inloggningsfunktion] D --> E[Se data i aktion] ``` - **Minut 1-2**: Starta din API-server (`cd api && npm start`) och testa anslutningen - **Minut 3**: Skapa en grundläggande `getAccount()`-funktion med fetch - **Minut 4**: Koppla upp inloggningsformuläret med `action="javascript:login()"` - **Minut 5**: Testa inloggning och se kontodata visas i konsolen **Snabba testkommandon**: ```bash # Verifiera att API:et körs curl http://localhost:5000/api # Testa hämtning av kontodata curl http://localhost:5000/api/accounts/test ``` **Varför detta är viktigt**: På 5 minuter får du se magin i asynkron datahämtning som driver alla moderna webapplikationer. Detta är grunden som gör att appar känns responsiva och levande. ## 🗺️ Din läranderesa genom datadrivna webbapplikationer ```mermaid journey title Från statiska sidor till dynamiska applikationer section Förstå utvecklingen Traditionell sidladdning: 3: You Upptäck AJAX/SPA-fördelar: 5: You Bemästra Fetch API-mönster: 7: You section Bygga autentisering Skapa inloggningsfunktioner: 4: You Hantera asynkrona operationer: 6: You Hantera användarsessioner: 8: You section Dynamiska UI-uppdateringar Lär dig DOM-manipulation: 5: You Bygg transaktionsvisningar: 7: You Skapa responsiva dashboards: 9: You section Professionella mönster Mallbaserad rendering: 6: You Strategier för felhantering: 7: You Prestandaoptimering: 8: You ``` **Ditt resa mål**: I slutet av denna lektion kommer du att förstå hur moderna webbapplikationer hämtar, bearbetar och visar data dynamiskt och skapar de sömlösa användarupplevelser vi förväntar oss från professionella applikationer. ## Förföreläsningsquiz [Förföreläsningsquiz](https://ff-quizzes.netlify.app/web/quiz/45) ### Förkunskaper Innan du dyker ner i datahämtning, se till att dessa komponenter är klara: - **Föregående lektion**: Slutför [Inloggnings- och registreringsformuläret](../2-forms/README.md) – vi bygger vidare på denna grund - **Lokal server**: Installera [Node.js](https://nodejs.org) och [starta server-API:t](../api/README.md) för att tillhandahålla kontodata - **API-anslutning**: Testa anslutningen till din server med detta kommando: ```bash curl http://localhost:5000/api # Förväntat svar: "Bank API v1.0.0" ``` Detta snabba test säkerställer att alla komponenter kommunicerar korrekt: - Verifierar att Node.js körs korrekt på din dator - Bekräftar att din API-server är aktiv och svarar - Validerar att din app kan nå servern (som att kontrollera radiokontakt före en uppdrag) ## 🧠 Översikt av datahanteringsekosystemet ```mermaid mindmap root((Databashantering)) 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 ``` **Kärnprincip**: Moderna webbapplikationer är dataorkestreringssystem – de koordinerar mellan användargränssnitt, server-API:er och webbläsarens säkerhetsmodeller för att skapa sömlösa, responsiva upplevelser. --- ## Förstå datahämtning i moderna webbappar Hur webbapplikationer hanterar data har utvecklats dramatiskt de senaste två decennierna. Att förstå denna utveckling hjälper dig att uppskatta varför moderna tekniker som AJAX och Fetch API är så kraftfulla och varför de blivit oumbärliga verktyg för webbutvecklare. Låt oss utforska hur traditionella webbplatser fungerade jämfört med de dynamiska, responsiva applikationer vi bygger idag. ### Traditionella multipages-applikationer (MPA) I webbens tidiga dagar var varje klick som att byta kanal på en gammal tv – skärmen blev svart och ställde in sig långsamt på det nya innehållet. Så var verkligheten för tidiga webbapplikationer, där varje interaktion innebar att hela sidan byggdes upp från grunden igen. ```mermaid sequenceDiagram participant User participant Browser participant Server User->>Browser: Klickar på länk eller skickar formulär Browser->>Server: Begär ny HTML-sida Note over Browser: Sidan blir tom Server->>Browser: Returnerar komplett HTML-sida Browser->>User: Visar ny sida (blinkning/uppdatering) ```  **Varför detta tillvägagångssätt kändes tungrott:** - Varje klick innebar att hela sidan byggdes om från scratch - Användare avbröts mitt i sina tankar av de irriterande sidblinkningarna - Din internetanslutning jobbade övertid med att ladda samma sidhuvud och sidfot om och om igen - Appar kändes mer som att klicka igenom ett arkivskåp än att använda programvara ### Moderna enkel-sidiga applikationer (SPA) AJAX (Asynchronous JavaScript and XML) förändrade detta paradigm helt. Som den modulära designen av Internationella rymdstationen, där astronauter kan byta ut enskilda komponenter utan att bygga om hela strukturen, tillåter AJAX oss att uppdatera specifika delar av en webbsida utan att ladda om allt. Trots att namnet nämner XML använder vi mest JSON idag, men kärnprincipen består: uppdatera bara det som behöver ändras. ```mermaid sequenceDiagram participant User participant Browser participant JavaScript participant Server User->>Browser: Interagerar med sidan Browser->>JavaScript: Triggar eventhanterare JavaScript->>Server: Hämtar bara nödvändiga data Server->>JavaScript: Returnerar JSON-data JavaScript->>Browser: Uppdaterar specifika sidkomponenter Browser->>User: Visar uppdaterat innehåll (ingen omladdning) ```  **Varför SPA känns så mycket bättre:** - Endast de delar som faktiskt ändrats uppdateras (smart, eller hur?) - Inga fler ryckiga avbrott – dina användare stannar i sitt flöde - Mindre data som färdas över nätverket betyder snabbare laddning - Allt känns snabbt och responsivt, precis som apparna i din telefon ### Evolutionen till moderna Fetch API Moderna webbläsare tillhandahåller [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), som ersätter den äldre [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Som skillnaden mellan att använda en telegraf och att skicka e-post, använder Fetch API löften (promises) för renare asynkron kod och hanterar JSON naturligt. | Funktion | XMLHttpRequest | Fetch API | |---------|----------------|----------| | **Syntax** | Komplex callback-baserad | Ren promise-baserad | | **JSON-hantering** | Kräver manuell tolkning | Inbyggd `.json()`-metod | | **Felhanteirng** | Begränsad felinformation | Omfattande felinformation | | **Modern support** | Bakåtkompatibilitet | ES6+ promises och async/await | > 💡 **Webbläsarkompatibilitet**: Goda nyheter – Fetch API fungerar i alla moderna webbläsare! Om du är nyfiken på specifika versioner finns hela kompatibilitetshistoriken på [caniuse.com](https://caniuse.com/fetch). > **Slutsatsen:** - Fungerar utmärkt i Chrome, Firefox, Safari och Edge (typ överallt där dina användare är) - Endast Internet Explorer behöver extra stöd (och ärligt talat, det är dags att låta IE gå) - Sätter dig perfekt för de eleganta async/await-mönstren vi kommer att använda senare ### Implementera användarinloggning och datahämtning Nu låt oss implementera inloggningssystemet som förvandlar din bankapp från en statisk vy till en fungerande applikation. Som autentiseringsprotokollen som används i säkra militära anläggningar, verifierar vi användaruppgifter och ger sedan tillgång till deras specifika data. Vi bygger detta steg för steg, med grundläggande autentisering först och sedan lägger vi till datahämtning. #### Steg 1: Skapa grunden för inloggningsfunktionen Öppna din `app.js`-fil och lägg till en ny `login`-funktion. Den ska hantera användarens autentiseringsprocess: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **Låt oss bryta ner det här:** - Det där `async`-ordet? Det talar om för JavaScript "hej, den här funktionen kan behöva vänta på saker" - Vi hämtar vårt formulär från sidan (inget fancy, bara hittar det via dess ID) - Sen plockar vi ut vad användaren skrev in som användarnamn - Ett smart trick: du kan nå vilket formulärfält som helst via dess `name`-attribut – inget behov av extra getElementById-anrop! > 💡 **Tillgångsmönster för formulär**: Varje formulärkontroll kan nås via dess namn (satt i HTML med `name`-attribut) som en egenskap på formulärelementet. Det ger ett rent och läsbart sätt att hämta formulärdata. #### Steg 2: Skapa funktionen för att hämta kontodata Nästa steg är att skapa en dedikerad funktion för att hämta kontodata från servern. Den följer samma mönster som din registreringsfunktion men fokuserar på datahämtning: ```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' }; } } ``` **Det här klarar koden av:** - **Använder** moderna `fetch` API för att asynkront begära data - **Konstruerar** en GET-förfrågan med användarnamn som parameter - **Använder** `encodeURIComponent()` för att säkert hantera specialtecken i URL:er - **Konverterar** svaret till JSON-format för enkel datamanipulation - **Hantera** fel graciöst genom att returnera ett felobjekt istället för att krascha > ⚠️ **Säkerhetsnotering**: Funktionen `encodeURIComponent()` hanterar specialtecken i URL:er. Som kodsystemen som används i marin kommunikation garanterar den att ditt meddelande anländer exakt som avsett, och förhindrar att tecken som "#" eller "&" tolkas fel. > **Varför detta är viktigt:** - Förhindrar att specialtecken bryter URL:en - Skyddar mot attacker som manipulerar URL:er - Säkerställer att din server får korrekta data - Följer säkra kodningsprinciper #### Förstå HTTP GET-förfrågningar Här är något som kan överraska dig: när du använder `fetch` utan extra alternativ skapar den automatiskt en [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET)-förfrågan. Det passar perfekt för vad vi gör – ber servern "hej, kan jag få se den här användarens kontodata?" Tänk på GET-förfrågningar som att artigt fråga om du får låna en bok från biblioteket – du begär att få se något som redan finns. POST-förfrågningar (som vi använde för registrering) är mer som att skicka in en ny bok som ska läggas till i samlingen. | GET-förfrågan | POST-förfrågan | |-------------|-------------| | **Syfte** | Hämta befintlig data | Skicka ny data till server | | **Parametrar** | I URL-sökväg/frågesträng | I förfrågans kropp | | **Cache** | Kan cachas av webbläsare | Cachas vanligtvis inte | | **Säkerhet** | Synlig i URL/loggar | Dold i förfrågans kropp | ```mermaid sequenceDiagram participant B as Browser participant S as Server Note over B,S: GET-förfrågan (Datainhämtning) B->>S: GET /api/accounts/test S-->>B: 200 OK + Kontodata Note over B,S: POST-förfrågan (Dataregistrering) B->>S: POST /api/accounts + Ny kontodata S-->>B: 201 Skapad + Bekräftelse Note over B,S: Felhantering B->>S: GET /api/accounts/nonexistent S-->>B: 404 Hittades inte + Felmeddelande ``` #### Steg 3: Sätta ihop allt Nu kommer det tillfredsställande momentet – låt oss koppla din konto-hämtningsfunktion till inloggningsprocessen. Här faller allt på plats: ```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'); } ``` Denna funktion följer en tydlig sekvens: - Extraherar användarnamnet från formulärets input - Begär användarens kontodata från servern - Hanterar eventuella fel under processen - Sparar kontodata och navigerar till instrumentpanelen vid framgång > 🎯 **Async/Await-mönster**: Eftersom `getAccount` är asynkron används `await` för att pausa exekvering tills servern svarar. Detta förhindrar att koden fortsätter med odefinierade data. #### Steg 4: Skapa ett hem för din data Din app behöver någonstans att komma ihåg kontoinformationen när den väl är inläst. Tänk på det som appens korttidsminne – en plats för att hålla aktuell användardata nära till hands. Lägg till denna rad högst upp i din `app.js`: ```javascript // Detta innehåller den nuvarande användarens kontodata let account = null; ``` **Varför vi behöver detta:** - Håller kontodatat åtkomligt från hela din app - Börjar med `null` vilket betyder "ingen är inloggad än" - Uppdateras när någon loggar in eller registrerar sig framgångsrikt - Fungerar som en enda sanningskälla – ingen förvirring om vem som är inloggad #### Steg 5: Koppla upp ditt formulär Nu kopplar vi din blänkande nya inloggningsfunktion till ditt HTML-formulär. Uppdatera din formtagg så här: ```html
``` **Vad denna lilla ändring gör:** - Stoppar formuläret från att utföra sitt standardbeteende "ladda om hela sidan" - Anropar din egna JavaScript-funktion istället - Behåller allting smidigt och likt en single-page app - Ger dig full kontroll över vad som händer när användare klickar på "Login" #### Steg 6: Förbättra din registreringsfunktion För konsekvens, uppdatera din `register`-funktion så den också sparar kontodata och navigerar till instrumentpanelen: ```javascript // Lägg till dessa rader i slutet av din registerfunktion account = result; navigate('/dashboard'); ``` **Denna förbättring ger:** - **Sömlös** övergång från registrering till instrumentpanelen - **Konsekvent** användarupplevelse mellan inloggning och registrering - **Omedelbar** tillgång till kontodata efter lyckad registrering #### Testa din implementation ```mermaid flowchart TD A[Användare anger inloggningsuppgifter] --> B[Inloggningsfunktion anropad] B --> C[Hämta kontodata från servern] C --> D{Data mottagen framgångsrikt?} D -->|Ja| E[Lagra kontodata globalt] D -->|Nej| F[Visa felmeddelande] E --> G[Navigera till instrumentpanelen] F --> H[Användaren stannar på inloggningssidan] ``` **Dags att provköra:** 1. Skapa ett nytt konto för att säkerställa att allt fungerar 2. Testa att logga in med samma uppgifter 3. Titta på din webbläsares konsol (F12) om något känns konstigt 4. Se till att du hamnar på instrumentpanelen efter lyckad inloggning Om något inte fungerar, panikera inte! De flesta problem är enkla fixar som stavfel eller att glömma starta API-servern. #### Ett snabbt ord om Cross-Origin-magik Du kanske undrar: "Hur kan min webbapp prata med den här API-servern när de körs på olika portar?" Bra fråga! Detta är något som varje webbutvecklare stöter på till slut. > 🔒 **Cross-Origin-säkerhet**: Webbläsare upprätthåller en "same-origin policy" för att förhindra obehörig kommunikation mellan olika domäner. Som kontrollstationen vid Pentagon verifierar de att kommunikationen är auktoriserad innan de tillåter datatransfer. > **I vår uppsättning:** - Din webbapp körs på `localhost:3000` (utvecklingsserver) - Din API-server körs på `localhost:5000` (backend-server) - API-servern inkluderar [CORS headers](https://developer.mozilla.org/docs/Web/HTTP/CORS) som explicit auktoriserar kommunikation från din webbapp Denna konfiguration speglar verklig utveckling där frontend och backend-applikationer vanligtvis körs på separata servrar. > 📚 **Läs mer**: Fördjupa dig mer i API:er och datahämtning med denna omfattande [Microsoft Learn-modul om API:er](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## Ge liv åt din data i HTML Nu gör vi den hämtade datan synlig för användarna genom DOM-manipulation. Som processen att framkalla foton i ett mörkrum tar vi osynlig data och renderar den till något användarna kan se och interagera med. DOM-manipulation är tekniken som förvandlar statiska webbsidor till dynamiska applikationer som uppdaterar sitt innehåll baserat på användarinteraktioner och server-svar. ### Välja rätt verktyg för jobbet När det gäller att uppdatera din HTML med JavaScript har du flera alternativ. Tänk på dessa som olika verktyg i en verktygslåda – varje perfekt för specifika uppgifter: | Metod | Vad den är bra för | När man ska använda den | Säkerhetsnivå | |--------|---------------------|----------------|--------------| | `textContent` | Visa användardata på ett säkert sätt | När du visar text | ✅ Stenhårt | | `createElement()` + `append()` | Bygga komplexa layouter | Skapa nya sektioner/listor | ✅ Pansarsäkert | | `innerHTML` | Sätta HTML-innehåll | ⚠️ Försök undvik den här | ❌ Riskfyllt | #### Det säkra sättet att visa text: textContent Egenskapen [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent) är din bästa vän när du visar användardata. Det är som att ha en vakt för din webbsida – inget skadligt släpps igenom: ```javascript // Det säkra, pålitliga sättet att uppdatera text const balanceElement = document.getElementById('balance'); balanceElement.textContent = account.balance; ``` **Fördelar med textContent:** - Behandlar allt som vanlig text (hindrar scriptkörning) - Rensar automatiskt befintligt innehåll - Effektivt för enkla textuppdateringar - Ger inbyggd säkerhet mot skadligt innehåll #### Skapa dynamiska HTML-element För mer komplext innehåll, kombinera [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) med metoden [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append): ```javascript // Säkert sätt att skapa nya element const transactionItem = document.createElement('div'); transactionItem.className = 'transaction-item'; transactionItem.textContent = `${transaction.date}: ${transaction.description}`; container.append(transactionItem); ``` **Att förstå detta tillvägagångssätt:** - **Skapar** nya DOM-element programmatiskt - **Behåller** full kontroll över elementens attribut och innehåll - **Tillåter** komplexa, nästlade elementstrukturer - **Bevarar** säkerheten genom att separera struktur från innehåll > ⚠️ **Säkerhetsaspekt**: Även om [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) förekommer ofta i handledningar, kan det köra inbäddade script. Precis som säkerhetsprotokollen på CERN som förhindrar obehörig kodkörning, erbjuder `textContent` och `createElement` säkrare alternativ. > **Risker med innerHTML:** - Kör alla `