You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/br/5-browser-extension/2-forms-browsers-local-storage/README.md

20 KiB

Projeto de Extensão de Navegador Parte 2: Chamar uma API, usar Armazenamento Local

Quiz Pré-Aula

Quiz pré-aula

Introdução

Lembra daquela extensão de navegador que você começou a construir? No momento, você tem um formulário bonito, mas ele é essencialmente estático. Hoje vamos dar vida a ele conectando-o a dados reais e dando-lhe memória.

Pense nos computadores de controle da missão Apollo - eles não apenas exibiam informações fixas. Eles se comunicavam constantemente com a espaçonave, atualizavam com dados de telemetria e lembravam parâmetros críticos da missão. Esse é o tipo de comportamento dinâmico que estamos construindo hoje. Sua extensão irá acessar a internet, buscar dados ambientais reais e lembrar suas configurações para a próxima vez.

A integração com APIs pode parecer complexa, mas é basicamente ensinar seu código a se comunicar com outros serviços. Seja buscando dados meteorológicos, feeds de redes sociais ou informações sobre pegada de carbono, como faremos hoje, tudo se resume a estabelecer essas conexões digitais. Também exploraremos como os navegadores podem persistir informações - semelhante a como bibliotecas usavam catálogos de fichas para lembrar onde os livros estavam.

Ao final desta aula, você terá uma extensão de navegador que busca dados reais, armazena preferências do usuário e oferece uma experiência suave. Vamos começar!

Siga os segmentos numerados nos arquivos apropriados para saber onde colocar seu código.

Configurar os elementos para manipular na extensão

Antes que seu JavaScript possa manipular a interface, ele precisa de referências a elementos HTML específicos. Pense nisso como um telescópio que precisa ser apontado para estrelas específicas - antes de Galileu estudar as luas de Júpiter, ele teve que localizar e focar em Júpiter.

No seu arquivo index.js, criaremos variáveis const que capturam referências para cada elemento importante do formulário. Isso é semelhante a como os cientistas rotulam seus equipamentos - em vez de procurar por todo o laboratório cada vez, eles podem acessar diretamente o que precisam.

// form fields
const form = document.querySelector('.form-data');
const region = document.querySelector('.region-name');
const apiKey = document.querySelector('.api-key');

// results
const errors = document.querySelector('.errors');
const loading = document.querySelector('.loading');
const results = document.querySelector('.result-container');
const usage = document.querySelector('.carbon-usage');
const fossilfuel = document.querySelector('.fossil-fuel');
const myregion = document.querySelector('.my-region');
const clearBtn = document.querySelector('.clear-btn');

O que este código faz:

  • Captura elementos do formulário usando document.querySelector() com seletores de classe CSS
  • Cria referências para os campos de entrada do nome da região e da chave da API
  • Estabelece conexões com elementos de exibição de resultados para dados de uso de carbono
  • Configura acesso a elementos da interface do usuário, como indicadores de carregamento e mensagens de erro
  • Armazena cada referência de elemento em uma variável const para fácil reutilização ao longo do código

Adicionar ouvintes de eventos

Agora faremos sua extensão responder às ações do usuário. Ouvintes de eventos são a maneira do seu código monitorar interações do usuário. Pense neles como os operadores nas antigas centrais telefônicas - eles ouviam chamadas recebidas e conectavam os circuitos certos quando alguém queria fazer uma conexão.

form.addEventListener('submit', (e) => handleSubmit(e));
clearBtn.addEventListener('click', (e) => reset(e));
init();

Entendendo esses conceitos:

  • Anexa um ouvinte de envio ao formulário que é acionado quando os usuários pressionam Enter ou clicam em enviar
  • Conecta um ouvinte de clique ao botão de limpar para redefinir o formulário
  • Passa o objeto de evento (e) para funções manipuladoras para controle adicional
  • Chama a função init() imediatamente para configurar o estado inicial da sua extensão

Observe a sintaxe de função de seta abreviada usada aqui. Essa abordagem moderna do JavaScript é mais limpa do que as expressões de função tradicionais, mas ambas funcionam igualmente bem!

Construir as funções de inicialização e redefinição

Vamos criar a lógica de inicialização para sua extensão. A função init() é como o sistema de navegação de um navio verificando seus instrumentos - ela determina o estado atual e ajusta a interface de acordo. Ela verifica se alguém já usou sua extensão antes e carrega suas configurações anteriores.

