# Budowa aplikacji bankowej, część 3: Metody pobierania i wykorzystywania danych Pomyśl o komputerze Enterprise ze Star Trek – gdy kapitan Picard pyta o status statku, informacje pojawiają się natychmiast, bez konieczności wyłączania i odbudowy całego interfejsu. Ten płynny przepływ informacji to dokładnie to, co tworzymy tutaj, dzięki dynamicznemu pobieraniu danych. Obecnie twoja aplikacja bankowa jest jak papierowa gazeta – informacyjna, ale statyczna. Przekształcimy ją w coś bardziej przypominającego centrum dowodzenia NASA, gdzie dane płyną nieprzerwanie i aktualizują się w czasie rzeczywistym, nie przerywając pracy użytkownika. Nauczysz się, jak komunikować się z serwerami asynchronicznie, obsługiwać dane, które przychodzą w różnych momentach, i przekształcać surowe informacje w coś znaczącego dla twoich użytkowników. To jest różnica między demonstracją a oprogramowaniem gotowym do produkcji. ## ⚡ Co możesz zrobić w następnych 5 minutach **Szybka ścieżka dla zapracowanych deweloperów** ```mermaid flowchart LR A[⚡ 5 minut] --> B[Skonfiguruj serwer API] B --> C[Przetestuj pobieranie za pomocą curl] C --> D[Stwórz funkcję logowania] D --> E[Zobacz dane w działaniu] ``` - **Minuty 1-2**: Uruchom serwer API (`cd api && npm start`) i przetestuj połączenie - **Minuta 3**: Utwórz podstawową funkcję `getAccount()` używając fetch - **Minuta 4**: Podłącz formularz logowania z `action="javascript:login()"` - **Minuta 5**: Przetestuj logowanie i obserwuj dane konta w konsoli **Szybkie polecenia testowe**: ```bash # Sprawdź, czy API działa curl http://localhost:5000/api # Przetestuj pobieranie danych konta curl http://localhost:5000/api/accounts/test ``` **Dlaczego to ważne**: W ciągu 5 minut zobaczysz magię asynchronicznego pobierania danych, która napędza każdą nowoczesną aplikację webową. To fundament, który sprawia, że aplikacje są responsywne i żywe. ## 🗺️ Twoja podróż edukacyjna przez aplikacje webowe oparte na danych ```mermaid journey title Od statycznych stron do dynamicznych aplikacji section Zrozumienie ewolucji Tradycyjne przeładowania stron: 3: You Odkryj korzyści AJAX/SPA: 5: You Opanuj wzorce Fetch API: 7: You section Budowanie uwierzytelniania Twórz funkcje logowania: 4: You Obsługuj operacje asynchroniczne: 6: You Zarządzaj sesjami użytkowników: 8: You section Dynamiczne aktualizacje UI Naucz się manipulacji DOM: 5: You Twórz wyświetlanie transakcji: 7: You Twórz responsywne pulpity: 9: You section Profesjonalne wzorce Renderowanie oparte na szablonach: 6: You Strategie obsługi błędów: 7: You Optymalizacja wydajności: 8: You ``` **Cel twojej podróży**: Na koniec tej lekcji zrozumiesz, jak nowoczesne aplikacje webowe pobierają, przetwarzają i wyświetlają dane dynamicznie, tworząc płynne doświadczenia użytkownika, których oczekujemy od profesjonalnych aplikacji. ## Quiz przed wykładem [Quiz przed wykładem](https://ff-quizzes.netlify.app/web/quiz/45) ### Wymagania wstępne Zanim zagłębisz się w pobieranie danych, upewnij się, że masz gotowe następujące elementy: - **Poprzednia lekcja**: Ukończ [formularz logowania i rejestracji](../2-forms/README.md) – na tym zbudujemy - **Lokalny serwer**: Zainstaluj [Node.js](https://nodejs.org) i [uruchom serwer API](../api/README.md), który dostarczy dane konta - **Połączenie z API**: Przetestuj połączenie z serwerem tym poleceniem: ```bash curl http://localhost:5000/api # Oczekiwana odpowiedź: "Bank API v1.0.0" ``` Ten szybki test zapewnia prawidłową komunikację komponentów: - Sprawdza, czy Node.js działa poprawnie na twoim systemie - Potwierdza, że serwer API jest aktywny i odpowiada - Weryfikuje, czy aplikacja może połączyć się z serwerem (jak sprawdzenie łączności radiowej przed misją) ## 🧠 Przegląd ekosystemu zarządzania danymi ```mermaid mindmap root((Zarządzanie Danymi)) Authentication Flow Login Process Walidacja Formularza Weryfikacja Poświadczeń Zarządzanie Sesją User State Globalny Obiekt Konta Strażnicy Nawigacji Obsługa Błędów API Communication Fetch Patterns Żądania GET Żądania POST Odpowiedzi Błędów Data Formats Przetwarzanie JSON Kodowanie URL Parsowanie Odpowiedzi Dynamic UI Updates DOM Manipulation Bezpieczne Aktualizacje Tekstu Tworzenie Elementów Klonowanie Szablonu User Experience Aktualizacje w Czasie Rzeczywistym Komunikaty o Błędach Stany Ładowania Security Considerations XSS Prevention Użycie textContent Dezynfekcja Danych Wejściowych Bezpieczne Tworzenie HTML CORS Handling Żądania Międzydomenowe Konfiguracja Nagłówków Konfiguracja Środowiska Developerskiego ``` **Podstawowa zasada**: Nowoczesne aplikacje webowe to systemy orkiestracji danych – koordynują interfejsy użytkownika, serwery API i modele bezpieczeństwa przeglądarki, by tworzyć płynne i responsywne doświadczenia. --- ## Zrozumienie pobierania danych w nowoczesnych aplikacjach webowych Sposób, w jaki aplikacje internetowe obsługują dane, znacznie ewoluował w ciągu ostatnich dwóch dekad. Zrozumienie tej ewolucji pomoże ci docenić, dlaczego nowoczesne techniki, takie jak AJAX i Fetch API, są tak potężne i dlaczego stały się niezbędnymi narzędziami dla deweloperów webowych. Przyjrzyjmy się, jak działały tradycyjne strony internetowe w porównaniu z dynamicznymi i responsywnymi aplikacjami, które tworzymy dziś. ### Tradycyjne aplikacje wielostronicowe (MPA) Na wczesnym etapie internetu każde kliknięcie było jak zmiana kanału w starym telewizorze – ekran robił się czarny, a następnie powoli ładował nową zawartość. Tak wyglądały wczesne aplikacje webowe, gdzie każda interakcja oznaczała kompletne przeładowanie całej strony. ```mermaid sequenceDiagram participant User participant Browser participant Server User->>Browser: Kliknięcie linku lub wysłanie formularza Browser->>Server: Żądanie nowej strony HTML Note over Browser: Strona staje się pusta Server->>Browser: Zwraca kompletną stronę HTML Browser->>User: Wyświetla nową stronę (flash/przeładowanie) ```  **Dlaczego to było niewygodne:** - Każde kliknięcie powodowało całkowite przeładowanie strony - Użytkownicy byli przerywani w trakcie myślenia przez irytujące migotanie strony - Twoje łącze internetowe pracowało na pełnych obrotach, wielokrotnie pobierając ten sam nagłówek i stopkę - Aplikacje bardziej przypominały przeklikiwanie się przez szafki z dokumentami niż obsługę oprogramowania ### Nowoczesne aplikacje jednowstronicowe (SPA) AJAX (Asynchronous JavaScript and XML) całkowicie zmienił ten schemat. Podobnie jak modułowa konstrukcja Międzynarodowej Stacji Kosmicznej, gdzie astronauci mogą wymieniać poszczególne elementy bez przebudowy całej struktury, AJAX pozwala aktualizować konkretne części strony bez przeładowywania całości. Mimo że w nazwie jest XML, obecnie używamy głównie JSON, ale idea pozostaje ta sama: aktualizujemy tylko to, co trzeba zmienić. ```mermaid sequenceDiagram participant User participant Browser participant JavaScript participant Server User->>Browser: Wchodzi w interakcję ze stroną Browser->>JavaScript: Wywołuje obsługę zdarzenia JavaScript->>Server: Pobiera tylko potrzebne dane Server->>JavaScript: Zwraca dane w formacie JSON JavaScript->>Browser: Aktualizuje konkretne elementy strony Browser->>User: Wyświetla zaktualizowaną zawartość (bez przeładowania) ```  **Dlaczego SPAs działają dużo lepiej:** - Aktualizują tylko zmienione fragmenty (sprytne, prawda?) - Brak uciążliwych przerw – użytkownicy płynnie wykonują swoje zadania - Mniej danych przesyłanych przez sieć oznacza szybsze ładowanie - Wszystko działa szybko i responsywnie, jak aplikacje na telefonie ### Ewolucja do nowoczesnego Fetch API Nowoczesne przeglądarki oferują [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), które zastępuje starszy [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). To jak przejście od używania telegrafu do korzystania z poczty elektronicznej – Fetch API opiera się na promise’ach dla czystszego kodu asynchronicznego i naturalnie obsługuje JSON. | Funkcja | XMLHttpRequest | Fetch API | |---------|----------------|----------| | **Składnia** | Złożona, oparta na callbackach | Czysta, oparta na promise’ach | | **Obsługa JSON** | Wymaga ręcznego parsowania | Wbudowana metoda `.json()` | | **Obsługa błędów** | Ograniczone informacje | Szczegółowe dane o błędach | | **Wsparcie nowoczesne** | Zgodność wsteczna | Promise i async/await ES6+ | > 💡 **Kompatybilność przeglądarek**: Dobra wiadomość – Fetch API działa we wszystkich nowoczesnych przeglądarkach! Jeśli interesują cię konkretne wersje, [caniuse.com](https://caniuse.com/fetch) ma pełną listę kompatybilności. > **Podsumowując:** - Świetnie działa w Chrome, Firefox, Safari i Edge (praktycznie wszędzie tam, gdzie są twoi użytkownicy) - Tylko Internet Explorer wymaga dodatkowej obsługi (szczerze mówiąc, czas pożegnać IE) - Idealnie przygotowuje do elegantnych wzorców async/await, które wykorzystamy później ### Implementacja logowania użytkownika i pobierania danych Teraz zaimplementujemy system logowania, który zmieni twoją aplikację bankową z statycznego widoku w funkcjonalną aplikację. Podobnie jak protokoły uwierzytelniania używane w bezpiecznych obiektach wojskowych, zweryfikujemy dane użytkownika i udzielimy dostępu do jego danych. Zbudujemy to krok po kroku, zaczynając od podstawowej autoryzacji, a potem dodając pobieranie danych. #### Krok 1: Utwórz fundament funkcji logowania Otwórz plik `app.js` i dodaj nową funkcję `login`, która będzie obsługiwać proces logowania użytkownika: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **Wyjaśnienie:** - Słowo kluczowe `async` mówi JavaScriptowi, że ta funkcja może wymagać oczekiwania na operacje - Pobieramy formularz z strony (nic specjalnego, tylko szukamy po ID) - Wyciągamy wpisaną przez użytkownika nazwę użytkownika - Sprytny trik: możesz odwoływać się do dowolnego pola formularza po jego nazwie (`name`) – nie trzeba dodatkowych getElementById! > 💡 **Wzorzec dostępu do formularza**: Każdy element formularza można uzyskać jako własność formularza po jego nazwie (ustawionej w atrybucie `name` w HTML). To zapewnia czytelny sposób na pobieranie danych z formularza. #### Krok 2: Utwórz funkcję pobierania danych konta Następnie stwórz dedykowaną funkcję, która pobierze dane konta z serwera. Postępuje podobnie jak funkcja rejestracji, ale skupia się na pobieraniu danych: ```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' }; } } ``` **Co robi ten kod:** - **Używa** nowoczesnego `fetch` do asynchronicznego pobierania danych - **Tworzy** URL żądania GET z parametrem nazwy użytkownika - **Zastosowuje** `encodeURIComponent()` dla bezpiecznego kodowania znaków specjalnych w URL - **Konwertuje** odpowiedź na format JSON dla łatwej obsługi danych - **Obsługuje** błędy, zwracając obiekt błędu zamiast awarii > ⚠️ **Uwaga bezpieczeństwa**: Funkcja `encodeURIComponent()` obsługuje znaki specjalne w URL, podobnie jak systemy kodowania w komunikacji morskiej. Zapewnia, że wiadomość dotrze dokładnie tak, jak zamierzasz, zapobiegając niepoprawnej interpretacji znaków takich jak "#" czy "&". > **Dlaczego to ważne:** - Zapobiega zepsuciu URL przez specjalne znaki - Chroni przed atakami manipulacji URL - Gwarantuje, że serwer otrzyma właściwe dane - Stosuje dobre praktyki bezpieczeństwa #### Zrozumienie zapytań HTTP GET Może cię zdziwić, że korzystając z `fetch` bez dodatkowych opcji, automatycznie wysyłasz żądanie [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET). To idealne do naszego celu – pytania serwera „hej, czy mogę zobaczyć dane konta tego użytkownika?”. Pomyśl o żądaniach GET jak o uprzejmym wypożyczaniu książki z biblioteki – prosisz o obejrzenie czegoś, co już istnieje. Żądania POST (które stosowaliśmy podczas rejestracji) są bardziej jak przesłanie nowej książki do kolekcji. | Żądanie GET | Żądanie POST | |-------------|-------------| | **Cel** | Pobranie istniejących danych | Wysłanie nowych danych na serwer | | **Parametry** | W ścieżce URL lub ciągu zapytania | W ciele żądania | | **Cache** | Może być buforowane przez przeglądarki | Zazwyczaj nie jest buforowane | | **Bezpieczeństwo** | Widoczne w URL i logach | Ukryte w ciele żądania | ```mermaid sequenceDiagram participant B as Przeglądarka participant S as Serwer Note over B,S: Żądanie GET (Pobieranie danych) B->>S: GET /api/accounts/test S-->>B: 200 OK + Dane konta Note over B,S: Żądanie POST (Przesyłanie danych) B->>S: POST /api/accounts + Nowe dane konta S-->>B: 201 Utworzono + Potwierdzenie Note over B,S: Obsługa błędów B->>S: GET /api/accounts/nonexistent S-->>B: 404 Nie znaleziono + Komunikat o błędzie ``` #### Krok 3: Połącz wszystko razem Teraz przyjemna część – połącz funkcję pobierania konta z procesem logowania. To tutaj wszystko się zazębia: ```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'); } ``` Ta funkcja wykonuje następujące kroki: - Pobiera nazwę użytkownika z formularza - Żąda danych konta użytkownika od serwera - Obsługuje ewentualne błędy podczas tego procesu - Przechowuje dane konta i przechodzi do panelu użytkownika po sukcesie > 🎯 **Wzorzec async/await**: Ponieważ `getAccount` jest funkcją asynchroniczną, używamy słowa kluczowego `await`, aby zatrzymać wykonanie do momentu, gdy serwer odpowie. Zapobiega to dalszemu wykonywaniu kodu z niezdefiniowanymi danymi. #### Krok 4: Utwórz miejsce na dane Twoja aplikacja potrzebuje miejsca, by zapamiętać informacje o koncie po ich załadowaniu. To jak krótkotrwała pamięć twojej aplikacji – miejsce, gdzie możesz mieć pod ręką dane bieżącego użytkownika. Dodaj tę linię na początku swojego pliku `app.js`: ```javascript // To przechowuje dane konta aktualnego użytkownika let account = null; ``` **Dlaczego tego potrzebujemy:** - Umożliwia dostęp do danych konta z dowolnego miejsca aplikacji - Początkowa wartość `null` oznacza „nikt jeszcze się nie zalogował” - Aktualizuje się, gdy ktoś się skutecznie zaloguje lub zarejestruje - Działa jak jedno źródło prawdy – brak zamieszania, kto jest zalogowany #### Krok 5: Podłącz formularz Teraz podłącz nową funkcję logowania do formularza HTML. Zaktualizuj tag formularza tak: ```html
``` **Co zmienia ta drobna modyfikacja:** - Powstrzymuje domyślne zachowanie formularza polegające na przeładowaniu całej strony - Wywołuje twoją niestandardową funkcję JavaScript - Utrzymuje płynność i styl aplikacji jednowstronicowej - Daje pełną kontrolę nad tym, co się dzieje po kliknięciu „Zaloguj” #### Krok 6: Ulepsz funkcję rejestracji Dla spójności zaktualizuj funkcję `register`, aby także zapisywała dane konta i przechodziła do panelu użytkownika: ```javascript // Dodaj te linie na końcu funkcji rejestracji account = result; navigate('/dashboard'); ``` **Ta poprawka zapewnia:** - **Płynne** przejście z rejestracji do panelu użytkownika - **Spójne** doświadczenie użytkownika pomiędzy logowaniem a rejestracją - **Natychmiastowy** dostęp do danych konta po pomyślnej rejestracji #### Testowanie implementacji ```mermaid flowchart TD A[Użytkownik wprowadza dane uwierzytelniające] --> B[Wywołanie funkcji logowania] B --> C[Pobierz dane konta z serwera] C --> D{Dane zostały odebrane pomyślnie?} D -->|Tak| E[Zapisz dane konta globalnie] D -->|Nie| F[Wyświetl komunikat o błędzie] E --> G[Przejdź do panelu] F --> H[Użytkownik pozostaje na stronie logowania] ``` **Czas sprawdzić działanie:** 1. Utwórz nowe konto, by upewnić się, że wszystko działa 2. Spróbuj zalogować się tymi samymi danymi 3. Sprawdź konsolę przeglądarki (F12), jeśli coś jest nie tak 4. Upewnij się, że po zalogowaniu trafiasz do panelu użytkownika Jeśli coś nie działa, nie panikuj! Większość problemów można naprawić prostymi poprawkami, jak literówki lub brak uruchomionego serwera API. #### Szybka uwaga o magii cross-origin Możesz się zastanawiać: „Jak moja aplikacja webowa komunikuje się z serwerem API, skoro działają na różnych portach?” Dobre pytanie! To temat, na który każdy web developer kiedyś natrafia. > 🔒 **Bezpieczeństwo cross-origin**: Przeglądarki stosują „zasadę tego samego pochodzenia” (same-origin policy), aby zapobiegać nieautoryzowanej komunikacji między różnymi domenami. Podobnie jak system kontroli bezpieczeństwa w Pentagonie, weryfikują, czy komunikacja jest autoryzowana przed zezwoleniem na transfer danych. > **W naszej konfiguracji:** - Twoja aplikacja działa na `localhost:3000` (serwer deweloperski) - Serwer API działa na `localhost:5000` (serwer backendowy) - Serwer API zawiera [nagłówki CORS](https://developer.mozilla.org/docs/Web/HTTP/CORS), które wyraźnie pozwalają na komunikację z twoją aplikacją webową To odzwierciedla rzeczywiste środowisko deweloperskie, gdzie frontend i backend zwykle działają na osobnych serwerach. > 📚 **Dowiedz się więcej**: Zgłębiaj API i pobieranie danych dzięki temu obszernemu [modułowi Microsoft Learn o API](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## Ożywianie danych w HTML Teraz uczynimy pobrane dane widocznymi dla użytkowników poprzez manipulację DOM. Tak jak podczas wywoływania zdjęć w ciemni, bierzemy niewidzialne dane i przekształcamy je w coś, co użytkownicy mogą zobaczyć i z czym mogą wejść w interakcję. Manipulacja DOM to technika, która przekształca statyczne strony internetowe w dynamiczne aplikacje, aktualizujące swoją zawartość na podstawie interakcji użytkownika i odpowiedzi serwera. ### Wybór odpowiedniego narzędzia Jeśli chodzi o aktualizację HTML za pomocą JavaScript, masz do dyspozycji kilka opcji. Pomyśl o nich jak o różnych narzędziach w skrzynce - każde idealne do określonych zadań: | Metoda | Do czego się świetnie nadaje | Kiedy jej używać | Poziom bezpieczeństwa | |--------|------------------------------|------------------|-----------------------| | `textContent` | Bezpieczne wyświetlanie danych użytkownika | Zawsze gdy pokazujesz tekst | ✅ Niezawodna | | `createElement()` + `append()` | Tworzenie złożonych układów | Tworzenie nowych sekcji/list | ✅ Solidna | | `innerHTML` | Ustawianie zawartości HTML | ⚠️ Lepiej unikać | ❌ Ryzykowna | #### Bezpieczny sposób na wyświetlanie tekstu: textContent Właściwość [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent) to twój najlepszy sprzymierzeniec przy wyświetlaniu danych użytkownika. To jak ochroniarz twojej strony - nic szkodliwego nie przejdzie: ```javascript // Bezpieczny, niezawodny sposób aktualizacji tekstu const balanceElement = document.getElementById('balance'); balanceElement.textContent = account.balance; ``` **Zalety używania textContent:** - Traktuje wszystko jak zwykły tekst (zapobiega wykonywaniu skryptów) - Automatycznie czyści istniejącą zawartość - Wydajne przy prostych aktualizacjach tekstu - Zapewnia wbudowaną ochronę przed złośliwą zawartością #### Tworzenie dynamicznych elementów HTML Dla bardziej złożonej zawartości połącz [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) z metodą [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append): ```javascript // Bezpieczny sposób tworzenia nowych elementów const transactionItem = document.createElement('div'); transactionItem.className = 'transaction-item'; transactionItem.textContent = `${transaction.date}: ${transaction.description}`; container.append(transactionItem); ``` **Co robi to podejście:** - **Tworzy** nowe elementy DOM programistycznie - **Pozwala zachować** pełną kontrolę nad atrybutami i zawartością elementów - **Umożliwia** tworzenie złożonych, zagnieżdżonych struktur - **Zachowuje** bezpieczeństwo przez oddzielenie struktury od zawartości > ⚠️ **Kwestionariusz bezpieczeństwa**: Choć [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) pojawia się w wielu tutorialach, może wykonywać osadzone skrypty. Podobnie jak protokoły bezpieczeństwa CERN, które zapobiegają nieautoryzowanemu wykonywaniu kodu, stosowanie `textContent` i `createElement` zapewnia bezpieczniejsze alternatywy. > **Ryzyka dotyczące innerHTML:** - Wykonuje wszystkie znaczniki `