Buscar Dados de APIs no Node.js
Se você é um desenvolvedor frontend escrevendo código Node.js, provavelmente já recorreu ao Axios por hábito, ou se perguntou se ainda precisa do node-fetch. A resposta hoje é mais simples do que você imagina: o Node.js moderno possui uma API fetch integrada e estável, e para a maioria dos casos de uso, é tudo o que você precisa.
Aqui está o que você precisa saber para fazer requisições HTTP do lado do servidor de forma limpa e confiável hoje.
Pontos-Chave
- O Node.js moderno vem com uma API
fetchglobal alimentada pelo undici — sem necessidade de instalar pacotes. fetchnão lança exceções em erros HTTP como 404 ou 500. Sempre verifiqueresponse.okantes de ler o corpo da resposta.- Use
AbortSignal.timeout()para timeouts de requisição em vez de configuração manual deAbortController. - Para cenários de alto volume com requisições repetidas para a mesma origem, use o
Pooldo undici para reutilização de conexões. - Prefira o
fetchnativo em vez do Axios em projetos exclusivos do Node para manter sua lista de dependências enxuta.
A API Fetch do Node.js É Estável e Integrada
Desde o Node.js 18, fetch está disponível globalmente sem necessidade de imports. Foi marcado como experimental na v18, e depois estabilizado na v21. É alimentado pelo undici por baixo dos panos — o cliente HTTP que sustenta a implementação do fetch no Node — e espelha a API Fetch do navegador que você já conhece.
Sem instalação. Sem require('node-fetch'). Apenas fetch().
const response = await fetch("https://api.github.com/users/nodejs/repos", {
headers: { "User-Agent": "my-app" },
})
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`)
}
const repos = await response.json()
console.log(repos.map((r) => r.name))
Uma coisa importante para entender: fetch não lança exceções em erros HTTP como 404 ou 500. Ele só lança em falhas de rede. Sempre verifique response.ok ou response.status antes de ler o corpo da resposta.
Fazendo Requisições POST com a API Fetch do Node.js
Enviar dados é simples. Defina o method, adicione um cabeçalho Content-Type e serialize seu payload:
const response = await fetch("https://api.example.com/posts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: "Hello", body: "World" }),
})
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`)
}
const data = await response.json()
Para uploads de FormData, omita completamente o cabeçalho Content-Type — fetch o define automaticamente com o boundary multipart correto.
Lidando com Timeouts Usando AbortSignal
Não há uma opção de timeout integrada na própria chamada fetch, mas AbortSignal.timeout() torna isso simples:
const response = await fetch("https://api.example.com/data", {
signal: AbortSignal.timeout(5000), // 5 segundos
})
Se a requisição exceder o limite, ela é abortada. Não é necessária configuração manual de AbortController para o caso simples.
Para cenários mais complexos — digamos que você queira cancelar uma requisição baseado em uma ação do usuário e aplicar um timeout — você pode combinar um AbortController com AbortSignal.any():
const controller = new AbortController()
const response = await fetch("https://api.example.com/data", {
signal: AbortSignal.any([
controller.signal,
AbortSignal.timeout(5000),
]),
})
// Chame controller.abort() em outro lugar para cancelar manualmente
Discover how at OpenReplay.com.
Quando Usar Undici Diretamente
Para a maioria das requisições de API no Node.js, o fetch global é a ferramenta certa. Mas se você estiver fazendo muitas requisições para a mesma origem — como acessar um serviço interno repetidamente — o Pool do undici oferece reutilização de conexões e controle mais refinado.
import { Pool } from "undici"
const pool = new Pool("https://internal-api.example.com", {
connections: 10,
})
const { statusCode, body } = await pool.request({
path: "/data",
method: "GET",
})
const data = await body.json()
Note que pool.request() retorna um body que é um stream legível, não um objeto Response. Você precisa consumi-lo explicitamente — por exemplo com body.json() ou body.text().
Use undici diretamente quando precisar de pooling avançado, streaming eficiente de respostas grandes, ou throughput máximo em código sensível a performance.
Fetch do Node.js vs Axios: Qual Você Deve Usar?
| Fetch Nativo | Axios | |
|---|---|---|
| Instalação necessária | Não | Sim |
| Compatível com navegador | Sim | Sim |
| Parse automático de JSON | Não (chame .json()) | Sim |
| Interceptors | Manual | Integrado |
| Lança exceção em erros HTTP | Não | Sim |
| Opção de timeout | AbortSignal | Integrado |
Axios continua sendo uma escolha sólida se você quer interceptors, parsing automático de JSON, ou comportamento consistente entre navegador e Node na mesma base de código. Mas se você está escrevendo código exclusivo para Node e não precisa desses extras, o fetch nativo mantém sua lista de dependências limpa.
Evite node-fetch para novos projetos. Era a solução certa antes do Node 18, mas agora é redundante em qualquer versão suportada do Node.js.
Conclusão
Para requisições HTTP do lado do servidor no Node.js moderno, comece com o fetch integrado. É estável, familiar e não requer nada extra. Adicione AbortSignal.timeout() para timeouts, verifique response.ok para erros, e recorra ao Pool do undici apenas quando a performance exigir. Mantenha o Axios em seu toolkit se você realmente precisar de seus recursos de nível mais alto — mas não o instale por padrão.
Perguntas Frequentes
Sim. A API fetch global foi introduzida como experimental no Node.js 18 e tornou-se estável no Node.js 21. É alimentada pelo undici e não requer pacotes adicionais. Qualquer versão atualmente suportada do Node.js a inclui pronta para uso.
Por design, o fetch só rejeita a promise em falhas no nível de rede, como erros de resolução DNS ou conexões perdidas. Códigos de status de erro HTTP como 404 ou 500 são considerados respostas válidas. Você deve verificar response.ok ou response.status você mesmo antes de processar o corpo da resposta.
Sim, não há conflito. Algumas equipes usam fetch nativo para requisições simples e Axios onde precisam de interceptors ou lançamento automático de erros. Dito isso, misturar clientes HTTP adiciona complexidade, então escolha um como padrão e use o outro apenas quando seus recursos específicos forem necessários.
Use undici diretamente quando precisar de pooling de conexões, controle refinado sobre conexões HTTP, ou throughput máximo para requisições repetidas à mesma origem. Para chamadas de API típicas onde simplicidade importa mais que performance bruta, o fetch global é suficiente.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.