# Bygg en bankapp del 3: Metoder for innhenting og bruk av data Tenk på Enterprise-datamaskinen i Star Trek – når kaptein Picard spør om statusen til skipet, dukker informasjonen opp umiddelbart uten at hele grensesnittet slår seg av og bygger seg opp på nytt. Den sømløse informasjonsflyten er akkurat det vi bygger her med dynamisk datainnhenting. Akkurat nå er bankappen din som en trykt avis – informativ, men statisk. Vi skal forvandle den til noe mer som oppdragskontrollen hos NASA, der data flyter kontinuerlig og oppdateres i sanntid uten å forstyrre brukerens arbeidsflyt. Du vil lære hvordan du kommuniserer med servere asynkront, håndterer data som kommer til på ulike tidspunkter, og omformer rå informasjon til noe meningsfylt for brukerne dine. Dette er forskjellen på en demo og programvare klar for produksjon. ## ⚡ Hva Du Kan Gjøre på de Neste 5 Minuttene **Rask start for travle utviklere** ```mermaid flowchart LR A[⚡ 5 minutter] --> B[Sett opp API-server] B --> C[Test hent med curl] C --> D[Lag innloggingsfunksjon] D --> E[Se data i aksjon] ``` - **Minutt 1-2**: Start API-serveren din (`cd api && npm start`) og test tilkoblingen - **Minutt 3**: Lag en grunnleggende `getAccount()`-funksjon med fetch - **Minutt 4**: Koble på logginnskjemaet med `action="javascript:login()"` - **Minutt 5**: Test logginn og se kontodataene dukke opp i konsollen **Hurtigtest kommandoer**: ```bash # Bekreft at API kjører curl http://localhost:5000/api # Test henting av kontodata curl http://localhost:5000/api/accounts/test ``` **Hvorfor dette er viktig**: På 5 minutter vil du oppleve magien ved asynkron datainnhenting som driver hver moderne webapplikasjon. Dette er grunnlaget som gjør at apper føles responsive og levende. ## 🗺️ Din læringsreise gjennom datadrevne webapplikasjoner ```mermaid journey title Fra statiske sider til dynamiske applikasjoner section Forstå utviklingen Tradisjonelle sideoppdateringer: 3: You Oppdag AJAX/SPA fordeler: 5: You Mestre Fetch API mønstre: 7: You section Bygge autentisering Lag innloggingsfunksjoner: 4: You Håndter asynkrone operasjoner: 6: You Administrer brukersesjoner: 8: You section Dynamiske UI-oppdateringer Lær DOM-manipulering: 5: You Bygg transaksjonsvisninger: 7: You Lag responsive dashbord: 9: You section Profesjonelle mønstre Malbasert rendering: 6: You Feilhåndteringsstrategier: 7: You Ytelsesoptimalisering: 8: You ``` **Mål for reisen din**: Innen slutten av denne leksjonen vil du forstå hvordan moderne webapplikasjoner henter inn, bearbeider og viser data dynamisk, og skaper de sømløse brukeropplevelsene vi forventer fra profesjonelle applikasjoner. ## Forhåndsforelesnings-quiz [Forhåndsforelesnings-quiz](https://ff-quizzes.netlify.app/web/quiz/45) ### Forutsetninger Før du går i dybden med datainnhenting, sørg for at du har disse komponentene klare: - **Tidligere leksjon**: Fullfør [Login and Registration Form](../2-forms/README.md) – vi bygger videre på dette grunnlaget - **Lokal server**: Installer [Node.js](https://nodejs.org) og [start server-API](../api/README.md) for å levere kontodata - **API-tilkobling**: Test servertilkoblingen din med denne kommandoen: ```bash curl http://localhost:5000/api # Forventet respons: "Bank API v1.0.0" ``` Denne raske testen sikrer at alle komponentene kommuniserer korrekt: - Verifiserer at Node.js kjører riktig på systemet ditt - Bekrefter at API-serveren er aktiv og svarer - Validerer at appen din kan nå serveren (som å sjekke radiokontakt før en oppdrag) ## 🧠 Oversikt over datahåndteringens økosystem ```mermaid mindmap root((Databehandling)) 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 ``` **Kjernetenkning**: Moderne webapplikasjoner er datasystemer for orkestrering – de koordinerer mellom brukergrensesnitt, server-API-er og nettleserens sikkerhetsmodeller for å skape sømløse, responsive opplevelser. --- ## Forstå datainnhenting i moderne webapper Måten webapplikasjoner håndterer data på har utviklet seg dramatisk i løpet av de siste tjue årene. Å forstå denne utviklingen vil hjelpe deg å sette pris på hvorfor moderne teknikker som AJAX og Fetch API er så kraftfulle, og hvorfor de har blitt uunnværlige verktøy for webutviklere. La oss utforske hvordan tradisjonelle nettsteder fungerte sammenlignet med de dynamiske, responsive appene vi bygger i dag. ### Tradisjonelle fler-sides applikasjoner (MPA) På de tidlige webdagene var hvert klikk som å bytte kanal på et gammelt fjernsyn – skjermen ble blank, for så å sakte stille inn det nye innholdet. Dette var virkeligheten for tidlige webapplikasjoner, hvor hver interaksjon betydde å bygge hele siden helt på nytt. ```mermaid sequenceDiagram participant User participant Browser participant Server User->>Browser: Klikker på lenke eller sender inn skjema Browser->>Server: Forespør ny HTML-side Note over Browser: Siden blir tom Server->>Browser: Returnerer komplett HTML-side Browser->>User: Viser ny side (blitser/laster på nytt) ``` ![Oppdateringsarbeidsflyt i en fler-sides applikasjon](../../../../translated_images/no/mpa.7f7375a1a2d4aa77.webp) **Hvorfor denne tilnærmingen føltes tungvint:** - Hvert klikk betydde å bygge hele siden fra bunnen av på nytt - Brukere ble forstyrret midt i tankene av plagsomme blink på siden - Internett-tilkoblingen jobbet overtid med å laste ned samme topp- og bunntekst gjentatte ganger - Apper føltes mer som å bla i en arkivskuff enn å bruke programvare ### Moderne enkelt-sides applikasjoner (SPA) AJAX (Asynchronous JavaScript and XML) endret dette paradigmet fullstendig. Som den modulære designen av Den internasjonale romstasjonen, der astronauter kan bytte ut individuelle komponenter uten å bygge hele strukturen på nytt, lar AJAX oss oppdatere spesifikke deler av en nettside uten å laste alt på nytt. Selv om navnet nevner XML, bruker vi i dag for det meste JSON, men kjerneprinsippet består: oppdater bare det som må endres. ```mermaid sequenceDiagram participant User participant Browser participant JavaScript participant Server User->>Browser: Samhandler med siden Browser->>JavaScript: Utløser hendelsesbehandler JavaScript->>Server: Henter bare nødvendige data Server->>JavaScript: Returnerer JSON-data JavaScript->>Browser: Oppdaterer spesifikke sideelementer Browser->>User: Viser oppdatert innhold (ingen omlasting) ``` ![Oppdateringsarbeidsflyt i en enkelt-sides applikasjon](../../../../translated_images/no/spa.268ec73b41f992c2.webp) **Hvorfor SPAs føles mye bedre:** - Bare delene som faktisk har endret seg oppdateres (smart, ikke sant?) - Ikke flere irriterende avbrudd – brukerne holder flyten - Mindre data som sendes over nettverket betyr raskere lasting - Alt føles smidig og responsivt, som appene på telefonen din ### Evolusjonen til moderne Fetch API Moderne nettlesere tilbyr [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), som erstatter den eldre [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Som forskjellen på å bruke telegraf og å sende e-post, bruker Fetch API promises for renere asynkron kode og håndterer JSON naturlig. | Funksjon | XMLHttpRequest | Fetch API | |---------|----------------|----------| | **Syntaks** | Kompleks callback-basert | Ren promise-basert | | **JSON-håndtering** | Krever manuell parsing | Innebygd `.json()`-metode | | **Feilhåndtering** | Begrenset feilinformasjon | Omfattende feildetaljer | | **Moderne støtte** | Legacy-kompatibilitet | ES6+ promises og async/await | > 💡 **Nettleserkompatibilitet**: God nyhet – Fetch API fungerer i alle moderne nettlesere! Om du er nysgjerrig på spesifikke versjoner, har [caniuse.com](https://caniuse.com/fetch) den komplette kompatibilitetshistorien. > **Konklusjonen:** - Fungerer utmerket i Chrome, Firefox, Safari og Edge (praktisk talt der brukerne dine er) - Bare Internet Explorer trenger ekstra hjelp (og ærlig talt, det er på tide å la IE gå) - Setter deg perfekt opp for elegante async/await-mønstre vi skal bruke senere ### Implementering av brukerinnlogging og datainnhenting Nå implementerer vi innloggingssystemet som forvandler bankappen din fra en statisk visning til en funksjonell applikasjon. Som autentiseringsprotokoller brukt i sikre militæranlegg, skal vi verifisere brukernes legitimasjon og så gi tilgang til deres spesifikke data. Vi bygger dette trinnvis, med grunnleggende autentisering først, deretter legger vi til datainnhentingsfunksjonalitet. #### Steg 1: Lag fundamentet for login-funksjonen Åpne filen `app.js` og legg til en ny funksjon `login`. Denne skal håndtere brukerautentiseringsprosessen: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **La oss bryte dette ned:** - Det `async`-nøkkelordet? Det forteller JavaScript "hei, denne funksjonen kan trenge å vente på noe" - Vi henter skjemaet vårt fra siden (ingen triks, bare finne det via ID) - Så trekker vi ut det brukeren skrev inn som brukernavn - Her er et fint triks: du kan nå hvert input i skjemaet via `name`-attributtet – slipper ekstra getElementById-kall! > 💡 **Tilgangsmønster for skjemaer**: Hver formkontroll kan nås via navnet sitt (`name`-attributtet i HTML) som en egenskap på skjemaelementet. Dette gir en ren, lesbar måte å hente skjema-data på. #### Steg 2: Lag funksjonen for å hente kontodata Deretter lager vi en dedikert funksjon for å hente kontodata fra serveren. Den følger samme mønster som registreringsfunksjonen, men fokuserer på innhenting: ```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' }; } } ``` **Dette oppnår koden:** - **Bruker** den moderne `fetch`-API-en for å asynkront hente data - **Bygger** en GET-forespørsel med brukernavn som parameter - **Bruker** `encodeURIComponent()` for sikker håndtering av spesialtegn i URL - **Konverterer** svar til JSON for enkel datahåndtering - **Håndterer** feil på en brukervennlig måte ved å returnere en feilobjekt i stedet for kræsje > ⚠️ **Sikkerhetsnotat**: `encodeURIComponent()` håndterer spesialtegn i URL-er. Som kodingssystemene brukt i marin kommunikasjon, sørger den for at meldingen din kommer frem akkurat som ønsket, og forhindrer at tegn som "#" eller "&" blir feilfortolket. > **Hvorfor dette er viktig:** - Forhindrer at spesialtegn ødelegger URL-er - Beskytter mot manipuleringsangrep mot URL - Sikrer at serveren mottar korrekt data - Følger sikre programmeringsprinsipper #### Forstå HTTP GET-forespørsler En ting som kanskje overrasker deg: når du bruker `fetch` uten ekstra opsjoner, lager det automatisk en [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET)-forespørsel. Dette passer perfekt når vi spør serveren om "hei, kan jeg se denne brukerens kontodata?" Tenk på GET-forespørsler som en høflig måte å låne en bok fra biblioteket – du ber om å se noe som allerede finnes. POST-forespørsler (som vi brukte for registrering) er mer som å sende inn en ny bok for å legge til samlingen. | GET-forespørsel | POST-forespørsel | |-------------|-------------| | **Formål** | Hente eksisterende data | Sende ny data til server | | **Parametre** | I URL-sti/spørringsstreng | I forespørselskropp | | **Caching** | Kan caches av nettlesere | Vanligvis ikke cachet | | **Sikkerhet** | Synlig i URL / logger | Skjult i forespørselskropp | ```mermaid sequenceDiagram participant B as Nettleser participant S as Server Note over B,S: GET-forespørsel (Datauthenting) B->>S: GET /api/accounts/test S-->>B: 200 OK + Kontodata Note over B,S: POST-forespørsel (Datainnsending) B->>S: POST /api/accounts + Nye kontodata S-->>B: 201 Opprettet + Bekreftelse Note over B,S: Feilhåndtering B->>S: GET /api/accounts/ikke-eksisterende S-->>B: 404 Ikke funnet + Feilmelding ``` #### Steg 3: Sette alt sammen Nå kommer den tilfredsstillende delen – la oss koble kontoinnhentingsfunksjonen til login-prosessen. Dette er hvor alt klikker på plass: ```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'); } ``` Denne funksjonen følger en klar rekkefølge: - Henter brukernavn fra skjemainput - Forespør brukerens kontodata fra serveren - Håndterer eventuelle feil underveis - Lagrer kontodata og navigerer til dashbord ved suksess > 🎯 **Async/Await-mønster**: Siden `getAccount` er asynkron, bruker vi `await` for å vente på at serveren svarer. Dette hindrer at koden fortsetter med udefinerte data. #### Steg 4: Lag et hjem for dataene dine Appen trenger et sted å huske kontoinformasjon når den er lastet inn. Tenk på dette som appens korttidsminne – et sted å holde brukerinformasjonen tilgjengelig. Legg til denne linjen øverst i `app.js`: ```javascript // Dette holder den nåværende brukerens kontodata let account = null; ``` **Hvorfor vi trenger dette:** - Holder kontodata tilgjengelig fra hvor som helst i appen - Startverdi `null` betyr "ingen er logget inn ennå" - Oppdateres når noen logger inn eller registrerer seg - Fungerer som en enkelt sannhetskilde – ingen forvirring om hvem som er innlogget #### Steg 5: Koble på skjemaet ditt Nå kobler vi den nye login-funksjonen til HTML-skjemaet ditt. Oppdater skjema-taggen slik: ```html
``` **Hva denne lille endringen gjør:** - Stopper skjemaet fra å gjøre sin standard "last hele siden på nytt" handling - Kaller din egen JavaScript-funksjon i stedet - Holder alt glatt og som en enkelt-sides app - Gir deg full kontroll over hva som skjer når brukeren trykker "Login" #### Steg 6: Forbedre registreringsfunksjonen For konsistens, oppdater `register`-funksjonen til også å lagre kontodata og navigere til dashbordet: ```javascript // Legg til disse linjene på slutten av din register-funksjon account = result; navigate('/dashboard'); ``` **Denne forbedringen gir:** - **Sømløs** overgang fra registrering til dashbord - **Konsistent** brukeropplevelse mellom login- og registreringsflyt - **Umiddelbar** tilgang til kontodata etter vellykket registrering #### Test implementeringen din ```mermaid flowchart TD A[Bruker skriver inn påloggingsinformasjon] --> B[Innloggingsfunksjon kalt] B --> C[Hent kontodata fra server] C --> D{Data mottatt vellykket?} D -->|Ja| E[Lagre kontodata globalt] D -->|Nei| F[Vis feilmelding] E --> G[Naviger til dashbord] F --> H[Bruker blir på påloggingssiden] ``` **Tid for å prøve det ut:** 1. Opprett en ny konto for å sikre at alt fungerer 2. Prøv å logge inn med de samme legitimasjonene 3. Sjekk nettleserkonsollen (F12) om noe virker feil 4. Sørg for at du lander på dashbordet etter innlogging Hvis noe ikke fungerer, ikke få panikk! De fleste problemer er enkle ting som skrivefeil eller at API-serveren ikke er startet. #### En kjapp kommentar om Cross-Origin-magien Du lurer kanskje på: "Hvordan snakker webappen min med denne API-serveren når de kjører på forskjellige porter?" Flott spørsmål! Dette er noe alle webutviklere møter etter hvert. > 🔒 **Cross-Origin Sikkerhet**: Nettlesere håndhever en "same-origin policy" for å forhindre uautorisert kommunikasjon mellom ulike domener. Som et kontrollpunkt ved Pentagon, verifiserer de at kommunikasjonen er autorisert før dataoverføring tillates. > **I vår konfigurasjon:** - Webappen din kjører på `localhost:3000` (utviklingsserver) - API-serveren din kjører på `localhost:5000` (backend-server) - API-serveren inkluderer [CORS-headere](https://developer.mozilla.org/docs/Web/HTTP/CORS) som eksplisitt tillater kommunikasjon fra webappen din Denne oppsettet speiler virkelige utviklingsmiljøer der frontend og backend applikasjoner vanligvis kjører på separate servere. > 📚 **Lær mer**: Dykk dypere inn i API-er og datainnhenting med denne omfattende [Microsoft Learn-modulen om API-er](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## Gi dataene dine liv i HTML Nå skal vi gjøre de innhentede dataene synlige for brukerne gjennom DOM-manipulasjon. Som i fremkallingsprosessen i et mørkerom, tar vi usynlige data og gjengir dem til noe brukerne kan se og samhandle med. DOM-manipulering er teknikken som forvandler statiske nettsider til dynamiske applikasjoner som oppdaterer innholdet sitt basert på brukerinteraksjoner og serverrespons. ### Velge riktig verktøy for jobben Når det gjelder å oppdatere HTML-en din med JavaScript, har du flere alternativer. Tenk på disse som forskjellige verktøy i en verktøykasse – hver perfekt for spesifikke oppgaver: | Metode | Hva den er best for | Når bruke den | Sikkerhetsnivå | |--------|---------------------|----------------|----------------| | `textContent` | Vise brukerdata trygt | Når som helst du viser tekst | ✅ Stein solid | | `createElement()` + `append()` | Bygge komplekse oppsett | Lage nye seksjoner/lister | ✅ Kulefast | | `innerHTML` | Sette HTML-innhold | ⚠️ Prøv å unngå denne | ❌ Risiko | #### Den trygge måten å vise tekst på: textContent [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent)-egenskapen er din beste venn når du skal vise brukerdata. Det er som en dørvakt for nettsiden din – ingenting skadelig slipper igjennom: ```javascript // Den sikre og pålitelige måten å oppdatere tekst på const balanceElement = document.getElementById('balance'); balanceElement.textContent = account.balance; ``` **Fordeler med textContent:** - Behandler alt som ren tekst (hindrer skripteksekvering) - Rydder automatisk eksisterende innhold - Effektivt for enkle tekstoppdateringer - Gir innebygd sikkerhet mot skadelig innhold #### Lage dynamiske HTML-elementer For mer komplekst innhold, kombiner [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) med [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append)-metoden: ```javascript // Sikker måte å lage nye elementer på const transactionItem = document.createElement('div'); transactionItem.className = 'transaction-item'; transactionItem.textContent = `${transaction.date}: ${transaction.description}`; container.append(transactionItem); ``` **Forstå denne tilnærmingen:** - **Oppretter** nye DOM-elementer programmert - **Opprettholder** full kontroll over element-attributter og innhold - **Tillater** komplekse, nestede elementstrukturer - **Bevarer** sikkerheten ved å skille struktur fra innhold > ⚠️ **Sikkerhetshensyn**: Selv om [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) dukker opp i mange veiledninger, kan det eksekvere innebygde skript. Som sikkerhetsprotokollene ved CERN som hindrer uautorisert kodeskjøring, gir bruken av `textContent` og `createElement` tryggere alternativer. > **Risiko med innerHTML:** - Eksekverer alle `