Neste laboratório, você aprenderá as habilidades essenciais para interagir com APIs web usando JavaScript moderno. Você explorará a API fetch, uma ferramenta poderosa e flexível integrada aos navegadores web, para fazer requisições de rede assíncronas. O objetivo principal é entender como requisitar dados de um servidor, lidar com a resposta e gerenciar possíveis erros, formando uma habilidade fundamental para construir aplicações web dinâmicas.
Você começará fazendo uma requisição GET básica para recuperar dados e, em seguida, aprenderá como lidar com a resposta, analisá-la como JSON e exibir os dados obtidos dentro de um elemento HTML. O laboratório também aborda aspectos cruciais como a implementação de tratamento de erros robusto, a realização de requisições POST para enviar dados a um servidor e a autenticação de suas requisições usando uma chave de API.
Fazer uma Requisição GET Básica com a API fetch
Nesta etapa, você aprenderá como fazer uma chamada fundamental de API em JavaScript: uma requisição GET. Usaremos a API fetch, que é uma ferramenta moderna, poderosa e flexível integrada a todos os navegadores web modernos e disponível em ambientes Node.js 18+. Ela nos permite requisitar recursos de um servidor de forma assíncrona.
A função fetch é baseada em Promises, o que significa que ela retorna uma Promise que resolve para a Response dessa requisição, independentemente de ter sido bem-sucedida ou não. Isso nos permite lidar com o resultado da operação assíncrona quando ela é concluída.
Primeiro, vamos criar um arquivo para escrever nosso código. No explorador de arquivos no lado esquerdo da sua tela, crie um novo arquivo chamado index.js no diretório ~/project.
Usaremos a API JSONPlaceholder para este exemplo. É uma API REST online gratuita e falsa, perfeita para testes e prototipagem. Solicitaremos um único item "todo".
Agora, adicione o seguinte código ao seu arquivo index.js. Este código define o URL do endpoint da API e usa fetch para fazer uma requisição GET.
// Define o URL da API para um único item todo
const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";
// Faz uma requisição GET usando a API fetch
fetch(apiUrl)
.then((response) => {
// A função fetch retorna uma promise.
// O primeiro bloco .then() recebe o objeto Response.
// Precisamos chamar o método .json() na resposta para analisar o corpo do texto como JSON.
return response.json();
})
.then((data) => {
// O segundo bloco .then() recebe os dados JSON analisados.
console.log("Dados buscados com sucesso:");
console.log(data);
})
.catch((error) => {
// O bloco .catch() será executado se ocorrer algum erro durante a operação fetch.
console.error("Erro ao buscar dados:", error);
});
Vamos detalhar o código:
apiUrl: Armazenamos o URL do endpoint da API com o qual queremos nos comunicar em uma constante.
fetch(apiUrl): Isso inicia a requisição GET para o URL especificado e retorna uma Promise.
.then(response => response.json()): Quando a Promise é resolvida, esta função é chamada. O objeto response não é o dado JSON real, mas uma representação da resposta HTTP completa. Chamamos o método response.json() para extrair o conteúdo do corpo JSON, que por si só retorna outra Promise.
.then(data => { ... }): Este segundo .then() lida com a Promise retornada por response.json(). O parâmetro data agora contém o objeto JSON real da API. Exibimos esses dados no console.
.catch(error => { ... }): Se a Promise for rejeitada em qualquer ponto (por exemplo, devido a um erro de rede), este bloco capturará o erro e o exibirá no console.
Para executar seu script e ver o resultado, abra um novo terminal no WebIDE e execute o seguinte comando:
node ~/project/index.js
Você deverá ver os dados buscados impressos no seu console, que representam um único item "todo" da API.
Saída Esperada:
Data fetched successfully:
{ userId: 1, id: 1, title: 'delectus aut autem', completed: false }
Lidar com a Resposta e Analisar Dados JSON
Nesta etapa, vamos nos aprofundar no tratamento da resposta de uma chamada de API. Ao usar fetch, o servidor envia de volta um objeto Response. Exploraremos o que este objeto contém e como analisar corretamente os dados JSON de seu corpo para usá-los em sua aplicação.
O objeto Response que você recebe no primeiro bloco .then() não é o dado em si. É uma representação da resposta HTTP completa, incluindo códigos de status (como 200 para OK), cabeçalhos e o corpo da resposta. O corpo é um fluxo de dados, e para usá-lo, você precisa lê-lo.
A API fetch fornece vários métodos para isso, como .text() para texto puro e .json() para analisar dados JSON. O método .json() lê o fluxo de resposta até a conclusão e retorna uma nova promessa que resolve com o resultado da análise do texto do corpo como um objeto JavaScript. É por isso que encadeamos um segundo .then() para trabalhar com os dados reais.
Vamos modificar nosso arquivo ~/project/index.js para demonstrar isso. Em vez de apenas registrar todo o objeto de dados, acessaremos e registraremos propriedades específicas dele, mostrando que temos um objeto JavaScript regular para trabalhar.
Atualize o conteúdo do seu arquivo ~/project/index.js com o seguinte código:
// Define o URL da API para um único item todo
const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";
fetch(apiUrl)
.then((response) => {
// O método response.json() analisa o corpo JSON da resposta
// e retorna uma promessa que resolve com o objeto JavaScript resultante.
return response.json();
})
.then((data) => {
// Agora 'data' é um objeto JavaScript. Podemos acessar suas propriedades.
console.log("Dados JSON analisados com sucesso:");
console.log(`Título da Tarefa: ${data.title}`);
console.log(`Está Concluída: ${data.completed}`);
})
.catch((error) => {
// O bloco .catch() será executado se ocorrer algum erro durante a operação fetch.
console.error("Erro ao buscar ou analisar dados:", error);
});
Neste código atualizado, o segundo bloco .then() agora recebe os data como um objeto JavaScript. Usamos literais de template (a sintaxe de crase `) para criar strings que incluem os valores de data.title e data.completed, demonstrando que o JSON foi analisado com sucesso.
Agora, execute o script novamente em seu terminal para ver a nova saída:
node ~/project/index.js
Você verá uma saída mais estruturada, confirmando que você acessou com sucesso as propriedades do objeto JSON analisado.
Saída Esperada:
Successfully parsed JSON data:
Todo Title: delectus aut autem
Is Completed: false
Exibir Dados Buscados em um Elemento HTML
Nesta etapa, você aprenderá como pegar os dados buscados de uma API e exibi-los em uma página web. Embora registrar dados no console seja útil para o desenvolvimento, o objetivo final é frequentemente apresentar essas informações ao usuário. Isso requer um arquivo HTML para estruturar o conteúdo e JavaScript para manipular o Modelo de Objeto do Documento (DOM).
Primeiro, precisamos de um arquivo HTML. No explorador de arquivos à esquerda, crie um novo arquivo chamado index.html no diretório ~/project.
Adicione a seguinte estrutura HTML básica ao seu arquivo index.html. Este arquivo inclui um título e um elemento div com o ID data-output, que servirá como um contêiner para nossos dados buscados. A tag <script> no final do corpo garante que nosso JavaScript seja executado após os elementos HTML terem sido carregados.
Em seguida, você precisa modificar seu arquivo ~/project/index.js para interagir com este HTML. Em vez de registrar no console, o script encontrará o elemento div pelo seu ID e atualizará seu conteúdo com os dados da API.
Substitua o conteúdo de ~/project/index.js pelo seguinte código:
const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";
// Seleciona o elemento HTML onde exibiremos os dados
const outputElement = document.getElementById("data-output");
fetch(apiUrl)
.then((response) => response.json())
.then((data) => {
// Assim que tivermos os dados, atualizamos o conteúdo HTML.
// Usamos innerHTML para substituir a mensagem "Loading..." por dados estruturados.
outputElement.innerHTML = `
<p><strong>Title:</strong> ${data.title}</p>
<p><strong>Completed:</strong> ${data.completed}</p>
`;
})
.catch((error) => {
// Se ocorrer um erro, exibimos uma mensagem de erro para o usuário.
outputElement.textContent = "Failed to load data.";
console.error("Error fetching data:", error);
});
Agora, para ver o resultado, você precisa servir esses arquivos através de um servidor web. O ambiente LabEx inclui Python, que possui um servidor web integrado simples.
Abra um novo terminal no WebIDE.
Inicie o servidor web executando o seguinte comando. Isso servirá os arquivos no diretório atual (~/project) na porta 8080.
python3 -m http.server 8080
A plataforma LabEx detectará este serviço em execução e fornecerá uma aba "Web 8080" para visualizar sua página index.html.
Você deverá agora ver sua página web exibindo o título e o status de conclusão do item "todo" buscado, substituindo a mensagem inicial "Loading data...".
Implementar Tratamento de Erros para Chamadas de API
Nesta etapa, focaremos em tornar nossa chamada de API mais robusta, implementando o tratamento adequado de erros. Requisições de API podem falhar por vários motivos, como uma URL incorreta, problemas de rede ou problemas do lado do servidor. É crucial lidar com essas falhas potenciais de forma elegante para proporcionar uma melhor experiência ao usuário.
Um detalhe importante sobre a API fetch é que sua promessa não rejeita em status de erro HTTP como 404 (Not Found) ou 500 (Internal Server Error). Ela só rejeita se houver uma falha de rede que impeça a requisição de ser concluída. Para lidar com erros HTTP, precisamos verificar a propriedade response.ok, que é true para respostas bem-sucedidas (códigos de status 200-299).
Vamos atualizar nosso ~/project/index.js para verificar o status da resposta e lidar com erros potenciais.
Substitua o conteúdo do seu arquivo ~/project/index.js pelo seguinte código. Estamos adicionando uma verificação dentro do primeiro bloco .then().
const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";
const outputElement = document.getElementById("data-output");
fetch(apiUrl)
.then((response) => {
// Verifica se a resposta foi bem-sucedida.
// A propriedade 'ok' é um booleano que é true se o código de status estiver na faixa de 200-299.
if (!response.ok) {
// Se não for, lançamos um erro que será capturado pelo bloco .catch().
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then((data) => {
outputElement.innerHTML = `
<p><strong>Title:</strong> ${data.title}</p>
<p><strong>Completed:</strong> ${data.completed}</p>
`;
})
.catch((error) => {
// Exibe uma mensagem de erro amigável para o usuário no elemento HTML.
outputElement.textContent = "Failed to load data. Please try again later.";
// Registra o erro técnico no console para fins de depuração.
console.error("Error fetching data:", error);
});
Para ver nosso tratamento de erros em ação, vamos intencionalmente usar uma URL de API inválida. Modifique o apiUrl em ~/project/index.js para apontar para um recurso que não existe. Isso fará com que a API retorne um erro 404 Not Found.
Altere esta linha em seu arquivo index.js: const apiUrl = 'https://jsonplaceholder.typicode.com/todos/1';
Para esta: const apiUrl = 'https://jsonplaceholder.typicode.com/invalid-path/1';
Agora, vamos ver o resultado. Se o seu servidor web Python da etapa anterior ainda estiver em execução, simplesmente atualize a aba de pré-visualização em seu navegador. Se você o parou, inicie-o novamente no terminal:
python3 -m http.server 8080
Em seguida, abra a pré-visualização. Em vez dos dados, você deverá ver a mensagem de erro exibida na página porque nossa verificação if (!response.ok) capturou o erro 404.
Saída Esperada na Página Web:
Failed to load data. Please try again later.
Importante: Antes de passar para a próxima etapa, lembre-se de alterar o apiUrl de volta para o correto: https://jsonplaceholder.typicode.com/todos/1.
Fazer uma Requisição POST para Enviar Dados
Nesta etapa, você aprenderá como enviar dados para um servidor usando uma requisição POST. Até agora, apenas buscamos (ou "GET") dados. Uma requisição POST é usada para submeter dados a um recurso especificado, frequentemente causando uma mudança de estado ou a criação de uma nova entrada no servidor.
Para fazer isso, precisamos fornecer mais informações à função fetch, incluindo o método da requisição, cabeçalhos para descrever os dados que estamos enviando e os próprios dados no corpo da requisição.
Primeiro, vamos atualizar nosso arquivo ~/project/index.html para incluir um formulário. Isso nos permitirá inserir dados que podemos então enviar para a API. Substitua todo o conteúdo de index.html pelo seguinte:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>POST Request Example</title>
</head>
<body>
<h1>Create a New Todo Item</h1>
<form id="add-todo-form">
<input
type="text"
id="todo-title"
placeholder="Enter a new todo title"
required
/>
<button type="submit">Add Todo</button>
</form>
<hr />
<h2>Server Response:</h2>
<div id="response-output"></div>
<script src="index.js"></script>
</body>
</html>
Este HTML cria um formulário simples com um campo de texto e um botão de submissão, além de uma div para exibir a resposta do servidor.
Em seguida, substituiremos completamente o código em ~/project/index.js para lidar com a submissão do formulário e fazer uma requisição POST.
Substitua o conteúdo de ~/project/index.js pelo seguinte código:
// O endpoint da API para criar novos todos
const apiUrl = "https://jsonplaceholder.typicode.com/todos";
// Obtém o formulário e o elemento de saída de resposta do DOM
const todoForm = document.getElementById("add-todo-form");
const responseOutput = document.getElementById("response-output");
// Adiciona um ouvinte de evento para o evento de submissão do formulário
todoForm.addEventListener("submit", function (event) {
// Previne o comportamento padrão de submissão do formulário
event.preventDefault();
// Obtém o título do campo de entrada
const todoTitle = document.getElementById("todo-title").value;
// Os dados que queremos enviar na requisição POST
const newTodo = {
title: todoTitle,
completed: false,
userId: 1
};
// As opções para a requisição fetch
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(newTodo)
};
// Faz a requisição POST
fetch(apiUrl, requestOptions)
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// A API retorna o objeto criado, incluindo um novo 'id'
return response.json();
})
.then((data) => {
// Exibe a resposta do servidor em nossa div de saída
responseOutput.innerHTML = `<p>Successfully created todo!</p><pre>${JSON.stringify(data, null, 2)}</pre>`;
})
.catch((error) => {
responseOutput.textContent = "Failed to create todo.";
console.error("Error:", error);
});
});
Vamos detalhar o novo objeto requestOptions:
method: 'POST': Isso informa ao fetch para executar uma requisição POST.
headers: { 'Content-Type': 'application/json' }: Este cabeçalho informa ao servidor que os dados no corpo estão no formato JSON.
body: JSON.stringify(newTodo): Estes são os dados reais que estamos enviando. Eles devem ser convertidos em uma string JSON antes de serem enviados.
Agora, inicie seu servidor web novamente se ele não estiver em execução:
python3 -m http.server 8080
Abra a pré-visualização, digite um título para um novo item de tarefa no campo de entrada e clique no botão "Add Todo". Você deverá ver uma mensagem de sucesso e os dados retornados pelo servidor, que incluem o novo id para o item que você "criou".
Autenticar Requisições com uma Chave de API
Nesta etapa, você aprenderá como autenticar suas requisições de API usando uma chave de API (API key). Muitas APIs exigem autenticação para identificar o usuário, controlar o acesso aos dados e rastrear o uso. Uma chave de API é uma string única de caracteres que você inclui em sua requisição para provar que tem permissão para usar a API.
Existem várias maneiras de enviar uma chave de API, mas um método comum e seguro é incluí-la nos cabeçalhos da requisição (request headers), tipicamente usando o cabeçalho Authorization.
Para este exemplo, simularemos a busca de dados protegidos de usuário que requerem uma chave de API. Modificaremos nosso código para incluir um cabeçalho Authorization com um token "Bearer", que é uma forma padrão de enviar credenciais de autenticação.
Primeiro, vamos simplificar nosso arquivo ~/project/index.html para apenas exibir os dados do usuário buscados. Substitua seu conteúdo pelo seguinte:
Em seguida, substitua o conteúdo de ~/project/index.js pelo código abaixo. Este script fará uma requisição GET para buscar os dados de um usuário e incluirá uma chave de API falsa nos cabeçalhos.
// Define o URL da API para o perfil de um usuário
const apiUrl = "https://jsonplaceholder.typicode.com/users/1";
// Em uma aplicação real, você obteria esta chave do seu provedor de API.
const apiKey = "YOUR_SECRET_API_KEY_HERE";
// Seleciona o elemento HTML para saída
const userProfileElement = document.getElementById("user-profile");
// Cria o objeto de opções de requisição, incluindo os cabeçalhos para autenticação
const requestOptions = {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`
}
};
// Faz a requisição GET autenticada
fetch(apiUrl, requestOptions)
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then((data) => {
// Exibe os dados do usuário buscados
userProfileElement.innerHTML = `
<p><strong>Name:</strong> ${data.name}</p>
<p><strong>Email:</strong> ${data.email}</p>
<p><strong>Website:</strong> ${data.website}</p>
`;
})
.catch((error) => {
userProfileElement.textContent = "Failed to load user profile.";
console.error("Error:", error);
});
Neste código:
Definimos uma apiKey de placeholder.
Criamos um objeto requestOptions.
Dentro de headers, adicionamos uma chave Authorization. O valor Bearer ${apiKey} é um formato comum, onde "Bearer" é o tipo de token, seguido pela própria chave.
Nota: A API JSONPlaceholder que estamos usando é pública e não requer realmente uma chave de API. Ela simplesmente ignorará este cabeçalho. No entanto, este código demonstra o método padrão que você usaria para as muitas APIs do mundo real que exigem autenticação.
Para ver o resultado, inicie seu servidor web se ele ainda não estiver em execução:
python3 -m http.server 8080
Em seguida, abra a pré-visualização. A página carregará com sucesso e exibirá o perfil do usuário, demonstrando que você estruturou corretamente uma requisição de API autenticada.
Resumo
Neste laboratório, você aprendeu como chamar uma API em JavaScript usando a moderna API fetch. Você começou fazendo uma requisição GET básica para recuperar dados de um endpoint de API público. Você praticou o tratamento da natureza assíncrona do fetch usando promessas (promises), encadeando blocos .then() para processar a resposta e analisar o texto do corpo como JSON. As principais habilidades incluíram exibir os dados buscados dinamicamente dentro de um elemento HTML e implementar tratamento de erros robusto com um bloco .catch() para gerenciar possíveis falhas de rede.
Com base nesses fundamentos, você explorou como enviar dados para um servidor construindo e executando uma requisição POST, incluindo os cabeçalhos necessários e um payload JSON. Finalmente, você aprendeu um método comum para proteger comunicações de API autenticando suas requisições, o que envolveu incluir uma chave de API para obter acesso autorizado a recursos protegidos.