Cliente HTTP em JavaScript: fazendo requisições corretamente — de A a Z
\nNo desenvolvimento web moderno, a interação com APIs externas e servidores é uma tarefa rotineira, mas criticamente importante. Independentemente de você estar escrevendo um microsserviço em Node.js, fazendo scraping de dados ou criando um bot, precisará de um cliente HTTP confiável. Neste artigo, vamos abordar como fazer requisições HTTP em JavaScript (Node.js) corretamente, explorar bibliotecas populares, tratamento de erros, timeouts e melhores práticas.
\n\n1. Ferramentas nativas: módulo http e node-fetch
\nO Node.js possui os módulos nativos http e https, mas suas APIs são de baixo nível e inconvenientes para uso diário. Por isso, geralmente são usadas bibliotecas wrapper.
1.1. node-fetch (v3+)
\nA partir da versão 18, o Node.js tem suporte nativo a fetch (experimental). Para versões mais antigas ou funcionalidades avançadas, use o pacote node-fetch.
// Instalação: npm install node-fetch\nimport fetch from 'node-fetch';\n\nasync function getUsers() {\n try {\n const response = await fetch('https://jsonplaceholder.typicode.com/users');\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error('Erro na requisição:', error.message);\n }\n}\n\ngetUsers();\n\n1.2. Fetch nativo (Node.js 18+)
\nUsado de forma similar ao fetch do navegador:
\n// Node.js 18+ sem pacotes adicionais\nasync function postData() {\n const response = await fetch('https://api.example.com/data', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ key: 'value' })\n });\n return response.json();\n}\n\n2. Axios — o padrão ouro de cliente HTTP
\nAxios é a biblioteca mais popular para requisições HTTP em JavaScript. Ela oferece uma interface conveniente, suporte a Promises, interceptadores (interceptors) e transformação automática de JSON.
\n\n2.1. Instalação e requisição GET básica
\n// npm install axios\nconst axios = require('axios');\n\nasync function fetchUsers() {\n try {\n const response = await axios.get('https://jsonplaceholder.typicode.com/users');\n console.log(response.data); // dados já parseados\n } catch (error) {\n console.error('Erro:', error.message);\n }\n}\n\n2.2. Requisição POST com dados
\nasync function createUser() {\n const newUser = { name: 'João', email: 'joao@example.com' };\n const response = await axios.post('https://jsonplaceholder.typicode.com/users', newUser);\n console.log('Usuário criado:', response.data);\n}\n\n2.3. Configuração de timeout e cabeçalhos
\nTimeout é uma opção criticamente importante para evitar que a aplicação congele:
\nasync function fetchWithTimeout() {\n try {\n const response = await axios.get('https://slow-api.example.com/data', {\n timeout: 5000, // 5 segundos\n headers: {\n 'Authorization': 'Bearer token123',\n 'Accept': 'application/json'\n }\n });\n return response.data;\n } catch (error) {\n if (error.code === 'ECONNABORTED') {\n console.error('Timeout da requisição');\n }\n }\n}\n\n3. Técnicas avançadas e melhores práticas
\n\n3.1. Tratamento de erros e tentativas repetidas (retry)
\nRedes são instáveis, por isso é importante implementar um mecanismo de tentativas repetidas:
\nasync function fetchWithRetry(url, retries = 3) {\n for (let i = 0; i < retries; i++) {\n try {\n const response = await axios.get(url);\n return response.data;\n } catch (error) {\n if (i === retries - 1) throw error; // última tentativa\n console.log(`Tentativa ${i + 1} falhou, repetindo em ${(i + 1) * 1000}ms...`);\n await new Promise(