Obtención de datos desde APIs en Node.js
Si eres desarrollador frontend escribiendo código en Node.js, probablemente hayas recurrido a Axios por costumbre, o te hayas preguntado si todavía necesitas node-fetch. La respuesta hoy es más simple de lo que podrías pensar: Node.js moderno tiene una API fetch integrada y estable, y para la mayoría de casos de uso, es todo lo que necesitas.
Aquí está lo que necesitas saber para hacer peticiones HTTP del lado del servidor de forma limpia y confiable hoy en día.
Puntos Clave
- Node.js moderno incluye una API
fetchglobal impulsada por undici — sin paquetes que instalar. fetchno lanza errores en respuestas HTTP como 404 o 500. Siempre verificaresponse.okantes de leer el cuerpo de la respuesta.- Usa
AbortSignal.timeout()para tiempos de espera de peticiones en lugar de configurar manualmenteAbortController. - Para escenarios de alto rendimiento con peticiones repetidas al mismo origen, usa el
Poolde undici para reutilización de conexiones. - Prefiere
fetchnativo sobre Axios en proyectos exclusivos de Node para mantener tu lista de dependencias reducida.
La API Fetch de Node.js es Estable e Integrada
Desde Node.js 18, fetch está disponible globalmente sin necesidad de importaciones. Se marcó como experimental en v18, y luego se estabilizó en v21. Está impulsado por undici internamente — el cliente HTTP que respalda la implementación de fetch en Node — y refleja la API Fetch del navegador que ya conoces.
Sin instalación. Sin require('node-fetch'). Solo 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))
Una cosa importante a entender: fetch no lanza errores en respuestas HTTP como 404 o 500. Solo lanza errores en fallos de red. Siempre verifica response.ok o response.status antes de leer el cuerpo de la respuesta.
Realizando Peticiones POST con la API Fetch de Node.js
Enviar datos es sencillo. Establece method, añade un encabezado Content-Type, y serializa tu carga útil:
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 cargas de FormData, omite el encabezado Content-Type por completo — fetch lo establece automáticamente con el límite multipart correcto.
Manejo de Tiempos de Espera con AbortSignal
No hay una opción de tiempo de espera integrada en la llamada fetch en sí, pero AbortSignal.timeout() lo hace de forma limpia:
const response = await fetch("https://api.example.com/data", {
signal: AbortSignal.timeout(5000), // 5 segundos
})
Si la petición excede el límite, la petición se aborta. No se necesita configuración manual de AbortController para el caso simple.
Para escenarios más complejos — digamos que quieres cancelar una petición basándote en una acción del usuario y aplicar un tiempo de espera — puedes combinar un AbortController con AbortSignal.any():
const controller = new AbortController()
const response = await fetch("https://api.example.com/data", {
signal: AbortSignal.any([
controller.signal,
AbortSignal.timeout(5000),
]),
})
// Llama a controller.abort() en otro lugar para cancelar manualmente
Discover how at OpenReplay.com.
Cuándo Usar Undici Directamente
Para la mayoría de peticiones API en Node.js, fetch global es la herramienta correcta. Pero si estás haciendo muchas peticiones al mismo origen — como consultar un servicio interno repetidamente — el Pool de undici te da reutilización de conexiones y un control más fino.
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()
Ten en cuenta que pool.request() devuelve un body que es un stream legible, no un objeto Response. Necesitas consumirlo explícitamente — por ejemplo con body.json() o body.text().
Usa undici directamente cuando necesites pooling avanzado, transmitir respuestas grandes de forma eficiente, o máximo rendimiento en código sensible al rendimiento.
Fetch de Node.js vs Axios: ¿Cuál Deberías Usar?
| Fetch Nativo | Axios | |
|---|---|---|
| Instalación requerida | No | Sí |
| Compatible con navegador | Sí | Sí |
| Parseo automático de JSON | No (llama .json()) | Sí |
| Interceptores | Manual | Integrado |
| Lanza errores en errores HTTP | No | Sí |
| Opción de tiempo de espera | AbortSignal | Integrado |
Axios sigue siendo una opción sólida si quieres interceptores, parseo automático de JSON, o comportamiento consistente entre navegador y Node en la misma base de código. Pero si estás escribiendo código exclusivo de Node y no necesitas esos extras, fetch nativo mantiene tu lista de dependencias limpia.
Evita node-fetch para proyectos nuevos. Fue la solución correcta antes de Node 18, pero ahora es redundante en cualquier versión soportada de Node.js.
Conclusión
Para peticiones HTTP del lado del servidor en Node.js moderno, comienza con el fetch integrado. Es estable, familiar, y no requiere nada extra. Añade AbortSignal.timeout() para tiempos de espera, verifica response.ok para errores, y recurre al Pool de undici solo cuando el rendimiento lo demande. Mantén Axios en tu caja de herramientas si genuinamente necesitas sus características de nivel superior — pero no lo instales por defecto.
Preguntas Frecuentes
Sí. La API fetch global se introdujo como experimental en Node.js 18 y se volvió estable en Node.js 21. Está impulsada por undici y no requiere paquetes adicionales. Cualquier versión actualmente soportada de Node.js la incluye de forma predeterminada.
Por diseño, fetch solo rechaza la promesa en fallos a nivel de red como errores de resolución DNS o conexiones perdidas. Los códigos de estado de error HTTP como 404 o 500 se consideran respuestas válidas. Debes verificar response.ok o response.status tú mismo antes de procesar el cuerpo de la respuesta.
Sí, no hay conflicto. Algunos equipos usan fetch nativo para peticiones simples y Axios donde necesitan interceptores o lanzamiento automático de errores. Dicho esto, mezclar clientes HTTP añade complejidad, así que elige uno como predeterminado y usa el otro solo cuando sus características específicas sean necesarias.
Usa undici directamente cuando necesites pooling de conexiones, control detallado sobre conexiones HTTP, o máximo rendimiento para peticiones repetidas al mismo origen. Para llamadas API típicas donde la simplicidad importa más que el rendimiento bruto, el fetch global es 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.