A função reset() oferece aos usuários um novo começo - semelhante a como os cientistas reiniciam seus instrumentos entre experimentos para garantir dados limpos.

function init() {
	// Check if user has previously saved API credentials
	const storedApiKey = localStorage.getItem('apiKey');
	const storedRegion = localStorage.getItem('regionName');

	// Set extension icon to generic green (placeholder for future lesson)
	// TODO: Implement icon update in next lesson

	if (storedApiKey === null || storedRegion === null) {
		// First-time user: show the setup form
		form.style.display = 'block';
		results.style.display = 'none';
		loading.style.display = 'none';
		clearBtn.style.display = 'none';
		errors.textContent = '';
	} else {
		// Returning user: load their saved data automatically
		displayCarbonUsage(storedApiKey, storedRegion);
		results.style.display = 'none';
		form.style.display = 'none';
		clearBtn.style.display = 'block';
	}
}

function reset(e) {
	e.preventDefault();
	// Clear stored region to allow user to choose a new location
	localStorage.removeItem('regionName');
	// Restart the initialization process
	init();
}

Desmembrando o que acontece aqui:

  • Recupera a chave da API e a região armazenadas no armazenamento local do navegador
  • Verifica se é um usuário de primeira viagem (sem credenciais armazenadas) ou um usuário recorrente
  • Exibe o formulário de configuração para novos usuários e oculta outros elementos da interface
  • Carrega automaticamente os dados salvos para usuários recorrentes e exibe a opção de redefinição
  • Gerencia o estado da interface do usuário com base nos dados disponíveis

Conceitos-chave sobre Armazenamento Local:

  • Persiste dados entre sessões do navegador (diferente do armazenamento de sessão)
  • Armazena dados como pares chave-valor usando getItem() e setItem()
  • Retorna null quando não existem dados para uma chave específica
  • Oferece uma maneira simples de lembrar preferências e configurações do usuário

💡 Entendendo o Armazenamento do Navegador: LocalStorage é como dar à sua extensão uma memória persistente. Considere como a antiga Biblioteca de Alexandria armazenava pergaminhos - as informações permaneciam disponíveis mesmo quando os estudiosos saíam e voltavam.

Características principais:

  • Persiste dados mesmo após fechar o navegador
  • Sobrevive a reinicializações do computador e falhas do navegador
  • Oferece espaço de armazenamento substancial para preferências do usuário
  • Proporciona acesso instantâneo sem atrasos de rede

Nota Importante: Sua extensão de navegador tem seu próprio armazenamento local isolado, separado das páginas da web regulares. Isso proporciona segurança e previne conflitos com outros sites.

Você pode visualizar seus dados armazenados abrindo as Ferramentas de Desenvolvedor do navegador (F12), navegando até a aba Application e expandindo a seção Local Storage.

Painel de armazenamento local

⚠️ Consideração de Segurança: Em aplicações de produção, armazenar chaves de API no LocalStorage apresenta riscos de segurança, já que o JavaScript pode acessar esses dados. Para fins de aprendizado, essa abordagem funciona bem, mas aplicações reais devem usar armazenamento seguro no servidor para credenciais sensíveis.

Lidar com o envio do formulário

Agora vamos lidar com o que acontece quando alguém envia seu formulário. Por padrão, os navegadores recarregam a página ao enviar formulários, mas vamos interceptar esse comportamento para criar uma experiência mais suave.

Essa abordagem espelha como o controle da missão lida com comunicações de espaçonaves - em vez de reiniciar todo o sistema para cada transmissão, eles mantêm a operação contínua enquanto processam novas informações.

Crie uma função que capture o evento de envio do formulário e extraia as entradas do usuário:

function handleSubmit(e) {
	e.preventDefault();
	setUpUser(apiKey.value, region.value);
}

No código acima, nós:

  • Impede o comportamento padrão de envio do formulário que atualizaria a página
  • Extrai valores de entrada do usuário dos campos de chave da API e região
  • Passa os dados do formulário para a função setUpUser() para processamento
  • Mantém o comportamento de aplicação de página única evitando recarregamentos

Lembre-se de que os campos do formulário HTML incluem o atributo required, então o navegador valida automaticamente que os usuários forneçam tanto a chave da API quanto a região antes que esta função seja executada.

Configurar preferências do usuário

