A Fetch API
Esta aula aborda a Fetch API do JavaScript, explicando como fazer requisições GET e POST, configurar headers personalizados, tratar respostas e lidar com erros de rede de forma eficiente.
A Fetch API é uma interface moderna para realizar requisições HTTP no navegador, substituindo o antigo XMLHttpRequest. Ela fornece uma abordagem baseada em Promises, tornando o código mais limpo e fácil de gerenciar. Nesta aula, vamos explorar os principais conceitos e práticas para usar a Fetch API em aplicações web.
Com a Fetch API, você pode buscar recursos (como dados JSON, textos ou imagens) de servidores remotos e enviar dados para eles. Vamos cobrir desde requisições simples até o tratamento de erros de rede, passando por configurações de cabeçalhos e manipulação de respostas.
GET e POST
Requisições GET são usadas para obter dados do servidor, enquanto POST é usado para enviar dados (como formulários ou JSON) para serem processados. A Fetch API simplifica ambos os tipos.
Exemplo de GET:
fetch('https://api.exemplo.com/dados')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Erro:', error));Exemplo de POST enviando JSON:
fetch('https://api.exemplo.com/enviar', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ nome: 'João', idade: 30 })
})
.then(response => response.json())
.then(data => console.log('Sucesso:', data))
.catch(error => console.error('Erro:', error));No POST, é obrigatório especificar o método e, geralmente, o cabeçalho Content-Type para que o servidor interprete corretamente o corpo da requisição. O corpo deve ser convertido para string com JSON.stringify().
Headers
Os cabeçalhos (headers) permitem enviar metadados adicionais na requisição, como tokens de autenticação, tipo de conteúdo esperado, etc. Você pode configurá-los no objeto de opções da Fetch.
Exemplo com headers personalizados:
fetch('https://api.exemplo.com/protegido', {
headers: {
'Authorization': 'Bearer meu-token',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data));É possível também usar o construtor Headers para criar e manipular cabeçalhos de forma mais programática:
const headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('X-API-Key', 'chave-secreta');
fetch('https://api.exemplo.com/dados', {
method: 'POST',
headers: headers,
body: JSON.stringify({ chave: 'valor' })
});Headers comuns incluem Content-Type, Accept, Authorization, Cache-Control, entre outros. Lembre-se de que alguns cabeçalhos são restritos e não podem ser modificados por segurança (como Cookie ou Host).
Tratando respostas
A resposta da Fetch é um objeto Response que contém informações como status, headers e corpo. Você precisa decidir como processar o corpo, dependendo do formato (JSON, texto, blob, etc.).
Exemplo verificando o status:
fetch('https://api.exemplo.com/usuarios')
.then(response => {
if (!response.ok) {
throw new Error(`Erro HTTP: ${response.status}`);
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error(error));Propriedades úteis do objeto Response:
response.status– código numérico (200, 404, etc.)response.statusText– mensagem correspondente (OK, Not Found)response.ok– booleano indicando se status está entre 200-299response.headers– objeto Headers com os cabeçalhos da resposta
Métodos para extrair o corpo:
response.json()– retorna Promise com o JSON analisadoresponse.text()– retorna Promise com o texto puroresponse.blob()– para dados binários (imagens, arquivos)response.formData()– para dados de formulário
Importante: o corpo só pode ser lido uma vez. Se precisar do conteúdo em diferentes formatos, use response.clone().
Erros de rede
Diferente de requisições com XMLHttpRequest, a Fetch API só rejeita a Promise em caso de erros de rede (como falha de DNS, tempo limite excedido ou conexão recusada). Erros HTTP (404, 500) são considerados respostas bem-sucedidas no nível da rede, então a Promise é resolvida normalmente. Você precisa verificar manualmente o status da resposta.
Exemplo tratando erros de rede e HTTP:
fetch('https://api.exemplo.com/recurso')
.then(response => {
if (!response.ok) {
throw new Error(`Erro HTTP: ${response.status}`);
}
return response.json();
})
.then(data => console.log(data))
.catch(error => {
if (error instanceof TypeError) {
console.error('Erro de rede:', error.message);
} else {
console.error('Erro na requisição:', error.message);
}
});Para detectar erros de rede, você pode verificar se o erro é do tipo TypeError (comum em falhas de rede). Além disso, você pode usar o AbortController para cancelar requisições e lidar com timeouts:
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
fetch('https://api.exemplo.com/dados', { signal: controller.signal })
.then(response => response.json())
.then(data => {
clearTimeout(timeoutId);
console.log(data);
})
.catch(error => {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
console.error('Requisição cancelada por timeout');
} else {
console.error('Erro:', error);
}
});Esse padrão é útil para evitar requisições pendentes que podem travar a aplicação.
Boas práticas
- Sempre verifique
response.okantes de processar o corpo. - Use
try/catchcom async/await para um código mais legível. - Defina timeouts com AbortController para evitar esperas infinitas.
- Não exponha tokens ou chaves no frontend; use variáveis de ambiente ou proxies.
- Prefira usar bibliotecas como axios para funcionalidades extras, mas a Fetch nativa é suficiente para a maioria dos casos.
Referências
- MDN: Fetch API
- MDN: Usando Fetch
- MDN: Headers
- MDN: Response
- MDN: AbortController
- JavaScript.info: Fetch API
Exercícios
Faça uma requisição GET para 'https://jsonplaceholder.typicode.com/posts/1' e exiba o título do post no console.
✓ Resposta:fetch('https://jsonplaceholder.typicode.com/posts/1') .then(response => response.json()) .then(data => console.log(data.title)) .catch(error => console.error('Erro:', error));Envie um POST para 'https://jsonplaceholder.typicode.com/posts' com um objeto JSON contendo title, body e userId. Exiba a resposta no console.
✓ Resposta:fetch('https://jsonplaceholder.typicode.com/posts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Meu post', body: 'Conteúdo do post', userId: 1 }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Erro:', error));Faça uma requisição GET com um cabeçalho personalizado 'X-Custom-Header' de valor 'meu-valor' para 'https://httpbin.org/headers' e exiba a resposta.
✓ Resposta:fetch('https://httpbin.org/headers', { headers: { 'X-Custom-Header': 'meu-valor' } }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Erro:', error));Trate uma resposta com status 404: faça uma requisição GET para uma URL inexistente (ex.: 'https://jsonplaceholder.typicode.com/invalid') e verifique se response.ok é false, lançando um erro com o status.
✓ Resposta:fetch('https://jsonplaceholder.typicode.com/invalid') .then(response => { if (!response.ok) { throw new Error(`Erro HTTP: ${response.status}`); } return response.json(); }) .then(data => console.log(data)) .catch(error => console.error('Erro:', error.message));Simule um erro de rede usando uma URL inválida (ex.: 'https://dominioquenaoexiste123.com') e capture o erro, exibindo 'Erro de rede' no console.
✓ Resposta:fetch('https://dominioquenaoexiste123.com') .then(response => console.log(response)) .catch(error => { if (error instanceof TypeError) { console.error('Erro de rede'); } else { console.error('Erro:', error.message); } });