# Izrada aplikacije za bankarstvo, dio 3: Metode dohvaćanja i korištenja podataka Razmislite o računalu Enterprisea iz Zvjezdanih staza - kada kapetan Picard zatraži status broda, informacije se pojavljuju trenutno, bez da se cijelo sučelje zatvori i ponovno izgradi. Taj neprekidni tok informacija upravo je ono što ovdje gradimo s dinamičkim dohvaćanjem podataka. Trenutno je vaša aplikacija za bankarstvo poput tiskane novine - informativna, ali statična. Pretvorit ćemo je u nešto slično kontrolnom centru NASA-e, gdje podaci kontinuirano teku i ažuriraju se u stvarnom vremenu bez prekida korisničkog tijeka rada. Naučit ćete kako komunicirati s poslužiteljima asinkrono, kako rukovati podacima koji dolaze u različito vrijeme i kako transformirati sirove informacije u nešto značajno za vaše korisnike. Ovo je razlika između demo verzije i softvera spremnog za produkciju. ## Kviz prije predavanja [Pre-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/45) ### Preduvjeti Prije nego što se upustite u dohvaćanje podataka, osigurajte da imate sljedeće komponente spremne: - **Prethodna lekcija**: Završite [Formu za prijavu i registraciju](../2-forms/README.md) - nadogradit ćemo na ovom temelju - **Lokalni poslužitelj**: Instalirajte [Node.js](https://nodejs.org) i [pokrenite API poslužitelj](../api/README.md) za pružanje podataka o računima - **API veza**: Testirajte vezu s poslužiteljem pomoću ove naredbe: ```bash curl http://localhost:5000/api # Expected response: "Bank API v1.0.0" ``` Ovaj brzi test osigurava da svi dijelovi ispravno komuniciraju: - Provjerava da Node.js ispravno radi na vašem sustavu - Potvrđuje da je vaš API poslužitelj aktivan i odgovara - Validira da vaša aplikacija može dosegnuti poslužitelj (kao provjera radio veze prije misije) --- ## Razumijevanje dohvaćanja podataka u modernim web aplikacijama Način na koji web aplikacije rukovode podacima dramatično se razvio tijekom posljednja dva desetljeća. Razumijevanje ove evolucije pomoći će vam da cijenite zašto su moderni pristupi poput AJAX-a i Fetch API-ja toliko moćni i zašto su postali ključni alati za web programere. Istražimo kako su tradicionalne web stranice funkcionirale u usporedbi s dinamičnim, responzivnim aplikacijama koje danas gradimo. ### Tradicionalne višestranične aplikacije (MPA) U ranim danima weba, svaki klik bio je poput mijenjanja kanala na starom televizoru - ekran bi se zamračio, a zatim polako prikazivao novi sadržaj. To je bila stvarnost ranih web aplikacija, gdje je svaka interakcija značila potpuno ponovno izgrađivanje cijele stranice od nule. ```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) ``` ![Radni tijek ažuriranja u višestraničnoj aplikaciji](../../../../translated_images/mpa.7f7375a1a2d4aa779d3f928a2aaaf9ad76bcdeb05cfce2dc27ab126024050f51.hr.png) **Zašto je ovaj pristup bio nezgrapan:** - Svaki klik značio je ponovno izgrađivanje cijele stranice od nule - Korisnici su bili prekidani usred razmišljanja zbog tih dosadnih bljeskova stranice - Vaša internetska veza radila je prekovremeno preuzimajući isti zaglavlje i podnožje iznova i iznova - Aplikacije su se osjećale više kao pretraživanje kartoteke nego korištenje softvera ### Moderne jednostranične aplikacije (SPA) AJAX (Asynchronous JavaScript and XML) potpuno je promijenio ovu paradigmu. Kao modularni dizajn Međunarodne svemirske postaje, gdje astronauti mogu zamijeniti pojedine komponente bez ponovnog izgrađivanja cijele strukture, AJAX nam omogućuje ažuriranje specifičnih dijelova web stranice bez ponovnog učitavanja svega. Iako ime spominje XML, danas uglavnom koristimo JSON, ali osnovni princip ostaje isti: ažuriraj samo ono što treba promijeniti. ```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) ``` ![Radni tijek ažuriranja u jednostraničnoj aplikaciji](../../../../translated_images/spa.268ec73b41f992c2a21ef9294235c6ae597b3c37e2c03f0494c2d8857325cc57.hr.png) **Zašto se SPA aplikacije osjećaju puno bolje:** - Ažuriraju se samo dijelovi koji se stvarno mijenjaju (pametno, zar ne?) - Nema više neugodnih prekida - vaši korisnici ostaju u svom tijeku - Manje podataka putuje mrežom, što znači brže učitavanje - Sve se osjeća brzo i responzivno, poput aplikacija na vašem telefonu ### Evolucija prema modernom Fetch API-ju Moderni preglednici pružaju [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), koji zamjenjuje stariji [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Kao razlika između upravljanja telegrafom i korištenja e-pošte, Fetch API koristi obećanja za čišći asinkroni kod i prirodno rukuje JSON-om. | Značajka | XMLHttpRequest | Fetch API | |----------|----------------|-----------| | **Sintaksa** | Složena, temeljena na povratnim pozivima | Čista, temeljena na obećanjima | | **Rukovanje JSON-om** | Potrebno ručno parsiranje | Ugrađena metoda `.json()` | | **Rukovanje greškama** | Ograničene informacije o greškama | Detaljne informacije o greškama | | **Podrška za moderne tehnologije** | Kompatibilnost sa starijim verzijama | ES6+ obećanja i async/await | > 💡 **Kompatibilnost preglednika**: Dobre vijesti - Fetch API radi u svim modernim preglednicima! Ako vas zanimaju specifične verzije, [caniuse.com](https://caniuse.com/fetch) ima kompletnu priču o kompatibilnosti. > **Zaključak:** - Odlično radi u Chromeu, Firefoxu, Safariju i Edgeu (praktički svugdje gdje su vaši korisnici) - Samo Internet Explorer treba dodatnu pomoć (i iskreno, vrijeme je da se oprostimo od IE-a) - Savršeno vas priprema za elegantne async/await obrasce koje ćemo kasnije koristiti ### Implementacija prijave korisnika i dohvaćanja podataka Sada ćemo implementirati sustav prijave koji vašu aplikaciju za bankarstvo transformira iz statičnog prikaza u funkcionalnu aplikaciju. Kao što se koriste protokoli autentifikacije u sigurnim vojnim objektima, provjerit ćemo korisničke vjerodajnice i zatim omogućiti pristup njihovim specifičnim podacima. Gradit ćemo ovo postupno, počevši od osnovne autentifikacije, a zatim dodajući mogućnosti dohvaćanja podataka. #### Korak 1: Kreiranje temelja funkcije za prijavu Otvorite svoju datoteku `app.js` i dodajte novu funkciju `login`. Ova funkcija će rukovati procesom autentifikacije korisnika: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **Razložimo ovo:** - Ključna riječ `async`? Ona govori JavaScriptu "hej, ova funkcija možda treba pričekati na neke stvari" - Dohvaćamo našu formu sa stranice (ništa posebno, samo je pronalazimo po njenom ID-u) - Zatim izvlačimo ono što je korisnik unio kao svoje korisničko ime - Evo zgodnog trika: možete pristupiti bilo kojem unosu forme pomoću atributa `name` - nema potrebe za dodatnim pozivima getElementById! > 💡 **Obrazac pristupa formi**: Svakom kontroleru forme može se pristupiti putem njegovog imena (postavljenog u HTML-u pomoću atributa `name`) kao svojstva elementa forme. Ovo pruža čist i čitljiv način za dohvaćanje podataka iz forme. #### Korak 2: Kreiranje funkcije za dohvaćanje podataka o računu Zatim ćemo kreirati namjensku funkciju za dohvaćanje podataka o računu s poslužitelja. Ovo slijedi isti obrazac kao vaša funkcija za registraciju, ali se fokusira na dohvaćanje podataka: ```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' }; } } ``` **Što ovaj kod postiže:** - **Koristi** moderni `fetch` API za asinkrono slanje zahtjeva za podatke - **Konstruira** URL GET zahtjeva s parametrom korisničkog imena - **Primjenjuje** `encodeURIComponent()` za sigurno rukovanje posebnim znakovima u URL-ovima - **Pretvara** odgovor u JSON format za jednostavnu manipulaciju podacima - **Rukuje** greškama na elegantan način vraćanjem objekta greške umjesto rušenja > ⚠️ **Napomena o sigurnosti**: Funkcija `encodeURIComponent()` rukuje posebnim znakovima u URL-ovima. Kao kodni sustavi koji se koriste u pomorskim komunikacijama, osigurava da vaša poruka stigne točno onako kako je namijenjena, sprječavajući da se znakovi poput "#" ili "&" pogrešno interpretiraju. > **Zašto je ovo važno:** - Sprječava da posebni znakovi pokvare URL-ove - Štiti od napada manipulacijom URL-om - Osigurava da vaš poslužitelj primi namijenjene podatke - Slijedi sigurne prakse kodiranja #### Razumijevanje HTTP GET zahtjeva Evo nečega što bi vas moglo iznenaditi: kada koristite `fetch` bez dodatnih opcija, automatski stvara [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET) zahtjev. Ovo je savršeno za ono što radimo - tražimo od poslužitelja "hej, mogu li vidjeti podatke o ovom korisniku?" Razmislite o GET zahtjevima kao o pristojnom traženju posudbe knjige iz knjižnice - tražite da vidite nešto što već postoji. POST zahtjevi (koje smo koristili za registraciju) više su poput predaje nove knjige da se doda u kolekciju. | GET zahtjev | POST zahtjev | |-------------|-------------| | **Svrha** | Dohvaćanje postojećih podataka | Slanje novih podataka na poslužitelj | | **Parametri** | U URL putanji/upitu | U tijelu zahtjeva | | **Keširanje** | Može se keširati od strane preglednika | Obično se ne kešira | | **Sigurnost** | Vidljivo u URL-u/logovima | Skriveno u tijelu zahtjeva | #### Korak 3: Povezivanje svih dijelova Sada dolazi zadovoljavajući dio - povežimo vašu funkciju za dohvaćanje podataka o računu s procesom prijave. Ovo je trenutak kada sve klikne na svoje mjesto: ```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'); } ``` Ova funkcija slijedi jasan slijed: - Izvlači korisničko ime iz unosa forme - Zahtijeva podatke o korisničkom računu s poslužitelja - Rukuje svim greškama koje se pojave tijekom procesa - Sprema podatke o računu i navigira na nadzornu ploču nakon uspjeha > 🎯 **Async/Await obrazac**: Budući da je `getAccount` asinkrona funkcija, koristimo ključnu riječ `await` kako bismo pauzirali izvršavanje dok poslužitelj ne odgovori. Ovo sprječava da kod nastavi s neodređenim podacima. #### Korak 4: Kreiranje prostora za vaše podatke Vaša aplikacija treba mjesto gdje će pamtiti informacije o računu nakon što se učitaju. Razmislite o ovome kao o kratkoročnoj memoriji vaše aplikacije - mjesto za čuvanje podataka trenutnog korisnika. Dodajte ovu liniju na vrh vaše datoteke `app.js`: ```javascript // This holds the current user's account data let account = null; ``` **Zašto nam je ovo potrebno:** - Čuva podatke o računu dostupnima s bilo kojeg mjesta u vašoj aplikaciji - Početak s `null` znači "još nitko nije prijavljen" - Ažurira se kada se netko uspješno prijavi ili registrira - Djeluje kao jedinstveni izvor istine - nema zabune oko toga tko je prijavljen #### Korak 5: Povezivanje vaše forme Sada povežimo vašu novu funkciju za prijavu s HTML formom. Ažurirajte oznaku forme ovako: ```html
``` **Što ova mala promjena čini:** - Zaustavlja formu da radi svoje zadano ponašanje "ponovnog učitavanja cijele stranice" - Poziva vašu prilagođenu JavaScript funkciju umjesto toga - Održava sve glatkim i u stilu jednostranične aplikacije - Daje vam potpunu kontrolu nad onim što se događa kada korisnici kliknu "Prijava" #### Korak 6: Poboljšanje funkcije za registraciju Radi dosljednosti, ažurirajte svoju funkciju `register` kako bi također spremala podatke o računu i navigirala na nadzornu ploču: ```javascript // Add these lines at the end of your register function account = result; navigate('/dashboard'); ``` **Ovo poboljšanje pruža:** - **Neometan** prijelaz s registracije na nadzornu ploču - **Dosljedno** korisničko iskustvo između prijave i registracije - **Trenutni** pristup podacima o računu nakon uspješne registracije #### Testiranje vaše implementacije ```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] ``` **Vrijeme je za testiranje:** 1. Kreirajte novi račun kako biste provjerili radi li sve ispravno 2. Pokušajte se prijaviti s istim vjerodajnicama 3. Pogledajte konzolu vašeg preglednika (F12) ako nešto ne funkcionira 4. Provjerite jeste li stigli na nadzornu ploču nakon uspješne prijave Ako nešto ne radi, ne paničarite! Većina problema su jednostavne greške poput tipfelera ili zaborava pokretanja API poslužitelja. #### Kratka riječ o magiji među-domenne komunikacije Možda se pitate: "Kako moja web aplikacija komunicira s ovim API poslužiteljem kad rade na različitim portovima?" Odlično pitanje! Ovo se tiče nečega na što svaki web programer kad-tad naiđe. > 🔒 **Sigurnost među-domenne komunikacije**: Preglednici provode "politiku istog podrijetla" kako bi spriječili neovlaštenu komunikaciju između različitih domena. Kao sustav kontrolnih točaka u Pentagonu, provjeravaju je li komunikacija ovlaštena prije nego što dopuste prijenos podataka. > **U našem postavljanju:** - Vaša web aplikacija radi na `localhost:3000` (razvojni poslužitelj) - Vaš API poslužitelj radi na `localhost:5000` (poslužitelj pozadinskog sustava) - API poslužitelj uključuje [CORS zaglavlja](https://developer.mozilla.org/docs/Web/HTTP/CORS) koja eksplicitno autoriziraju komunikaciju s vašom web aplikacijom Ova konfiguracija odražava stvarni razvoj gdje frontend i backend aplikacije obično rade na odvojenim poslužiteljima. > 📚 **Saznajte više**: Dublje istražite API-je i dohvaćanje podataka s ovim sveobuhvatnim [Microsoft Learn modulom o API-jima](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## Oživljavanje vaših podataka u HTML-u Sada ćemo učiniti dohvaćene podatke vidljivima korisnicima putem manipulacije DOM-om. Kao proces razvijanja fotografija u tamnoj komori, uzimamo nevidljive podatke i prikazujemo ih u nešto što korisnici mogu vidjeti i s čime mogu interagirati. Manipulacija DOM-om je tehnika koja transformira statične web stranice u dinamičke aplikacije koje ažuriraju svoj sadržaj na temelju interakcija korisnika i odgovora poslužitelja. ### Odabir pravog alata za posao Kada je riječ o ažuriranju vašeg HTML-a pomoću JavaScripta, imate nekoliko opcija. Razmislite o njima kao o različitim alatima u kutiji s alatima - svaki je savršen za određene zadatke: | Metoda | Za što je odlična | Kada je koristiti | Razina sigurnosti | |--------|-------------------|-------------------|-------------------| | `textContent` | Sigurno prikazivanje korisničkih podataka | Kad god prikazujete tekst | ✅ Potpuno sigurno | | `createElement()` + `append()` | Izgradnja složenih izgleda | Kreiranje novih sekcija/lista | ✅ Pouzdano | | `innerHTML` | Postavljanje HTML sadržaja | ⚠️ Pokušajte izbjegavati ovu metodu | ❌ Rizično | #### Siguran način prikazivanja teksta: textContent Svojstvo [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent) vaš je najbolji prijatelj kada prikazujete korisničke podatke. To je poput zaštitara za vašu web stranicu - ništa štetno ne Za složeniji sadržaj, kombinirajte [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) s metodom [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append): ```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); ``` **Razumijevanje ovog pristupa:** - **Stvara** nove DOM elemente programatski - **Omogućuje** potpunu kontrolu nad atributima i sadržajem elemenata - **Omogućuje** složene, ugniježđene strukture elemenata - **Održava** sigurnost odvajanjem strukture od sadržaja > ⚠️ **Sigurnosno upozorenje**: Iako se [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) često pojavljuje u tutorijalima, može izvršavati ugrađene skripte. Kao što sigurnosni protokoli u CERN-u sprječavaju neovlašteno izvršavanje koda, korištenje `textContent` i `createElement` pruža sigurnije alternative. > **Rizici innerHTML-a:** - Izvršava bilo koje `