# Створення банківського додатку, частина 3: Методи отримання та використання даних Згадайте комп'ютер Enterprise зі Star Trek - коли капітан Пікард запитує статус корабля, інформація з'являється миттєво, без перезавантаження інтерфейсу. Саме такий плавний потік інформації ми створюємо тут за допомогою динамічного отримання даних. Зараз ваш банківський додаток схожий на друковану газету - інформативний, але статичний. Ми перетворимо його на щось схоже на центр управління місіями NASA, де дані постійно оновлюються в реальному часі, не перериваючи робочий процес користувача. Ви навчитеся асинхронно взаємодіяти з серверами, обробляти дані, які надходять у різний час, і перетворювати необроблену інформацію на щось корисне для ваших користувачів. Це різниця між демонстраційним і готовим до використання програмним забезпеченням. ## Тест перед лекцією [Тест перед лекцією](https://ff-quizzes.netlify.app/web/quiz/45) ### Передумови Перед тим як зануритися в отримання даних, переконайтеся, що у вас готові наступні компоненти: - **Попередній урок**: Завершіть [Форму входу та реєстрації](../2-forms/README.md) - ми будемо будувати на цій основі - **Локальний сервер**: Встановіть [Node.js](https://nodejs.org) і [запустіть сервер API](../api/README.md), щоб забезпечити дані облікового запису - **З'єднання з API**: Перевірте з'єднання з сервером за допомогою цієї команди: ```bash curl http://localhost:5000/api # Expected response: "Bank API v1.0.0" ``` Цей швидкий тест забезпечує правильну взаємодію всіх компонентів: - Перевіряє, чи Node.js працює правильно на вашій системі - Підтверджує, що ваш сервер API активний і відповідає - Переконується, що ваш додаток може досягти сервера (як перевірка радіозв'язку перед місією) --- ## Розуміння отримання даних у сучасних веб-додатках Спосіб обробки даних веб-додатками значно еволюціонував за останні два десятиліття. Розуміння цієї еволюції допоможе вам оцінити, чому сучасні техніки, такі як AJAX і Fetch API, є настільки потужними і чому вони стали необхідними інструментами для веб-розробників. Давайте розглянемо, як працювали традиційні веб-сайти у порівнянні з динамічними, чутливими додатками, які ми створюємо сьогодні. ### Традиційні багатосторінкові додатки (MPA) У ранні дні вебу кожен клік був схожий на зміну каналів на старому телевізорі - екран ставав порожнім, а потім повільно налаштовувався на новий контент. Це була реальність ранніх веб-додатків, де кожна взаємодія означала повне перезавантаження сторінки. ```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) ``` ![Робочий процес оновлення у багатосторінковому додатку](../../../../translated_images/mpa.7f7375a1a2d4aa779d3f928a2aaaf9ad76bcdeb05cfce2dc27ab126024050f51.uk.png) **Чому цей підхід здавався незручним:** - Кожен клік означав повне перезавантаження сторінки - Користувачів переривали ці дратівливі спалахи сторінок - Ваше інтернет-з'єднання працювало понаднормово, завантажуючи той самий заголовок і підвал знову і знову - Додатки більше нагадували перегляд картотеки, ніж використання програмного забезпечення ### Сучасні односторінкові додатки (SPA) AJAX (асинхронний JavaScript і XML) повністю змінив цей підхід. Як модульний дизайн Міжнародної космічної станції, де астронавти можуть замінити окремі компоненти без перебудови всієї структури, AJAX дозволяє нам оновлювати конкретні частини веб-сторінки без перезавантаження всього. Незважаючи на те, що в назві згадується XML, сьогодні ми здебільшого використовуємо JSON, але основний принцип залишається: оновлювати лише те, що потрібно змінити. ```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) ``` ![Робочий процес оновлення у односторінковому додатку](../../../../translated_images/spa.268ec73b41f992c2a21ef9294235c6ae597b3c37e2c03f0494c2d8857325cc57.uk.png) **Чому SPA здаються набагато кращими:** - Оновлюються лише ті частини, які дійсно змінилися (розумно, правда?) - Більше ніяких різких переривань - ваші користувачі залишаються у своєму потоці - Менше даних передається через мережу, що означає швидше завантаження - Все здається швидким і чутливим, як додатки на вашому телефоні ### Еволюція до сучасного Fetch API Сучасні браузери надають [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), який замінює старий [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Як різниця між використанням телеграфу і електронної пошти, Fetch API використовує обіцянки для чистішого асинхронного коду і природно обробляє JSON. | Функція | XMLHttpRequest | Fetch API | |---------|----------------|----------| | **Синтаксис** | Складний, заснований на зворотних викликах | Чистий, заснований на обіцянках | | **Обробка JSON** | Потрібен ручний аналіз | Вбудований метод `.json()` | | **Обробка помилок** | Обмежена інформація про помилки | Детальна інформація про помилки | | **Сучасна підтримка** | Сумісність зі спадщиною | Обіцянки ES6+ і async/await | > 💡 **Сумісність з браузерами**: Хороші новини - Fetch API працює у всіх сучасних браузерах! Якщо вам цікаві конкретні версії, [caniuse.com](https://caniuse.com/fetch) має повну історію сумісності. > **Основний висновок:** - Чудово працює у Chrome, Firefox, Safari та Edge (загалом скрізь, де є ваші користувачі) - Лише Internet Explorer потребує додаткової допомоги (і чесно кажучи, час відпустити IE) - Ідеально підходить для елегантних async/await патернів, які ми будемо використовувати пізніше ### Реалізація системи входу та отримання даних Тепер давайте реалізуємо систему входу, яка перетворить ваш банківський додаток зі статичного дисплея на функціональний додаток. Як протоколи автентифікації, що використовуються у захищених військових об'єктах, ми перевіримо облікові дані користувача, а потім надамо доступ до його конкретних даних. Ми будемо будувати це поступово, починаючи з базової автентифікації, а потім додаючи можливості отримання даних. #### Крок 1: Створення основи функції входу Відкрийте ваш файл `app.js` і додайте нову функцію `login`. Вона буде обробляти процес автентифікації користувача: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **Розберемо це:** - Ключове слово `async`? Воно говорить JavaScript: "ей, ця функція може потребувати очікування" - Ми знаходимо нашу форму на сторінці (нічого складного, просто знаходимо її за ID) - Потім витягуємо те, що користувач ввів як своє ім'я користувача - Ось цікавий трюк: ви можете отримати доступ до будь-якого вводу форми за його атрибутом `name` - не потрібно додаткових викликів getElementById! > 💡 **Шаблон доступу до форми**: Кожен елемент управління формою може бути доступний за його ім'ям (встановленим у HTML за допомогою атрибуту `name`) як властивість елемента форми. Це забезпечує чистий, читабельний спосіб отримання даних форми. #### Крок 2: Створення функції отримання даних облікового запису Далі ми створимо спеціальну функцію для отримання даних облікового запису з сервера. Це слідує тому ж шаблону, що і ваша функція реєстрації, але зосереджено на отриманні даних: ```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' }; } } ``` **Що виконує цей код:** - **Використовує** сучасний `fetch` API для асинхронного запиту даних - **Конструює** URL запиту GET з параметром імені користувача - **Застосовує** `encodeURIComponent()` для безпечної обробки спеціальних символів у URL - **Перетворює** відповідь у формат JSON для легкого маніпулювання даними - **Обробляє** помилки акуратно, повертаючи об'єкт помилки замість аварійного завершення > ⚠️ **Примітка щодо безпеки**: Функція `encodeURIComponent()` обробляє спеціальні символи у URL. Як системи кодування, що використовуються у військових комунікаціях, вона забезпечує, що ваше повідомлення прибуде точно так, як задумано, запобігаючи неправильному тлумаченню символів, таких як "#" або "&". > **Чому це важливо:** - Запобігає тому, щоб спеціальні символи ламали URL - Захищає від атак маніпуляції URL - Забезпечує, що ваш сервер отримує задуманий набір даних - Слідує практикам безпечного кодування #### Розуміння HTTP GET запитів Ось що може вас здивувати: коли ви використовуєте `fetch` без додаткових опцій, він автоматично створює [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET) запит. Це ідеально для того, що ми робимо - запитуємо сервер: "ей, чи можу я побачити дані цього користувача?" Думайте про GET запити як про ввічливе прохання позичити книгу з бібліотеки - ви запитуєте, щоб побачити щось, що вже існує. POST запити (які ми використовували для реєстрації) більше схожі на подання нової книги для додавання до колекції. | GET запит | POST запит | |-----------|-----------| | **Призначення** | Отримання існуючих даних | Надсилання нових даних на сервер | | **Параметри** | У шляху URL/рядку запиту | У тілі запиту | | **Кешування** | Може кешуватися браузерами | Зазвичай не кешується | | **Безпека** | Видимий у URL/журналах | Прихований у тілі запиту | #### Крок 3: Об'єднання всього разом Тепер найзадовільніша частина - давайте підключимо вашу функцію отримання даних облікового запису до процесу входу. Тут все стає на свої місця: ```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'); } ``` Ця функція слідує чіткій послідовності: - Витягує ім'я користувача з вводу форми - Запитує дані облікового запису користувача з сервера - Обробляє будь-які помилки, які виникають під час процесу - Зберігає дані облікового запису та переходить на панель управління у разі успіху > 🎯 **Патерн Async/Await**: Оскільки `getAccount` є асинхронною функцією, ми використовуємо ключове слово `await`, щоб призупинити виконання до отримання відповіді від сервера. Це запобігає продовженню коду з невизначеними даними. #### Крок 4: Створення місця для ваших даних Вашому додатку потрібне місце, де він буде зберігати інформацію про обліковий запис після її завантаження. Думайте про це як про короткострокову пам'ять вашого додатку - місце, де зберігаються дані поточного користувача. Додайте цей рядок на початку вашого файлу `app.js`: ```javascript // This holds the current user's account data let account = null; ``` **Чому це необхідно:** - Зберігає дані облікового запису доступними з будь-якого місця у вашому додатку - Початок з `null` означає "поки що ніхто не увійшов" - Оновлюється, коли хтось успішно входить або реєструється - Діє як єдине джерело правди - ніякої плутанини щодо того, хто увійшов #### Крок 5: Підключення вашої форми Тепер давайте підключимо вашу нову функцію входу до HTML форми. Оновіть тег форми ось так: ```html
``` **Що робить ця маленька зміна:** - Зупиняє форму від її стандартної поведінки "перезавантажити всю сторінку" - Викликає вашу власну функцію JavaScript замість цього - Зберігає все плавним і схожим на односторінковий додаток - Дає вам повний контроль над тим, що відбувається, коли користувачі натискають "Вхід" #### Крок 6: Покращення функції реєстрації Для узгодженості оновіть вашу функцію `register`, щоб також зберігати дані облікового запису та переходити на панель управління: ```javascript // Add these lines at the end of your register function account = result; navigate('/dashboard'); ``` **Це покращення забезпечує:** - **Плавний** перехід від реєстрації до панелі управління - **Послідовний** користувацький досвід між процесами входу та реєстрації - **Миттєвий** доступ до даних облікового запису після успішної реєстрації #### Тестування вашої реалізації ```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] ``` **Час випробувати це:** 1. Створіть новий обліковий запис, щоб переконатися, що все працює 2. Спробуйте увійти з тими ж обліковими даними 3. Загляньте в консоль вашого браузера (F12), якщо щось здається неправильним 4. Переконайтеся, що ви потрапляєте на панель управління після успішного входу Якщо щось не працює, не панікуйте! Більшість проблем - це прості виправлення, такі як друкарські помилки або забуття запустити сервер API. #### Коротке слово про магію між різними джерелами Ви можете запитати: "Як мій веб-додаток спілкується з цим сервером API, якщо вони працюють на різних портах?" Чудове запитання! Це стосується того, з чим кожен веб-розробник стикається рано чи пізно. > 🔒 **Безпека між джерелами**: Браузери застосовують "політику одного джерела", щоб запобігти несанкціонованій комунікації між різними доменами. Як система перевірки на вході до Пентагону, вони перевіряють, чи дозволена комунікація, перш ніж дозволити передачу даних. > **У нашій конфігурації:** - Ваш веб-додаток працює на `localhost:3000` (сервер розробки) - Ваш сервер API працює на `localhost:5000` (сервер бекенду) - Сервер API включає [заголовки CORS](https://developer.mozilla.org/docs/Web/HTTP/CORS), які явно дозволяють комунікацію з вашим веб-додатком Ця конфігурація відображає реальну розробку, де фронтенд і бекенд додатки зазвичай працюють на окремих серверах. > 📚 **Дізнайтеся більше**: Глибше зануртеся в API та отримання даних за допомогою цього детального [модуля Microsoft Learn про API](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## Перетворення ваших даних у HTML Тепер ми зробимо отримані дані видимими для користувачів через маніпуляцію DOM. Як процес розробки фотографій у тем Для більш складного контенту, комбінуйте [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) з методом [`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); ``` **Розуміння цього підходу:** - **Створює** нові елементи DOM програмно - **Забезпечує** повний контроль над атрибутами та вмістом елементів - **Дозволяє** створювати складні, вкладені структури елементів - **Зберігає** безпеку, розділяючи структуру від контенту > ⚠️ **Міркування щодо безпеки**: Хоча [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) часто зустрічається в багатьох навчальних матеріалах, він може виконувати вбудовані скрипти. Як і протоколи безпеки в CERN, які запобігають виконанню несанкціонованого коду, використання `textContent` та `createElement` є більш безпечними альтернативами. > **Ризики використання innerHTML:** - Виконує будь-які теги `