Fetch API: fazendo requisições HTTP
1. Introdução à Fetch API
A Fetch API é a interface moderna do JavaScript para realizar requisições HTTP, substituindo o antigo XMLHttpRequest. Introduzida no ES6, ela utiliza Promises para lidar com operações assíncronas de forma mais limpa e legível.
Diferentemente do XMLHttpRequest, que exigia callbacks aninhados e configuração manual de eventos, o Fetch oferece uma sintaxe concisa baseada em Promises, permitindo encadeamento com .then() ou o uso de async/await. A API é nativa nos navegadores modernos e, a partir do Node.js 18, também está disponível no backend sem necessidade de bibliotecas externas.
Para ambientes legados, existem polyfills como o whatwg-fetch que garantem compatibilidade com navegadores antigos.
2. Sintaxe Básica e Primeira Requisição GET
A estrutura fundamental da Fetch API é surpreendentemente simples:
fetch('https://api.exemplo.com/dados')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Erro:', error));
O método fetch() recebe uma URL e retorna uma Promise que resolve para um objeto Response. Esse objeto contém métodos para extrair o corpo da resposta:
.json()— para dados JSON.text()— para texto simples.blob()— para arquivos binários.formData()— para dados de formulário.arrayBuffer()— para buffers binários
Tratamento básico de erros:
fetch('https://api.exemplo.com/usuarios')
.then(response => {
if (!response.ok) {
throw new Error(`Erro HTTP: ${response.status}`);
}
return response.json();
})
.then(usuarios => console.log(usuarios))
.catch(error => console.error('Falha na requisição:', error));
A propriedade response.ok retorna true apenas para status entre 200-299, facilitando a detecção de erros HTTP.
3. Configurando Requisições com o Objeto options
O segundo parâmetro do fetch() permite configurar detalhes da requisição:
// POST com JSON
fetch('https://api.exemplo.com/usuarios', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
body: JSON.stringify({
nome: 'Maria',
email: 'maria@exemplo.com'
})
});
Métodos HTTP suportados: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.
Enviando FormData:
const formData = new FormData();
formData.append('arquivo', fileInput.files[0]);
formData.append('nome', 'Documento');
fetch('/upload', {
method: 'POST',
body: formData // Não definir Content-Type, o navegador define automaticamente
});
Enviando URLSearchParams:
const params = new URLSearchParams();
params.append('usuario', 'joao');
params.append('acao', 'login');
fetch('/autenticar', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: params
});
4. Tratamento de Respostas e Erros
É crucial entender que o Fetch não rejeita a Promise para erros HTTP (4xx/5xx). A Promise só é rejeitada em caso de falha de rede.
fetch('https://api.exemplo.com/recurso')
.then(response => {
if (!response.ok) {
// Lança exceção manual para erros HTTP
throw new Error(`Erro ${response.status}: ${response.statusText}`);
}
return response.json();
})
.then(data => processarDados(data))
.catch(error => {
// Captura tanto erros de rede quanto erros HTTP
console.error('Requisição falhou:', error.message);
});
Boas práticas: Sempre verifique response.ok e lance exceções apropriadas. Utilize response.status para lógicas condicionais (ex: redirecionar para login se 401).
5. Fetch no Node.js
A partir do Node.js 18, o Fetch está disponível nativamente como globalThis.fetch. Para versões anteriores, use o pacote node-fetch:
npm install node-fetch
// Node.js 18+ (nativo)
const response = await fetch('https://api.exemplo.com/dados');
const data = await response.json();
// Node.js < 18 com node-fetch
import fetch from 'node-fetch';
Diferenças importantes para o ambiente Node.js:
- Timeouts não são nativos — é necessário implementar com AbortController
- Cookies não são gerenciados automaticamente
- Não há suporte a CORS (inexistente no backend)
- O node-fetch não suporta todos os recursos do Fetch do navegador
6. Fetch no Ecossistema React
No React, as requisições geralmente são feitas dentro do hook useEffect:
import { useState, useEffect } from 'react';
function ListaUsuarios() {
const [usuarios, setUsuarios] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('https://api.exemplo.com/usuarios')
.then(response => {
if (!response.ok) throw new Error('Erro ao carregar');
return response.json();
})
.then(data => {
setUsuarios(data);
setLoading(false);
})
.catch(err => {
setError(err.message);
setLoading(false);
});
}, []);
if (loading) return <p>Carregando...</p>;
if (error) return <p>Erro: {error}</p>;
return <ul>{usuarios.map(u => <li key={u.id}>{u.nome}</li>)}</ul>;
}
Hook customizado useFetch:
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal })
.then(res => {
if (!res.ok) throw new Error('Erro na requisição');
return res.json();
})
.then(setData)
.catch(err => {
if (err.name !== 'AbortError') setError(err.message);
})
.finally(() => setLoading(false));
return () => controller.abort(); // Cleanup ao desmontar
}, [url]);
return { data, loading, error };
}
7. Boas Práticas e Padrões Avançados
Abortando requisições com AbortController:
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeoutId);
// processar resposta
} catch (error) {
if (error.name === 'AbortError') {
console.log('Requisição cancelada por timeout');
}
}
Wrapper para reutilização de lógica:
const api = {
baseURL: 'https://api.exemplo.com',
async request(endpoint, options = {}) {
const token = localStorage.getItem('token');
const config = {
headers: {
'Content-Type': 'application/json',
...(token && { 'Authorization': `Bearer ${token}` }),
...options.headers
},
...options
};
const response = await fetch(`${this.baseURL}${endpoint}`, config);
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.message || `Erro ${response.status}`);
}
return response.json();
},
get(endpoint) { return this.request(endpoint); },
post(endpoint, data) { return this.request(endpoint, { method: 'POST', body: JSON.stringify(data) }); },
put(endpoint, data) { return this.request(endpoint, { method: 'PUT', body: JSON.stringify(data) }); },
delete(endpoint) { return this.request(endpoint, { method: 'DELETE' }); }
};
// Uso:
const usuarios = await api.get('/usuarios');
Cache simples para evitar requisições duplicadas:
const cache = new Map();
async function fetchComCache(url, ttl = 60000) {
if (cache.has(url)) {
const { data, timestamp } = cache.get(url);
if (Date.now() - timestamp < ttl) return data;
}
const response = await fetch(url);
const data = await response.json();
cache.set(url, { data, timestamp: Date.now() });
return data;
}
8. Conclusão e Próximos Passos
A Fetch API representa a evolução natural das requisições HTTP no JavaScript, oferecendo uma interface baseada em Promises que se integra perfeitamente com async/await. Embora bibliotecas como Axios ofereçam recursos adicionais (interceptors automáticos, progresso de upload, timeouts nativos), o Fetch é suficiente para a maioria dos casos de uso e elimina dependências externas.
Pontos-chave para lembrar:
- Sempre verifique response.ok para erros HTTP
- Use AbortController para cancelar requisições
- No React, gerencie estados de loading, dados e erro
- Considere criar wrappers para centralizar lógica de autenticação
Nos próximos artigos, exploraremos o consumo de APIs REST completas, manipulação de JSON e envio de formulários complexos.
Referências
- MDN Web Docs: Fetch API — Documentação oficial completa com exemplos e especificações técnicas
- Node.js Documentation: Fetch — Documentação oficial do Fetch nativo no Node.js 18+
- React Documentation: Fetching Data with Effects — Guia oficial do React sobre requisições com useEffect
- JavaScript.info: Fetch API — Tutorial detalhado em português com exemplos práticos e explicações claras
- DigitalOcean: How to Use the Fetch API — Tutorial completo cobrindo GET, POST, tratamento de erros e boas práticas
- Axios vs Fetch: Which One to Use? — Artigo comparativo detalhado entre Axios e Fetch API