# Construindo um App Bancário Parte 3: Métodos de Busca e Uso de Dados Pense no computador da Enterprise em Star Trek - quando o Capitão Picard pede o status da nave, as informações aparecem instantaneamente sem que toda a interface seja interrompida e reconstruída. Esse fluxo contínuo de informações é exatamente o que estamos construindo aqui com a busca dinâmica de dados. Atualmente, seu app bancário é como um jornal impresso - informativo, mas estático. Vamos transformá-lo em algo mais parecido com o controle de missão da NASA, onde os dados fluem continuamente e são atualizados em tempo real sem interromper o fluxo de trabalho do usuário. Você aprenderá como se comunicar com servidores de forma assíncrona, lidar com dados que chegam em momentos diferentes e transformar informações brutas em algo significativo para seus usuários. Essa é a diferença entre um demo e um software pronto para produção. ## Quiz Pré-Aula [Quiz pré-aula](https://ff-quizzes.netlify.app/web/quiz/45) ### Pré-requisitos Antes de mergulhar na busca de dados, certifique-se de ter os seguintes componentes prontos: - **Aula Anterior**: Complete o [Formulário de Login e Registro](../2-forms/README.md) - vamos construir com base nesse fundamento - **Servidor Local**: Instale o [Node.js](https://nodejs.org) e [execute a API do servidor](../api/README.md) para fornecer dados da conta - **Conexão com a API**: Teste sua conexão com o servidor com este comando: ```bash curl http://localhost:5000/api # Expected response: "Bank API v1.0.0" ``` Este teste rápido garante que todos os componentes estão se comunicando corretamente: - Verifica se o Node.js está funcionando corretamente no seu sistema - Confirma que o servidor da API está ativo e respondendo - Valida que seu app pode alcançar o servidor (como verificar o contato de rádio antes de uma missão) --- ## Entendendo a Busca de Dados em Aplicativos Web Modernos A forma como os aplicativos web lidam com dados evoluiu dramaticamente nas últimas duas décadas. Entender essa evolução ajudará você a apreciar por que técnicas modernas como AJAX e a API Fetch são tão poderosas e por que se tornaram ferramentas essenciais para desenvolvedores web. Vamos explorar como os sites tradicionais funcionavam em comparação com os aplicativos dinâmicos e responsivos que construímos hoje. ### Aplicativos Tradicionais de Múltiplas Páginas (MPA) Nos primórdios da web, cada clique era como mudar de canal em uma televisão antiga - a tela ficava em branco e depois sintonizava lentamente o novo conteúdo. Essa era a realidade dos primeiros aplicativos web, onde cada interação significava reconstruir completamente a página inteira do zero. ```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) ``` ![Fluxo de atualização em um aplicativo de múltiplas páginas](../../../../translated_images/mpa.7f7375a1a2d4aa779d3f928a2aaaf9ad76bcdeb05cfce2dc27ab126024050f51.br.png) **Por que essa abordagem parecia desajeitada:** - Cada clique significava reconstruir a página inteira do zero - Os usuários eram interrompidos no meio do pensamento por aqueles flashes irritantes de página - Sua conexão com a internet trabalhava dobrado baixando o mesmo cabeçalho e rodapé repetidamente - Os aplicativos pareciam mais como navegar por um arquivo do que usar um software ### Aplicativos Modernos de Página Única (SPA) O AJAX (JavaScript e XML Assíncrono) mudou completamente esse paradigma. Como o design modular da Estação Espacial Internacional, onde os astronautas podem substituir componentes individuais sem reconstruir toda a estrutura, o AJAX nos permite atualizar partes específicas de uma página da web sem recarregar tudo. Apesar do nome mencionar XML, hoje usamos principalmente JSON, mas o princípio central permanece: atualizar apenas o que precisa mudar. ```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) ``` ![Fluxo de atualização em um aplicativo de página única](../../../../translated_images/spa.268ec73b41f992c2a21ef9294235c6ae597b3c37e2c03f0494c2d8857325cc57.br.png) **Por que os SPAs são muito melhores:** - Apenas as partes que realmente mudaram são atualizadas (inteligente, não é?) - Sem mais interrupções bruscas - seus usuários permanecem no fluxo - Menos dados trafegando pela rede significa carregamento mais rápido - Tudo parece ágil e responsivo, como os aplicativos no seu celular ### A Evolução para a API Fetch Moderna Os navegadores modernos fornecem a [API `Fetch`](https://developer.mozilla.org/docs/Web/API/Fetch_API), que substitui o antigo [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Como a diferença entre operar um telégrafo e usar e-mail, a API Fetch usa promessas para um código assíncrono mais limpo e lida naturalmente com JSON. | Recurso | XMLHttpRequest | API Fetch | |---------|----------------|-----------| | **Sintaxe** | Baseada em callbacks complexos | Baseada em promessas limpas | | **Manipulação de JSON** | Requer análise manual | Método embutido `.json()` | | **Tratamento de Erros** | Informações limitadas sobre erros | Detalhes abrangentes sobre erros | | **Suporte Moderno** | Compatibilidade com versões antigas | Promessas ES6+ e async/await | > 💡 **Compatibilidade com Navegadores**: Boas notícias - a API Fetch funciona em todos os navegadores modernos! Se você estiver curioso sobre versões específicas, [caniuse.com](https://caniuse.com/fetch) tem a história completa de compatibilidade. > **O resumo:** - Funciona muito bem no Chrome, Firefox, Safari e Edge (basicamente em todos os lugares onde seus usuários estão) - Apenas o Internet Explorer precisa de ajuda extra (e, honestamente, já é hora de deixar o IE para trás) - Prepara você perfeitamente para os padrões elegantes de async/await que usaremos mais tarde ### Implementando Login de Usuário e Recuperação de Dados Agora vamos implementar o sistema de login que transforma seu app bancário de uma exibição estática em um aplicativo funcional. Como os protocolos de autenticação usados em instalações militares seguras, vamos verificar as credenciais do usuário e, em seguida, fornecer acesso aos seus dados específicos. Vamos construir isso de forma incremental, começando com a autenticação básica e depois adicionando as capacidades de busca de dados. #### Passo 1: Criar a Base da Função de Login Abra seu arquivo `app.js` e adicione uma nova função `login`. Ela será responsável pelo processo de autenticação do usuário: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **Vamos detalhar isso:** - Essa palavra-chave `async`? Está dizendo ao JavaScript "ei, essa função pode precisar esperar por algumas coisas" - Estamos pegando nosso formulário da página (nada sofisticado, apenas encontrando pelo seu ID) - Depois, estamos extraindo o que o usuário digitou como nome de usuário - Aqui vai uma dica legal: você pode acessar qualquer entrada de formulário pelo atributo `name` - sem necessidade de chamadas extras de getElementById! > 💡 **Padrão de Acesso ao Formulário**: Cada controle de formulário pode ser acessado pelo seu nome (definido no HTML usando o atributo `name`) como uma propriedade do elemento do formulário. Isso fornece uma maneira limpa e legível de obter dados do formulário. #### Passo 2: Criar a Função de Busca de Dados da Conta Em seguida, criaremos uma função dedicada para recuperar os dados da conta do servidor. Isso segue o mesmo padrão da função de registro, mas foca na recuperação de dados: ```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' }; } } ``` **O que esse código realiza:** - **Usa** a moderna API `fetch` para solicitar dados de forma assíncrona - **Constrói** uma URL de solicitação GET com o parâmetro de nome de usuário - **Aplica** `encodeURIComponent()` para lidar com caracteres especiais em URLs de forma segura - **Converte** a resposta para o formato JSON para fácil manipulação de dados - **Lida** com erros de forma elegante, retornando um objeto de erro em vez de travar > ⚠️ **Nota de Segurança**: A função `encodeURIComponent()` lida com caracteres especiais em URLs. Como os sistemas de codificação usados em comunicações navais, ela garante que sua mensagem chegue exatamente como pretendido, evitando que caracteres como "#" ou "&" sejam interpretados incorretamente. > **Por que isso importa:** - Evita que caracteres especiais quebrem URLs - Protege contra ataques de manipulação de URL - Garante que seu servidor receba os dados pretendidos - Segue práticas seguras de codificação #### Entendendo as Solicitações HTTP GET Aqui está algo que pode surpreendê-lo: quando você usa `fetch` sem opções extras, ele automaticamente cria uma solicitação [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET). Isso é perfeito para o que estamos fazendo - pedindo ao servidor "ei, posso ver os dados da conta deste usuário?" Pense nas solicitações GET como pedir educadamente para pegar um livro emprestado na biblioteca - você está solicitando ver algo que já existe. Solicitações POST (que usamos para registro) são mais como enviar um novo livro para ser adicionado à coleção. | Solicitação GET | Solicitação POST | |-----------------|------------------| | **Propósito** | Recuperar dados existentes | Enviar novos dados ao servidor | | **Parâmetros** | No caminho/consulta da URL | No corpo da solicitação | | **Cache** | Pode ser armazenado em cache pelos navegadores | Normalmente não armazenado em cache | | **Segurança** | Visível na URL/logs | Oculto no corpo da solicitação | #### Passo 3: Juntando Tudo Agora vem a parte satisfatória - vamos conectar sua função de busca de conta ao processo de login. É aqui que tudo se encaixa: ```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'); } ``` Esta função segue uma sequência clara: - Extrai o nome de usuário da entrada do formulário - Solicita os dados da conta do usuário ao servidor - Lida com quaisquer erros que ocorram durante o processo - Armazena os dados da conta e navega para o painel de controle em caso de sucesso > 🎯 **Padrão Async/Await**: Como `getAccount` é uma função assíncrona, usamos a palavra-chave `await` para pausar a execução até que o servidor responda. Isso evita que o código continue com dados indefinidos. #### Passo 4: Criando um Local para Seus Dados Seu app precisa de um lugar para armazenar as informações da conta assim que forem carregadas. Pense nisso como a memória de curto prazo do seu app - um lugar para manter os dados do usuário atual à mão. Adicione esta linha no topo do seu arquivo `app.js`: ```javascript // This holds the current user's account data let account = null; ``` **Por que precisamos disso:** - Mantém os dados da conta acessíveis de qualquer lugar no seu app - Começar com `null` significa "ninguém está logado ainda" - É atualizado quando alguém faz login ou registro com sucesso - Atua como uma única fonte de verdade - sem confusão sobre quem está logado #### Passo 5: Conecte Seu Formulário Agora vamos conectar sua nova função de login ao formulário HTML. Atualize a tag do formulário assim: ```html
``` **O que essa pequena mudança faz:** - Impede que o formulário execute seu comportamento padrão de "recarregar toda a página" - Chama sua função personalizada em JavaScript - Mantém tudo suave e com aparência de aplicativo de página única - Dá a você controle total sobre o que acontece quando os usuários clicam em "Login" #### Passo 6: Melhore Sua Função de Registro Para consistência, atualize sua função `register` para também armazenar os dados da conta e navegar para o painel de controle: ```javascript // Add these lines at the end of your register function account = result; navigate('/dashboard'); ``` **Essa melhoria oferece:** - **Transição suave** do registro para o painel de controle - **Experiência consistente** para o usuário entre os fluxos de login e registro - **Acesso imediato** aos dados da conta após o registro bem-sucedido #### Testando Sua Implementação ```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] ``` **Hora de testar:** 1. Crie uma nova conta para garantir que tudo está funcionando 2. Tente fazer login com essas mesmas credenciais 3. Dê uma olhada no console do seu navegador (F12) se algo parecer errado 4. Certifique-se de que você chega ao painel de controle após um login bem-sucedido Se algo não estiver funcionando, não entre em pânico! A maioria dos problemas são correções simples, como erros de digitação ou esquecer de iniciar o servidor da API. #### Uma Palavra Rápida Sobre Magia de Origem Cruzada Você pode estar se perguntando: "Como meu app web está conversando com este servidor de API quando eles estão rodando em portas diferentes?" Ótima pergunta! Isso toca em algo que todo desenvolvedor web encontra eventualmente. > 🔒 **Segurança de Origem Cruzada**: Os navegadores aplicam uma "política de mesma origem" para evitar comunicação não autorizada entre diferentes domínios. Como o sistema de controle de acesso no Pentágono, eles verificam se a comunicação é autorizada antes de permitir a transferência de dados. > **Na nossa configuração:** - Seu app web roda em `localhost:3000` (servidor de desenvolvimento) - Seu servidor de API roda em `localhost:5000` (servidor backend) - O servidor de API inclui cabeçalhos [CORS](https://developer.mozilla.org/docs/Web/HTTP/CORS) que autorizam explicitamente a comunicação do seu app web Essa configuração reflete o desenvolvimento do mundo real, onde aplicativos frontend e backend geralmente rodam em servidores separados. > 📚 **Saiba Mais**: Aprofunde-se em APIs e busca de dados com este módulo abrangente do [Microsoft Learn sobre APIs](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## Dando Vida aos Seus Dados no HTML Agora vamos tornar os dados buscados visíveis para os usuários por meio da manipulação do DOM. Como o processo de revelar fotografias em um laboratório, estamos transformando dados invisíveis em algo que os usuários podem ver e interagir. A manipulação do DOM é a técnica que transforma páginas web estáticas em aplicativos dinâmicos que atualizam seu conteúdo com base nas interações do usuário e nas respostas do servidor. ### Escolhendo a Ferramenta Certa para o Trabalho Quando se trata de atualizar seu HTML com JavaScript, você tem várias opções. Pense nelas como diferentes ferramentas em uma caixa de ferramentas - cada uma perfeita para trabalhos específicos: | Método | Para que é ótimo | Quando usar | Nível de segurança | |--------|------------------|-------------|--------------------| | `textContent` | Exibir dados do usuário com segurança | Sempre que estiver mostrando texto | ✅ Muito seguro | | `createElement()` + `append()` | Construir layouts complexos | Criar novas seções/listas | ✅ Muito seguro | | `innerHTML` | Definir conteúdo HTML | ⚠️ Tente evitar este | ❌ Arriscado | #### A Maneira Segura de Mostrar Texto: textContent A propriedade [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent) é sua melhor amiga ao exibir dados do usuário. É como ter um segurança para sua página web - nada prejudicial passa: ```javascript // The safe, reliable way to update text const balanceElement = document.getElementById('balance'); balanceElement.textContent = account.balance; ``` **Benefícios do textContent:** - Trata tudo como texto simples (impede execução de scripts) - Limpa automaticamente o conteúdo existente - Eficiente para atualizações simples de texto - Oferece segurança integrada contra conteúdo malicioso #### Criando Elementos HTML Dinâmicos Para conteúdos mais complexos, combine [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) com o método [`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); ``` **Entendendo essa abordagem:** - **Cria** novos elementos DOM programaticamente - **Mantém** controle total sobre atributos e conteúdo dos elementos - **Permite** estruturas complexas e aninhadas de elementos - **Preserva** a segurança ao separar estrutura de conteúdo > ⚠️ **Consideração de Segurança**: Embora [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) apareça em muitos tutoriais, ele pode executar scripts embutidos. Assim como os protocolos de segurança no CERN que impedem a execução de códigos não autorizados, usar `textContent` e `createElement` oferece alternativas mais seguras. > **Riscos do innerHTML:** - Executa qualquer tag `