# Build a Banking App Part 3: Methods of Fetching and Using Data Think about the Enterprise's computer in Star Trek - when Captain Picard asks for ship status, the information appears instantly without the whole interface shutting down and rebuilding itself. That seamless flow of information is exactly what we're building here with dynamic data fetching. Right now, your banking app is like a printed newspaper - informative but static. We're going to transform it into something more like mission control at NASA, where data flows continuously and updates in real-time without interrupting the user's workflow. You'll learn how to communicate with servers asynchronously, handle data that arrives at different times, and transform raw information into something meaningful for your users. This is the difference between a demo and production-ready software. ## Pre-Lecture Quiz [Pre-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/45) ### Prerequisites Before diving into data fetching, ensure you have these components ready: - **Previous Lesson**: Complete the [Login and Registration Form](../2-forms/README.md) - we'll build on this foundation - **Local Server**: Install [Node.js](https://nodejs.org) and [run the server API](../api/README.md) to provide account data - **API Connection**: Test your server connection with this command: ```bash curl http://localhost:5000/api # Expected response: "Bank API v1.0.0" ``` This quick test ensures all components are communicating properly: - Verifies that Node.js is running correctly on your system - Confirms your API server is active and responding - Validates that your app can reach the server (like checking radio contact before a mission) --- ## Understanding Data Fetching in Modern Web Apps The way web applications handle data has evolved dramatically over the past two decades. Understanding this evolution will help you appreciate why modern techniques like AJAX and the Fetch API are so powerful and why they've become essential tools for web developers. Let's explore how traditional websites worked compared to the dynamic, responsive applications we build today. ### Traditional Multi-Page Applications (MPA) In the early days of the web, every click was like changing channels on an old television - the screen would go blank, then slowly tune into the new content. This was the reality of early web applications, where every interaction meant completely rebuilding the entire page from scratch. ```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) ```  **Why this approach felt clunky:** - Every click meant rebuilding the entire page from scratch - Users got interrupted mid-thought by those annoying page flashes - Your internet connection worked overtime downloading the same header and footer repeatedly - Apps felt more like clicking through a filing cabinet than using software ### Modern Single-Page Applications (SPA) AJAX (Asynchronous JavaScript and XML) changed this paradigm entirely. Like the modular design of the International Space Station, where astronauts can replace individual components without rebuilding the entire structure, AJAX allows us to update specific parts of a webpage without reloading everything. Despite the name mentioning XML, we mostly use JSON today, but the core principle remains: update only what needs to change. ```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) ```  **Why SPAs feel so much better:** - Only the parts that actually changed get updated (smart, right?) - No more jarring interruptions - your users stay in their flow - Less data traveling over the wire means faster loading - Everything feels snappy and responsive, like the apps on your phone ### The Evolution to Modern Fetch API Modern browsers provide the [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), which replaces the older [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Like the difference between operating a telegraph and using email, Fetch API uses promises for cleaner asynchronous code and handles JSON naturally. | Feature | XMLHttpRequest | Fetch API | |---------|----------------|----------| | **Syntax** | Complex callback-based | Clean promise-based | | **JSON Handling** | Manual parsing required | Built-in `.json()` method | | **Error Handling** | Limited error information | Comprehensive error details | | **Modern Support** | Legacy compatibility | ES6+ promises and async/await | > 💡 **Browser Compatibility**: Good news - the Fetch API works in all modern browsers! If you're curious about specific versions, [caniuse.com](https://caniuse.com/fetch) has the complete compatibility story. > **The bottom line:** - Works great in Chrome, Firefox, Safari, and Edge (basically everywhere your users are) - Only Internet Explorer needs extra help (and honestly, it's time to let IE go) - Sets you up perfectly for the elegant async/await patterns we'll use later ### Implementing User Login and Data Retrieval Now let's implement the login system that transforms your banking app from a static display into a functional application. Like the authentication protocols used in secure military facilities, we'll verify user credentials and then provide access to their specific data. We'll build this incrementally, starting with basic authentication and then adding the data-fetching capabilities. #### Step 1: Create the Login Function Foundation Open your `app.js` file and add a new `login` function. This will handle the user authentication process: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **Let's break this down:** - That `async` keyword? It's telling JavaScript "hey, this function might need to wait for things" - We're grabbing our form from the page (nothing fancy, just finding it by its ID) - Then we're pulling out whatever the user typed as their username - Here's a neat trick: you can access any form input by its `name` attribute - no need for extra getElementById calls! > 💡 **Form Access Pattern**: Every form control can be accessed by its name (set in the HTML using the `name` attribute) as a property of the form element. This provides a clean, readable way to get form data. #### Step 2: Create the Account Data Fetching Function Next, we'll create a dedicated function to retrieve account data from the server. This follows the same pattern as your registration function but focuses on data retrieval: ```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' }; } } ``` **Here's what this code accomplishes:** - **Uses** the modern `fetch` API to request data asynchronously - **Constructs** a GET request URL with the username parameter - **Applies** `encodeURIComponent()` to safely handle special characters in URLs - **Converts** the response to JSON format for easy data manipulation - **Handles** errors gracefully by returning an error object instead of crashing > ⚠️ **Security Note**: The `encodeURIComponent()` function handles special characters in URLs. Like the encoding systems used in naval communications, it ensures your message arrives exactly as intended, preventing characters like "#" or "&" from being misinterpreted. > **Why this matters:** - Prevents special characters from breaking URLs - Protects against URL manipulation attacks - Ensures your server receives the intended data - Follows secure coding practices #### Understanding HTTP GET Requests Here's something that might surprise you: when you use `fetch` without any extra options, it automatically creates a [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET) request. This is perfect for what we're doing - asking the server "hey, can I see this user's account data?" Think of GET requests like politely asking to borrow a book from the library - you're requesting to see something that already exists. POST requests (which we used for registration) are more like submitting a new book to be added to the collection. | GET Request | POST Request | |-------------|-------------| | **Purpose** | Retrieve existing data | Send new data to server | | **Parameters** | In URL path/query string | In request body | | **Caching** | Can be cached by browsers | Not typically cached | | **Security** | Visible in URL/logs | Hidden in request body | #### Step 3: Bringing It All Together Now for the satisfying part - let's connect your account fetching function to the login process. This is where everything clicks into place: ```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'); } ``` This function follows a clear sequence: - Extract the username from the form input - Request the user's account data from the server - Handle any errors that occur during the process - Store the account data and navigate to the dashboard upon success > 🎯 **Async/Await Pattern**: Since `getAccount` is an asynchronous function, we use the `await` keyword to pause execution until the server responds. This prevents the code from continuing with undefined data. #### Step 4: Creating a Home for Your Data Your app needs somewhere to remember the account information once it's loaded. Think of this like your app's short-term memory - a place to keep the current user's data handy. Add this line at the top of your `app.js` file: ```javascript // This holds the current user's account data let account = null; ``` **Why we need this:** - Keeps the account data accessible from anywhere in your app - Starting with `null` means "no one's logged in yet" - Gets updated when someone successfully logs in or registers - Acts like a single source of truth - no confusion about who's logged in #### Step 5: Wire Up Your Form Now let's connect your shiny new login function to your HTML form. Update your form tag like this: ```html
``` **What this little change does:** - Stops the form from doing its default "reload the whole page" behavior - Calls your custom JavaScript function instead - Keeps everything smooth and single-page-app-like - Gives you complete control over what happens when users hit "Login" #### Step 6: Enhance Your Registration Function For consistency, update your `register` function to also store account data and navigate to the dashboard: ```javascript // Add these lines at the end of your register function account = result; navigate('/dashboard'); ``` **This enhancement provides:** - **Seamless** transition from registration to dashboard - **Consistent** user experience between login and registration flows - **Immediate** access to account data after successful registration #### Testing Your Implementation ```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] ``` **Time to take it for a spin:** 1. Create a new account to make sure everything's working 2. Try logging in with those same credentials 3. Peek at your browser's console (F12) if anything seems off 4. Make sure you land on the dashboard after a successful login If something's not working, don't panic! Most issues are simple fixes like typos or forgetting to start the API server. #### A Quick Word About Cross-Origin Magic You might be wondering: "How is my web app talking to this API server when they're running on different ports?" Great question! This touches on something every web developer bumps into eventually. > 🔒 **Cross-Origin Security**: Browsers enforce a "same-origin policy" to prevent unauthorized communication between different domains. Like the checkpoint system at the Pentagon, they verify that communication is authorized before allowing data transfer. > **In our setup:** - Your web app runs on `localhost:3000` (development server) - Your API server runs on `localhost:5000` (backend server) - The API server includes [CORS headers](https://developer.mozilla.org/docs/Web/HTTP/CORS) that explicitly authorize communication from your web app This configuration mirrors real-world development where frontend and backend applications typically run on separate servers. > 📚 **Learn More**: Dive deeper into APIs and data fetching with this comprehensive [Microsoft Learn module on APIs](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## Bringing Your Data to Life in HTML Now we'll make the fetched data visible to users through DOM manipulation. Like the process of developing photographs in a darkroom, we're taking invisible data and rendering it into something users can see and interact with. DOM manipulation is the technique that transforms static web pages into dynamic applications that update their content based on user interactions and server responses. ### Choosing the Right Tool for the Job When it comes to updating your HTML with JavaScript, you've got several options. Think of these like different tools in a toolbox - each one perfect for specific jobs: | Method | What it's great for | When to use it | Safety level | |--------|---------------------|----------------|--------------| | `textContent` | Displaying user data safely | Any time you're showing text | ✅ Rock solid | | `createElement()` + `append()` | Building complex layouts | Creating new sections/lists | ✅ Bulletproof | | `innerHTML` | Setting HTML content | ⚠️ Try to avoid this one | ❌ Risky business | #### The Safe Way to Show Text: textContent The [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent) property is your best friend when displaying user data. It's like having a bouncer for your webpage - nothing harmful gets through: ```javascript // The safe, reliable way to update text const balanceElement = document.getElementById('balance'); balanceElement.textContent = account.balance; ``` **Benefits of textContent:** - Treats everything as plain text (prevents script execution) - Automatically clears existing content - Efficient for simple text updates - Provides built-in security against malicious content #### Creating Dynamic HTML Elements For more complex content, combine [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) with the [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append) method: ```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); ``` **Understanding this approach:** - **Creates** new DOM elements programmatically - **Maintains** full control over element attributes and content - **Allows** for complex, nested element structures - **Preserves** security by separating structure from content > ⚠️ **Security Consideration**: While [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) appears in many tutorials, it can execute embedded scripts. Like the security protocols at CERN that prevent unauthorized code execution, using `textContent` and `createElement` provides safer alternatives. > **Risks of innerHTML:** - Executes any `