# Construir uma App Bancária Parte 3: Métodos de Obtenção e Utilização de Dados Pense no computador da Enterprise em Star Trek – quando o Capitão Picard pede o estado da nave, a informação aparece instantaneamente sem que toda a interface desligue e se reconstrua. Esse fluxo contínuo de informações é exatamente o que estamos a construir aqui com a obtenção dinâmica de dados. Neste momento, a sua app bancária é como um jornal impresso – informativa mas estática. Vamos transformá-la em algo mais como o controlo de missão da NASA, onde os dados fluem continuamente e são atualizados em tempo real sem interromper o fluxo de trabalho do utilizador. Vai aprender a comunicar com servidores de forma assíncrona, lidar com dados que chegam em momentos diferentes e transformar informação bruta em algo significativo para os seus utilizadores. Esta é a diferença entre uma demo e um software pronto para produção. ## ⚡ O Que Pode Fazer Nos Próximos 5 Minutos **Caminho Rápido para Desenvolvedores Ocupados** ```mermaid flowchart LR A[⚡ 5 minutos] --> B[Configurar servidor API] B --> C[Testar fetch com curl] C --> D[Criar função de login] D --> E[Ver dados em ação] ``` - **Minutos 1-2**: Inicie o seu servidor API (`cd api && npm start`) e teste a ligação - **Minuto 3**: Crie uma função básica `getAccount()` usando fetch - **Minuto 4**: Ligue o formulário de login com `action="javascript:login()"` - **Minuto 5**: Teste o login e veja os dados da conta aparecerem na consola **Comandos de Teste Rápido**: ```bash # Verificar se a API está a funcionar curl http://localhost:5000/api # Testar a obtenção de dados da conta curl http://localhost:5000/api/accounts/test ``` **Porquê Isto é Importante**: Em 5 minutos, verá a magia da obtenção de dados assíncrona que alimenta todas as aplicações web modernas. Esta é a base que torna as apps responsivas e dinâmicas. ## 🗺️ O Seu Percurso de Aprendizagem em Aplicações Web Baseadas em Dados ```mermaid journey title De Páginas Estáticas a Aplicações Dinâmicas section Compreender a Evolução Recarregamentos tradicionais de página: 3: You Descobrir benefícios do AJAX/SPA: 5: You Dominar padrões Fetch API: 7: You section Construir Autenticação Criar funções de login: 4: You Lidar com operações assíncronas: 6: You Gerir sessões de utilizador: 8: You section Atualizações Dinâmicas da IU Aprender manipulação do DOM: 5: You Construir exibições de transações: 7: You Criar painéis responsivos: 9: You section Padrões Profissionais Renderização baseada em templates: 6: You Estratégias de tratamento de erros: 7: You Otimização de desempenho: 8: You ``` **Destino do Seu Percurso**: No final desta lição, vai entender como as aplicações web modernas obtêm, processam e exibem dados dinamicamente, criando as experiências de utilizador fluídas que esperamos de aplicações profissionais. ## Questionário Pré-Aula [Questionário pré-aula](https://ff-quizzes.netlify.app/web/quiz/45) ### Pré-requisitos Antes de mergulhar na obtenção de dados, tenha estes componentes prontos: - **Lição Anterior**: Complete o [Formulário de Login e Registo](../2-forms/README.md) – vamos construir sobre esta base - **Servidor Local**: Instale [Node.js](https://nodejs.org) e [execute o servidor API](../api/README.md) para fornecer dados da conta - **Ligação à API**: Teste a ligação ao seu servidor com este comando: ```bash curl http://localhost:5000/api # Resposta esperada: "API do Banco v1.0.0" ``` Este teste rápido assegura que todos os componentes estão a comunicar corretamente: - Verifica que o Node.js está a funcionar corretamente no seu sistema - Confirma que o seu servidor API está ativo e a responder - Valida que a sua app pode alcançar o servidor (como verificar contacto rádio antes de uma missão) ## 🧠 Visão Geral do Ecossistema de Gestão de Dados ```mermaid mindmap root((Gestão de Dados)) Authentication Flow Processo de Login Validação de Formulário Verificação de Credenciais Gestão de Sessão Estado do Utilizador Objeto Global da Conta Guardas de Navegação Gestão de Erros API Communication Padrões de Requisição Requisições GET Requisições POST Respostas de Erro Formatos de Dados Processamento JSON Codificação URL Análise de Resposta Dynamic UI Updates Manipulação do DOM Atualizações Seguras de Texto Criação de Elementos Clonagem de Templates Experiência do Utilizador Atualizações em Tempo Real Mensagens de Erro Estados de Carregamento Security Considerations Prevenção XSS Uso de textContent Sanitização de Entrada Criação Segura de HTML Gestão de CORS Requisições Cross-Origin Configuração de Cabeçalhos Configuração de Desenvolvimento ``` **Princípio Fundamental**: Aplicações web modernas são sistemas de orquestração de dados – coordenam interfaces de utilizador, APIs de servidor e modelos de segurança do navegador para criar experiências fluidas e responsivas. --- ## Compreender a Obtenção de Dados em Aplicações Web Modernas A forma como as aplicações web lidam com dados evoluiu dramaticamente nas últimas duas décadas. Compreender esta evolução ajudará a apreciar porque técnicas modernas como AJAX e a API Fetch são tão poderosas e por que se tornaram ferramentas essenciais para os desenvolvedores web. Vamos explorar como os sites tradicionais funcionavam comparados com as aplicações dinâmicas e responsivas que construímos hoje. ### Aplicações Tradicionais de Múltiplas Páginas (MPA) Nos primórdios da web, cada clique era como mudar de canal numa televisão antiga – o ecrã ficava em branco e depois sintonizava lentamente o novo conteúdo. Esta era a realidade das primeiras aplicações web, onde cada interação significava reconstruir a página inteira do zero. ```mermaid sequenceDiagram participant User participant Browser participant Server User->>Browser: Clica no link ou submete formulário Browser->>Server: Requisita nova página HTML Note over Browser: A página fica em branco Server->>Browser: Devolve página HTML completa Browser->>User: Mostra nova página (flash/recarregamento) ```  **Porque este método parecia pesado:** - Cada clique implicava reconstruir a página inteira do zero - Os utilizadores eram interrompidos no meio do pensamento por aqueles flashes irritantes de página - A ligação à internet trabalhava em excesso a descarregar o mesmo cabeçalho e rodapé repetidamente - As apps pareciam mais um arquivo de gavetas para clicar do que software a usar ### Aplicações Modernas de Página Única (SPA) AJAX (JavaScript assíncrono e XML) mudou este paradigma completamente. Como o design modular da Estação Espacial Internacional, onde os astronautas podem substituir componentes individuais sem reconstruir toda a estrutura, AJAX permite-nos atualizar partes específicas de uma página sem recarregar tudo. Apesar do nome mencionar XML, hoje em dia usamos principalmente JSON, mas o princípio central mantém-se: atualizar apenas o que precisa de mudar. ```mermaid sequenceDiagram participant User participant Browser participant JavaScript participant Server User->>Browser: Interage com a página Browser->>JavaScript: Activa o manipulador de eventos JavaScript->>Server: Busca apenas os dados necessários Server->>JavaScript: Devolve dados JSON JavaScript->>Browser: Actualiza elementos específicos da página Browser->>User: Mostra conteúdo actualizado (sem recarregar) ```  **Porque é que as SPAs parecem muito melhores:** - Só as partes que realmente mudaram são atualizadas (inteligente, certo?) - Sem interrupções bruscas – o utilizador mantém o seu fluxo - Menos dados a viajar, significado carregamentos mais rápidos - Tudo parece rápido e responsivo, como as apps no seu telemóvel ### A Evolução para a API Fetch Moderna Os navegadores modernos fornecem a [`Fetch` API](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 email, a API Fetch usa promessas para um código assíncrono mais limpo e manipula JSON naturalmente. | Característica | XMLHttpRequest | Fetch API | |---------|----------------|----------| | **Sintaxe** | Complexa baseada em callbacks | Limpa baseada em promessas | | **Manipulação de JSON** | Análise manual necessária | Método `.json()` incorporado | | **Gestão de Erros** | Informações limitadas | Detalhes completos de erros | | **Suporte Moderno** | Compatibilidade legado | Promessas ES6+ e async/await | > 💡 **Compatibilidade dos Navegadores**: Boas notícias – a Fetch API funciona em todos os navegadores modernos! Se tiver curiosidade sobre versões específicas, [caniuse.com](https://caniuse.com/fetch) tem a história completa de compatibilidade. > **Conclusão:** - Funciona bem no Chrome, Firefox, Safari e Edge (basicamente em todo o lado onde os utilizadores estão) - Apenas o Internet Explorer precisa de ajuda extra (e honestamente, está na hora de deixar o IE para trás) - Prepara-o perfeitamente para os padrões elegantes async/await que usaremos mais tarde ### Implementar Login de Utilizador e Recuperação de Dados Agora vamos implementar o sistema de login que transforma a sua app bancária de uma exibição estática numa aplicação funcional. Como os protocolos de autenticação usados em instalações militares seguras, vamos verificar as credenciais do utilizador e depois fornecer acesso aos seus dados específicos. Vamos construir isso incrementalmente, começando com a autenticação básica e depois adicionando a capacidade de obter dados. #### Passo 1: Criar a Fundação da Função de Login Abra o seu ficheiro `app.js` e adicione uma nova função `login`. Esta vai tratar do processo de autenticação: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **Vamos detalhar este código:** - A palavra-chave `async`? Está a dizer ao JavaScript "ei, esta função pode precisar de esperar por coisas" - Estamos a obter o nosso formulário da página (nada de especial, apenas a encontrar pelo ID) - Depois extraímos o que o utilizador digitou como nome de utilizador - Aqui está um truque: pode aceder a qualquer input do formulário pelo seu atributo `name` – não precisa de chamadas extras getElementById! > 💡 **Padrão de Acesso a Formulários**: Cada controlo de formulário pode ser acedido pelo seu nome (definido em HTML usando o atributo `name`) como uma propriedade do elemento de formulário. Isto fornece uma forma limpa e legível de obter os dados do formulário. #### Passo 2: Criar a Função de Obtenção de Dados da Conta A seguir, vamos criar uma função dedicada para obter os dados da conta do servidor. Isto segue o mesmo padrão da sua função de registo mas foca-se na obtençã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' }; } } ``` **Isto é o que este código faz:** - **Usa** a moderna API `fetch` para solicitar dados de forma assíncrona - **Constrói** uma URL para uma requisição GET com o parâmetro do nome de utilizador - **Aplica** `encodeURIComponent()` para tratar caracteres especiais nas URLs em segurança - **Converte** a resposta para o formato JSON para facilitar a manipulação dos dados - **Lida** com erros de forma elegante, retornando um objeto de erro em vez de falhar > ⚠️ **Nota de Segurança**: A função `encodeURIComponent()` trata caracteres especiais em URLs. Como os sistemas de codificação usados em comunicações navais, garante que a sua mensagem chega exatamente como pretendida, prevenindo que caracteres como "#" ou "&" sejam mal interpretados. > **Porque isto é importante:** - Prevém que caracteres especiais partam URLs - Protege contra ataques de manipulação de URL - Garante que o seu servidor recebe os dados pretendidos - Segue práticas seguras de programação #### Compreender Requisições HTTP GET Aqui está algo que pode surpreendê-lo: quando usa `fetch` sem opções adicionais, ele cria automaticamente uma requisição [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET). Isto é perfeito para o que estamos a fazer – pedir ao servidor "ei, posso ver os dados da conta deste utilizador?" Pense nas requisições GET como pedir educadamente emprestado um livro na biblioteca – está a solicitar ver algo que já existe. Requisições POST (que usamos para registo) são mais como submeter um novo livro para adicionar à coleção. | Requisição GET | Requisição POST | |-------------|-------------| | **Objetivo** | Recuperar dados existentes | Enviar dados novos ao servidor | | **Parâmetros** | Na URL / query string | No corpo da requisição | | **Cache** | Pode ser guardada em cache pelos navegadores | Normalmente não é guardada em cache | | **Segurança** | Visível na URL/logs | Oculto no corpo da requisição | ```mermaid sequenceDiagram participant B as Browser participant S as Server Note over B,S: Pedido GET (Recuperação de Dados) B->>S: GET /api/accounts/test S-->>B: 200 OK + Dados da Conta Note over B,S: Pedido POST (Submissão de Dados) B->>S: POST /api/accounts + Novos Dados da Conta S-->>B: 201 Created + Confirmação Note over B,S: Tratamento de Erros B->>S: GET /api/accounts/nonexistent S-->>B: 404 Not Found + Mensagem de Erro ``` #### Passo 3: Juntar Tudo Agora a parte satisfatória – vamos ligar a função de obtenção da 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 do utilizador do input do formulário - Solicita os dados da conta do utilizador ao servidor - Trata quaisquer erros que ocorram durante o processo - Armazena os dados da conta e navega para o dashboard 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é o servidor responder. Isto previne que o código continue com dados indefinidos. #### Passo 4: Criar um Local para os Seus Dados A sua app precisa de um local para guardar a informação da conta depois de carregada. Pense nisto como a memória de curto prazo da sua app – um lugar para manter os dados do utilizador atual à mão. Adicione esta linha no topo do seu ficheiro `app.js`: ```javascript // Isto contém os dados da conta do utilizador atual let account = null; ``` **Porque precisamos disto:** - Mantém os dados da conta acessíveis de qualquer parte da sua app - Começar com `null` significa "ninguém está logado ainda" - Atualiza-se quando alguém faz login ou regista com sucesso - Age como uma fonte única de verdade – nenhuma confusão sobre quem está logado #### Passo 5: Ligar o Seu Formulário Agora vamos ligar a sua nova função de login ao formulário HTML. Atualize a tag do seu formulário assim: ```html
``` **O que esta pequena alteração faz:** - Impede o formulário de fazer o seu comportamento padrão de "recarregar a página inteira" - Chama a sua função JavaScript personalizada em vez disso - Mantém tudo suave e como uma aplicação de página única - Dá-lhe controlo completo sobre o que acontece quando os utilizadores clicam em "Login" #### Passo 6: Melhorar a Sua Função de Registo Para manter a consistência, atualize a sua função `register` para também guardar os dados da conta e navegar para o dashboard: ```javascript // Adicione estas linhas no final da sua função de registo account = result; navigate('/dashboard'); ``` **Esta melhoria proporciona:** - **Transição fluida** do registo para o dashboard - **Experiência consistente** para o utilizador entre fluxos de login e registo - **Acesso imediato** aos dados da conta após registo bem-sucedido #### Testar a Sua Implementação ```mermaid flowchart TD A[Utilizador insere credenciais] --> B[Função de login chamada] B --> C[Obter dados da conta do servidor] C --> D{Dados recebidos com sucesso?} D -->|Sim| E[Guardar dados da conta globalmente] D -->|Não| F[Exibir mensagem de erro] E --> G[Navegar para o painel] F --> H[Utilizador permanece na página de login] ``` **Hora de experimentar:** 1. Crie uma nova conta para garantir que tudo funciona 2. Tente fazer login com essas mesmas credenciais 3. Espie a consola do seu navegador (F12) se algo parecer estranho 4. Certifique-se que chega ao dashboard após um login bem-sucedido Se algo não estiver a funcionar, não entre em pânico! A maioria dos problemas são correções simples como erros de digitação ou esquecer de arrancar o servidor API. #### Uma Palavra Rápida Sobre a Magia Cross-Origin Pode estar a perguntar-se: "Como é que a minha app web está a falar com este servidor API se estão a correr em portas diferentes?" Ótima pergunta! Isto toca num ponto que todos os desenvolvedores web acabam por encontrar. > 🔒 **Segurança Cross-Origin**: Os navegadores aplicam uma "política de mesma origem" para prevenir comunicações não autorizadas entre domínios diferentes. Como o sistema de controlo num posto de segurança, verificam que a comunicação é autorizada antes de permitir a transferência de dados. > **Na nossa configuração:** - A sua app web corre em `localhost:3000` (servidor de desenvolvimento) - O seu servidor API corre em `localhost:5000` (servidor backend) - O servidor API inclui [headers CORS](https://developer.mozilla.org/docs/Web/HTTP/CORS) que autorizam explicitamente a comunicação da sua app web Esta configuração espelha o ambiente real de desenvolvimento onde as aplicações frontend e backend tipicamente correm em servidores separados. > 📚 **Saiba Mais**: Aprofunde APIs e obtenção de dados com este módulo abrangente da [Microsoft Learn sobre APIs](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon). ## Dar Vida aos Seus Dados em HTML Agora vamos tornar os dados obtidos visíveis aos utilizadores através da manipulação do DOM. Tal como o processo de revelar fotografias num laboratório, estamos a pegar em dados invisíveis e a transformá-los em algo que os utilizadores podem ver e interagir. A manipulação do DOM é a técnica que transforma páginas web estáticas em aplicações dinâmicas que atualizam o seu conteúdo com base nas interações do utilizador e nas respostas do servidor. ### Escolher a Ferramenta Certa para o Trabalho Quando se trata de atualizar o seu HTML com JavaScript, tem várias opções. Pense nelas como diferentes ferramentas numa caixa de ferramentas – cada uma perfeita para trabalhos específicos: | Método | Em que é boa | Quando usar | Nível de segurança | |--------|--------------|-------------|--------------------| | `textContent` | Exibir dados do utilizador de forma segura | Sempre que mostrar texto | ✅ À prova de bala | | `createElement()` + `append()` | Construir layouts complexos | Criar secções/listas novas | ✅ À prova de bala | | `innerHTML` | Definir conteúdo HTML | ⚠️ Tente evitar este | ❌ Negócio arriscado | #### A Forma Segura de Mostrar Texto: textContent A propriedade [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent) é a sua melhor amiga quando mostra dados do utilizador. É como ter um segurança na sua página web – nada de prejudicial passa: ```javascript // A forma segura e fiável de atualizar texto const balanceElement = document.getElementById('balance'); balanceElement.textContent = account.balance; ``` **Benefícios do textContent:** - Trata tudo como texto simples (evita a execução de scripts) - Limpa automaticamente o conteúdo existente - Eficiente para atualizações simples de texto - Proporciona segurança incorporada contra conteúdos maliciosos #### Criar 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 // Maneira segura de criar novos elementos const transactionItem = document.createElement('div'); transactionItem.className = 'transaction-item'; transactionItem.textContent = `${transaction.date}: ${transaction.description}`; container.append(transactionItem); ``` **Compreender esta abordagem:** - **Cria** novos elementos DOM programaticamente - **Mantém** pleno controlo sobre os atributos e conteúdo dos elementos - **Permite** estruturas complexas e aninhadas de elementos - **Preserva** a segurança, separando estrutura do conteúdo > ⚠️ **Consideração de Segurança**: Embora [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) apareça em muitos tutoriais, pode executar scripts embutidos. Tal como os protocolos de segurança no CERN que impedem a execução não autorizada de código, usar `textContent` e `createElement` oferece alternativas mais seguras. > **Riscos do innerHTML:** - Executa quaisquer tags `