A função setUpUser é responsável por salvar as credenciais do usuário e iniciar a primeira chamada à API. Isso cria uma transição suave da configuração para a exibição de resultados.

function setUpUser(apiKey, regionName) {
	// Save user credentials for future sessions
	localStorage.setItem('apiKey', apiKey);
	localStorage.setItem('regionName', regionName);
	
	// Update UI to show loading state
	loading.style.display = 'block';
	errors.textContent = '';
	clearBtn.style.display = 'block';
	
	// Fetch carbon usage data with user's credentials
	displayCarbonUsage(apiKey, regionName);
}

Passo a passo, aqui está o que acontece:

  • Salva a chave da API e o nome da região no armazenamento local para uso futuro
  • Exibe um indicador de carregamento para informar aos usuários que os dados estão sendo buscados
  • Limpa quaisquer mensagens de erro anteriores da exibição
  • Revela o botão de limpar para que os usuários possam redefinir suas configurações mais tarde
  • Inicia a chamada à API para buscar dados reais de uso de carbono

Esta função cria uma experiência de usuário perfeita ao gerenciar tanto a persistência de dados quanto as atualizações da interface do usuário em uma ação coordenada.

Exibir dados de uso de carbono

Agora vamos conectar sua extensão a fontes de dados externas por meio de APIs. Isso transforma sua extensão de uma ferramenta independente em algo que pode acessar informações em tempo real de toda a internet.

Entendendo APIs

APIs são como diferentes aplicativos se comunicam entre si. Pense nelas como o sistema de telégrafo que conectava cidades distantes no século XIX - os operadores enviavam solicitações para estações distantes e recebiam respostas com as informações solicitadas. Toda vez que você verifica redes sociais, faz uma pergunta a um assistente de voz ou usa um aplicativo de entrega, as APIs estão facilitando essas trocas de dados.

Conceitos-chave sobre APIs REST:

  • REST significa 'Transferência de Estado Representacional'
  • Usa métodos HTTP padrão (GET, POST, PUT, DELETE) para interagir com dados
  • Retorna dados em formatos previsíveis, geralmente JSON
  • Fornece endpoints consistentes baseados em URL para diferentes tipos de solicitações

A API CO2 Signal que usaremos fornece dados em tempo real sobre a intensidade de carbono das redes elétricas em todo o mundo. Isso ajuda os usuários a entender o impacto ambiental do uso de eletricidade!

💡 Entendendo o JavaScript Assíncrono: A palavra-chave async permite que seu código lide com várias operações simultaneamente. Quando você solicita dados de um servidor, não quer que toda a extensão congele - isso seria como o controle de tráfego aéreo parar todas as operações enquanto espera por uma resposta de um avião.

Benefícios principais:

  • Mantém a responsividade da extensão enquanto os dados são carregados
  • Permite que outros códigos continuem executando durante solicitações de rede
  • Melhora a legibilidade do código em comparação com padrões tradicionais de callback
  • Habilita tratamento de erros elegante para problemas de rede

Aqui está um vídeo rápido sobre async:

Async e Await para gerenciar promessas

🎥 Clique na imagem acima para um vídeo sobre async/await.

Crie a função para buscar e exibir dados de uso de carbono:

// Modern fetch API approach (no external dependencies needed)
async function displayCarbonUsage(apiKey, region) {
	try {
		// Fetch carbon intensity data from CO2 Signal API
		const response = await fetch('https://api.co2signal.com/v1/latest', {
			method: 'GET',
			headers: {
				'auth-token': apiKey,
				'Content-Type': 'application/json'
			},
			// Add query parameters for the specific region
			...new URLSearchParams({ countryCode: region }) && {
				url: `https://api.co2signal.com/v1/latest?countryCode=${region}`
			}
		});

		// Check if the API request was successful
		if (!response.ok) {
			throw new Error(`API request failed: ${response.status}`);
		}

		const data = await response.json();
		const carbonData = data.data;

		// Calculate rounded carbon intensity value
		const carbonIntensity = Math.round(carbonData.carbonIntensity);

		// Update the user interface with fetched data
		loading.style.display = 'none';
		form.style.display = 'none';
		myregion.textContent = region.toUpperCase();
		usage.textContent = `${carbonIntensity} grams (grams CO₂ emitted per kilowatt hour)`;
		fossilfuel.textContent = `${carbonData.fossilFuelPercentage.toFixed(2)}% (percentage of fossil fuels used to generate electricity)`;
		results.style.display = 'block';

		// TODO: calculateColor(carbonIntensity) - implement in next lesson

	} catch (error) {
		console.error('Error fetching carbon data:', error);
		
		// Show user-friendly error message
		loading.style.display = 'none';
		results.style.display = 'none';
		errors.textContent = 'Sorry, we couldn\'t fetch data for that region. Please check your API key and region code.';
	}
}

Desmembrando o que acontece aqui:

  • Usa a moderna API fetch() em vez de bibliotecas externas como Axios para um código mais limpo e sem dependências
  • Implementa verificação de erros adequada com response.ok para capturar falhas na API cedo
  • Lida com operações assíncronas usando async/await para um fluxo de código mais legível
  • Autentica com a API CO2 Signal usando o cabeçalho auth-token
  • Analisa dados de resposta JSON e extrai informações de intensidade de carbono
  • Atualiza múltiplos elementos da interface com dados ambientais formatados
  • Fornece mensagens de erro amigáveis ao usuário quando as chamadas à API falham

Conceitos modernos de JavaScript demonstrados:

  • Literais de template com a sintaxe ${} para formatação de strings limpa
  • Tratamento de erros com blocos try/catch para aplicações robustas
  • Padrão async/await para lidar graciosamente com solicitações de rede
  • Desestruturação de objetos para extrair dados específicos de respostas da API
  • Encadeamento de métodos para múltiplas manipulações de DOM

Esta função demonstra vários conceitos importantes de desenvolvimento web - comunicação com servidores externos, autenticação, processamento de dados, atualização de interfaces e gerenciamento de erros de forma elegante. Estas são habilidades fundamentais que os desenvolvedores profissionais usam regularmente.

🎉 O que você conquistou: Você criou uma extensão de navegador que:

  • Conecta-se à internet e recupera dados ambientais reais
  • Persiste configurações do usuário entre sessões
  • Lida com erros de forma elegante em vez de travar
  • Proporciona uma experiência de usuário suave e profissional

Teste seu trabalho executando npm run build e atualizando sua extensão no navegador. Agora você tem um rastreador funcional de pegada de carbono. A próxima aula adicionará funcionalidade dinâmica de ícones para completar a extensão.


Desafio do Agente GitHub Copilot 🚀

Use o modo Agente para completar o seguinte desafio:

Descrição: Melhore a extensão de navegador adicionando melhorias no tratamento de erros e recursos de experiência do usuário. Este desafio ajudará você a praticar o trabalho com APIs, armazenamento local e manipulação de DOM usando padrões modernos de JavaScript.

Prompt: Crie uma versão aprimorada da função displayCarbonUsage que inclua: 1) Um mecanismo de tentativa de nova chamada para falhas na API com recuo exponencial, 2) Validação de entrada para o código da região antes de fazer a chamada à API, 3) Uma animação de carregamento com indicadores de progresso, 4) Cache de respostas da API no localStorage com marcações de expiração (cache por 30 minutos), e 5) Um recurso para exibir dados históricos de chamadas anteriores à API. Além disso, adicione comentários JSDoc no estilo TypeScript para documentar todos os parâmetros da função e tipos de retorno.

Saiba mais sobre o modo agente aqui.

🚀 Desafio

Amplie sua compreensão sobre APIs explorando a riqueza de APIs baseadas em navegador disponíveis para desenvolvimento web. Escolha uma dessas APIs de navegador e construa uma pequena demonstração:

Perguntas de pesquisa para considerar:

  • Que problemas do mundo real esta API resolve?
  • Como a API lida com erros e casos extremos?
  • Quais considerações de segurança existem ao usar esta API?
  • Quão amplamente suportada é esta API em diferentes navegadores?

Após sua pesquisa, identifique quais características tornam uma API amigável para desenvolvedores e confiável.

Quiz Pós-Aula

Quiz pós-aula

Revisão & Autoestudo

Você aprendeu sobre LocalStorage e APIs nesta lição, ambos muito úteis para o desenvolvedor web profissional. Consegue pensar em como essas duas coisas funcionam juntas? Pense em como você arquitetaria um site que armazenaria itens para serem usados por uma API.

Tarefa

Adote uma API


Aviso Legal:
Este documento foi traduzido usando o serviço de tradução por IA Co-op Translator. Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.