APIs para principiantes: Tu primera llamada fetch() con JavaScript

Conecta tu página web con el mundo exterior: trae datos reales de internet y crea aplicaciones que realmente funcionan

¿Has visto páginas que muestran el clima actual, noticias en tiempo real, o datos de redes sociales? Eso se hace con APIs. Y si ya sabes manipular el DOM, estás listo para el siguiente nivel: traer datos de internet.

En este tutorial vas a aprender a conectar tu página web con servicios reales y crear aplicaciones que realmente impresionan. Sin trucos, sin complicaciones técnicas.

1 línea Para traer datos de internet
∞ posibilidades Miles de APIs gratis disponibles
Real-time Datos actualizados al instante
Profesional Como las apps que usas diariamente

🤔 ¿Qué es una API (explicado sin tecnicismos)?

Una API es como un camarero en un restaurante. Tú (tu página web) le pides algo al camarero (la API), y él va a la cocina (el servidor) y te trae lo que pediste.

🍕

Restaurante normal

Tú: "Quiero una pizza"
Camarero: Va a la cocina
Resultado: Te trae tu pizza

🌐

API en internet

Tu página: "Quiero el clima de Madrid"
API: Va al servidor de clima
Resultado: Te trae "22°C, soleado"

🎯 ¿Por qué necesitas APIs?

📊 Datos reales

En lugar de mostrar "22°C" hardcodeado, muestras la temperatura REAL de ahora mismo.

🔄 Contenido dinámico

Tu página se actualiza sola. Como Instagram que carga nuevas fotos sin que recargues.

🚀 Apps profesionales

La diferencia entre una página de práctica y una aplicación real que la gente usaría.

🛠️ fetch(): Tu nueva herramienta mágica

fetch() es la función de JavaScript que te permite "ir a buscar" datos de internet. Es como un mensajero súper rápido que trae lo que le pidas.

🏗️ Estructura básica (sin miedo):

Sintaxis básica de fetch()
fetch('https://api-example.com/datos')
  .then(response => response.json())
  .then(data => {
    // Aquí ya tienes los datos para usar
    console.log(data);
  });

📋 Paso a paso:

1
fetch('url')

Le dices a JavaScript: "ve a esta dirección y trae lo que hay"

2
.then(response => response.json())

Conviertes la respuesta en datos que JavaScript entiende

3
.then(data => { ... })

¡Ya puedes usar los datos! Los muestras, los guardas, lo que quieras

🚀 Proyecto práctico: Ejemplos que funcionan

Vamos con ejemplos reales. Cada uno más interesante que el anterior.

📝 Nivel 1: Tu primera llamada API

Empezamos con algo simple: traer una cita inspiracional random.

🎮 Demo interactivo:

Haz clic para obtener una cita inspiracional

Cargando...

👆 Datos reales desde internet

🛡️ SEGURIDAD IMPORTANTE: ¡No uses innerHTML con APIs!

El código de abajo tiene una vulnerabilidad XSS grave. Lo mostramos para que aprendas qué NO hacer:

❌ INSEGURO (no copies esto):
Código inseguro - NO usar
display.innerHTML = `<p>"${data.text}"</p>`; // ⚠️ XSS vulnerable!

¿Por qué es peligroso? Si la API devuelve algo como <script>alert('hack')</script>, se ejecutará en tu página.

JavaScript SEGURO (úsalo así):

Implementación completa y segura de fetch
// 1. Encontrar elementos
const boton = document.querySelector('#quote-btn');
const display = document.querySelector('#quote-display');

// 2. Función para obtener cita
async function obtenerCita() {
    try {
        const response = await fetch('https://thequoteshub.com/api/');
        const data = await response.json();

        // 3. Crear elementos DOM de forma SEGURA
        display.replaceChildren(); // Limpiar

        const quoteText = document.createElement('p');
        quoteText.className = 'quote-text';
        quoteText.textContent = `"${data.text}"`;

        const quoteAuthor = document.createElement('p');
        quoteAuthor.className = 'quote-author';
        quoteAuthor.textContent = `- ${data.author}`;

        // 4. Agregar al DOM
        display.appendChild(quoteText);
        display.appendChild(quoteAuthor);

    } catch (error) {
        display.replaceChildren();
        const errorMsg = document.createElement('p');
        errorMsg.textContent = 'Error: No se pudo obtener la cita';
        display.appendChild(errorMsg);
    }
}

// 5. Escuchar el click
boton.addEventListener('click', obtenerCita);

🤓 ¿Por qué este código es SEGURO?

  1. createElement(): Crea elementos HTML de forma segura
  2. textContent: Inserta SOLO texto, nunca ejecuta HTML/JS
  3. replaceChildren(): Limpia el contenedor sin vulnerabilidades
  4. appendChild(): Agrega elementos de forma controlada

Resultado: Aunque la API devuelva <script>, se mostrará como texto inofensivo.

⚠️ ¡MUY IMPORTANTE! Las claves del JSON

Cada API devuelve un JSON con claves específicas. Si usas la clave equivocada, obtienes undefined.

❌ Esta API devuelve:
Estructura de respuesta JSON de la API
{
  "text": "La vida es lo que pasa...",
  "author": "John Lennon",
  "id": 12345
}
✅ Por eso usamos:
Acceso correcto e incorrecto a propiedades
data.text    // ✅ Correcto
data.author  // ✅ Correcto

data.content // ❌ undefined!
data.quote   // ❌ undefined!

Regla de oro: Siempre revisa la documentación de la API o prueba la respuesta con console.log(data) primero.

🔍 DOMINAR DATOS JSON COMPLEJOS: Acceso a arrays y objetos anidados

El reto real de las APIs: Las respuestas no son simples. Son estructuras complejas con arrays dentro de objetos, objetos dentro de arrays, y múltiples niveles de anidación.

💪 Lo que vas a dominar aquí:

  • Acceder a propiedades dentro de objetos anidados
  • Navegar arrays que contienen objetos
  • Manejar estructuras de datos de múltiples niveles
  • Evitar errores de "undefined" al acceder a propiedades

📦 Anatomía de una respuesta JSON real

Ejemplo de respuesta típica de una API de clima:

Ejemplo de respuesta JSON compleja con objetos y arrays anidados
{
  "coord": {
    "lon": -3.7038,
    "lat": 40.4168
  },
  "weather": [
    {
      "id": 800,
      "main": "Clear",
      "description": "cielo claro",
      "icon": "01d"
    }
  ],
  "main": {
    "temp": 22.5,
    "feels_like": 21.8,
    "humidity": 45
  },
  "sys": {
    "country": "ES",
    "sunrise": 1692772892
  },
  "name": "Madrid"
}

🎯 PASO A PASO: Cómo acceder a cada propiedad

1
Propiedades simples (nivel 1)
Acceso a propiedades simples
data.name        // "Madrid"

Regla: Usa el punto (.) para acceder a propiedades directas

2
Objetos anidados (nivel 2)
Acceso a objetos anidados
data.coord.lon     // -3.7038
data.coord.lat     // 40.4168
data.main.temp     // 22.5
data.sys.country  // "ES"

Regla: Encadena puntos para "navegar" dentro de objetos

3
Arrays con objetos (nivel 2+)
Acceso a arrays con objetos
data.weather           // El array completo
data.weather[0]       // El primer elemento del array
data.weather[0].main // "Clear"
data.weather[0].description // "cielo claro"

Regla: Usa [0] para acceder al primer elemento, [1] al segundo, etc.

⚠️ ERRORES COMUNES y cómo evitarlos

Error #1: Array vacío

❌ Problema:
Código problemático - Acceso sin verificar
data.weather[0].main // Error si weather está vacío!
✅ Solución SEGURA:
Verificación segura de arrays
// Verificar si existe y tiene elementos
if (data.weather && data.weather.length > 0) {
    const weatherMain = data.weather[0].main;
}

// O usando operador opcional (?)
const weatherMain = data.weather?.[0]?.main || 'No disponible';

Error #2: Propiedad inexistente

❌ Problema:
Código problemático - Propiedad no verificada
data.main.pressure // undefined si no existe
✅ Solución SEGURA:
Verificación segura de propiedades
// Verificar antes de usar
const pressure = data.main.pressure || 'No disponible';

// O con operador opcional
const pressure = data.main?.pressure ?? 'No disponible';

🎮 PRÁCTICA: Ejemplo con GitHub API (datos reales y complejos)

La API de GitHub devuelve datos MUY anidados. Perfecto para practicar:

{
  "login": "octocat",
  "id": 1,
  "avatar_url": "https://github.com/images/error/octocat_happy.gif",
  "name": "The Octocat",
  "company": "@github",
  "public_repos": 8,
  "followers": 4008,
  "following": 9,
  "created_at": "2011-01-25T18:44:36Z",
  "plan": {
    "name": "pro",
    "space": 976562499,
    "private_repos": 9999
  }
}

📝 Cómo extraer cada dato:

Extracción de datos de la respuesta de GitHub
// ✅ Datos simples
const username = data.login;           // "octocat"
const realName = data.name;            // "The Octocat"
const followers = data.followers;       // 4008

// ✅ Objeto anidado
const planName = data.plan.name;        // "pro"
const planSpace = data.plan.space;      // 976562499

// ✅ Acceso SEGURO (por si plan no existe)
const safePlanName = data.plan?.name || 'No tiene plan';

🚀 CASO PRÁCTICO: API con arrays de objetos complejos

Ejemplo real de una API de posts con comentarios:

Estructura compleja: API con arrays de objetos anidados
{
  "posts": [
    {
      "id": 1,
      "title": "Mi primer post",
      "author": {
        "name": "Juan Pérez",
        "avatar": "https://example.com/juan.jpg",
        "social": {
          "twitter": "@juanperez",
          "github": "juanperez"
        }
      },
      "comments": [
        {
          "id": 101,
          "text": "¡Excelente post!",
          "author": {
            "name": "María García"
          }
        },
        {
          "id": 102,
          "text": "Muy útil, gracias",
          "author": {
            "name": "Carlos López"
          }
        }
      ]
    }
  ]
}

🎯 ACCESO PASO A PASO a esta estructura compleja:

Acceso paso a paso a estructura compleja
// 1. ✅ Obtener el primer post
const firstPost = data.posts[0];

// 2. ✅ Datos del post
const postTitle = firstPost.title;                    // "Mi primer post"

// 3. ✅ Autor del post (objeto anidado)
const authorName = firstPost.author.name;          // "Juan Pérez"

// 4. ✅ Social del autor (objeto anidado dentro de otro objeto)
const authorTwitter = firstPost.author.social.twitter; // "@juanperez"

// 5. ✅ Primer comentario
const firstComment = firstPost.comments[0];
const commentText = firstComment.text;              // "¡Excelente post!"

// 6. ✅ Autor del comentario
const commentAuthor = firstComment.author.name;      // "María García"

🔄 Recorrer TODOS los comentarios (bucles con datos anidados):

Recorrer arrays de forma segura
// ✅ Mostrar todos los comentarios del primer post
firstPost.comments.forEach((comment, index) => {
    console.log(`Comentario ${index + 1}:`);
    console.log(`- ${comment.text}`);
    console.log(`- Por: ${comment.author.name}`);
});

// ✅ Versión SEGURA (por si no hay comentarios)
if (firstPost.comments && firstPost.comments.length > 0) {
    firstPost.comments.forEach(comment => {
        // Procesar comentarios de forma segura
        const authorName = comment.author?.name || 'Anónimo';
        console.log(`${comment.text} - ${authorName}`);
    });
} else {
    console.log('No hay comentarios en este post');
}

🎯 REGLAS DE ORO para datos JSON complejos:

  1. console.log(data) primero: Siempre imprime la respuesta completa para ver su estructura
  2. Navega paso a paso: Ve de lo general (data) a lo específico (data.posts[0].author.name)
  3. Verifica antes de acceder: Usa && para verificar que exista, o ?. para acceso opcional
  4. Siempre maneja arrays vacíos: Verifica .length > 0 antes de usar [0]
  5. Usa valores por defecto: Operador || para tener fallbacks como 'No disponible'

💡 Herramientas para debuggear JSON complejo

🔍 En el navegador:

Herramientas de debugging en el navegador
// Inspeccionar estructura completa
console.log('API Response:', data);

// Ver claves disponibles
console.log('Keys:', Object.keys(data));

// Verificar tipo
console.log('Es array?', Array.isArray(data));

🛠️ Chrome DevTools:

  • F12 → Console
  • Network → XHR para ver llamadas
  • Click en respuesta → Preview tab
  • Expandir objetos para navegar

📝 Nivel 2: Buscador de usuarios de GitHub

Ahora algo más útil: buscar perfiles reales de GitHub.

🎮 Demo interactivo:

Busca cualquier usuario de GitHub (ej: octocat, torvalds, gaearon)

Buscando usuario...

HTML necesario:

HTML para el buscador de GitHub
<input type="text" id="github-input" placeholder="Usuario de GitHub...">
<button id="github-btn">Buscar</button>
<div id="github-result"></div>

🛡️ Ejemplo GitHub: Versión SEGURA

El siguiente código muestra la forma segura de crear elementos dinámicos:

JavaScript SEGURO para GitHub:

Obtener datos del usuario de GitHub
const input = document.querySelector('#github-input');
const boton = document.querySelector('#github-btn');
const resultado = document.querySelector('#github-result');

async function buscarUsuario() {
    const username = input.value.trim();
    
    // Validación SEGURA
    if (username === '') {
        resultado.replaceChildren();
        const errorMsg = document.createElement('p');
        errorMsg.textContent = 'Por favor escribe un nombre de usuario';
        resultado.appendChild(errorMsg);
        return;
    }
    
    // Loading SEGURO
    resultado.replaceChildren();
    const loading = document.createElement('p');
    loading.textContent = 'Buscando...';
    resultado.appendChild(loading);
    
    try {
        const response = await fetch(`https://api.github.com/users/${username}`);
        
        if (!response.ok) {
            throw new Error('Usuario no encontrado');
        }
        
        const data = await response.json();
        
        // Crear tarjeta SEGURA
        resultado.replaceChildren();
        
        const userCard = document.createElement('div');
        userCard.className = 'user-card';
        
        const avatar = document.createElement('img');
        avatar.src = data.avatar_url; // Seguro: propiedad directa
        avatar.alt = 'Avatar';
        avatar.className = 'avatar';
        
        const name = document.createElement('h3');
        name.textContent = data.name || data.login; // Seguro: solo texto
        
        userCard.appendChild(avatar);
        userCard.appendChild(name);
        // ... más elementos
        
        resultado.appendChild(userCard);
        
    } catch (error) {
        resultado.replaceChildren();
        const errorMsg = document.createElement('p');
        errorMsg.textContent = `${error.message}`;
        resultado.appendChild(errorMsg);
    }
}

boton.addEventListener('click', buscarUsuario);

📝 Nivel 3: App del clima (como los profesionales)

El clásico: una app que muestra el clima actual de cualquier ciudad.

🎮 Demo interactivo:

Prueba con: Madrid, Barcelona, Buenos Aires, Ciudad de México

🛡️ Clima SEGURO: Sin innerHTML

Ejemplo profesional usando createElement() para máxima seguridad:

JavaScript SEGURO del clima:

App del clima completa y segura
// API key gratuita (en producción, mantén esto secreto)
const API_KEY = 'TU_API_KEY_AQUI';
const BASE_URL = 'https://api.openweathermap.org/data/2.5/weather';

async function obtenerClima() {
    const ciudad = document.querySelector('#city-input').value.trim();
    const resultado = document.querySelector('#weather-result');
    
    if (ciudad === '') return;
    
    // Loading SEGURO
    resultado.replaceChildren();
    const loading = document.createElement('p');
    loading.textContent = 'Obteniendo clima...';
    resultado.appendChild(loading);
    
    try {
        const url = `${BASE_URL}?q=${ciudad}&appid=${API_KEY}&units=metric&lang=es`;
        const response = await fetch(url);
        
        if (!response.ok) {
            throw new Error('Ciudad no encontrada');
        }
        
        const data = await response.json();
        
        // Crear weather card de forma SEGURA
        resultado.replaceChildren();
        
        const weatherCard = document.createElement('div');
        weatherCard.className = 'weather-card';
        
        const title = document.createElement('h3');
        title.textContent = `🌍 ${data.name}, ${data.sys.country}`;
        
        const temperature = document.createElement('div');
        temperature.className = 'temperature';
        temperature.textContent = `${Math.round(data.main.temp)}°C`;
        
        const description = document.createElement('p');
        description.className = 'description';
        description.textContent = data.weather[0].description;
        
        // Ensamblar elementos
        weatherCard.appendChild(title);
        weatherCard.appendChild(temperature);
        weatherCard.appendChild(description);
        
        resultado.appendChild(weatherCard);
        
    } catch (error) {
        resultado.replaceChildren();
        const errorMsg = document.createElement('p');
        errorMsg.textContent = `${error.message}`;
        resultado.appendChild(errorMsg);
    }
}

⚠️ Errores comunes con APIs (y cómo solucionarlos)

🎯 Resumen de seguridad:

En este tutorial has aprendido a usar métodos DOM seguros:

  • createElement() en lugar de innerHTML
  • textContent en lugar de insertar HTML
  • replaceChildren() para limpiar contenedores
  • appendChild() para construir elementos

Resultado: Código 100% seguro contra XSS 🛡️

Error #1: No manejar errores

❌ Malo:
Código problemático sin manejo de errores
fetch(url).then(data => {
    // ¿Y si falla?
});
✅ Bueno:
Manejo correcto de errores
fetch(url)
  .then(data => {/* éxito */})
  .catch(error => {/* error */});

Por qué: Las APIs pueden fallar. Internet puede fallar. Siempre maneja errores.

Error #2: No verificar response.ok

❌ Problema:
Error: No verificar response.ok
fetch(url)
  .then(response => response.json()) // ¡Error 404!
✅ Solución:
Verificación correcta de response.ok
fetch(url)
  .then(response => {
    if (!response.ok) throw new Error('Error HTTP');
    return response.json();
  })

Por qué: fetch() no rechaza automáticamente códigos 404, 500, etc.

Error #3: API keys expuestas

❌ Peligroso:
PELIGRO: API key expuesta en frontend
// En el frontend, visible para todos
const apiKey = 'sk-1234567890abcdef';
✅ Seguro:
Alternativas seguras para API keys
// Usar APIs públicas sin key, o
// Hacer llamadas desde tu backend

Por qué: Cualquiera puede ver tu API key y usarla (y cobrarte).

Error #4: No mostrar estados de carga

❌ Malo:
Sin feedback visual de carga
// Usuario hace click... ¿pasa algo?
fetch(url).then(...);
✅ Bueno:
Con feedback visual de carga
button.textContent = 'Cargando...';
fetch(url).then(...);

Por qué: Las APIs pueden tardar. El usuario necesita feedback visual.

🎯 APIs gratis para principiantes

Estas APIs no requieren registro y puedes usarlas ahora mismo:

🎭 Random Quotes

https://thequoteshub.com/api/

Citas célebres aleatorias. La que usamos en este tutorial.

🐕 Dog Photos

https://dog.ceo/api/breeds/image/random

Fotos random de perritos. ✅ Funciona perfectamente.

📊 Datos de Prueba

https://httpbin.org/uuid

Genera UUID únicos. Perfecta para IDs aleatorios.

😂 Chuck Norris Facts

https://api.chucknorris.io/jokes/random

Chistes de Chuck Norris. ✅ Funciona y garantiza risas.

🏛️ GitHub API

https://api.github.com/users/octocat

Datos públicos de usuarios. ✅ Perfecta para portfolios.

🌐 APIs Públicas

https://httpbin.org/json

Datos JSON de prueba. Siempre disponible para testing.

🚀 Proyecto completo: Explorador de APIs

Vamos a crear una mini-aplicación que combine múltiples APIs:

🎮 Demo final - Mini Dashboard:

Haz clic en cualquier botón para traer contenido desde diferentes APIs

🏆 Desafío final:

¿Puedes crear tu propia versión? Intenta agregar:

  • ✅ Una API diferente (clima, noticias, etc.)
  • ✅ Botón para guardar favoritos en localStorage
  • ✅ Contador de cuántas veces has usado cada API
  • ✅ Animaciones cuando cargue el contenido

💡 async/await: La forma moderna

Una vez que domines fetch() básico, puedes usar async/await para código más limpio:

📜 Forma tradicional (.then)

Método tradicional con .then()
fetch(url)
  .then(response => response.json())
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error(error);
  });

✨ Forma moderna (async/await)

Método moderno con async/await
async function obtenerDatos() {
  try {
    const response = await fetch(url);
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

¿Cuál usar? Para empezar, domina .then(). Luego aprende async/await. Ambas hacen lo mismo, pero async/await es más fácil de leer.

🎯 ¿Qué sigue después de las APIs?

¡Enhorabuena! Ya sabes conectar tu página web con el mundo real. Tus siguientes pasos:

🏗️

Proyectos completos

Lista de tareas con backend, chat en tiempo real, dashboard personal.

🔐

Autenticación

Login, registro, sesiones. Crear apps solo para usuarios registrados.

📱

Progressive Web Apps

Hacer que tu web funcione como una app nativa del teléfono.

💡 Consejos de desarrollador profesional

🎯 Para dominar APIs:

  • Practica con APIs gratuitas primero
  • Lee siempre la documentación
  • Usa Postman para probar antes de programar
  • Siempre maneja errores
  • Muestra estados de carga

🎯 Herramientas útiles:

  • Chrome DevTools → Network tab
  • Postman para probar APIs
  • JSONFormatter para leer respuestas
  • Public APIs list en GitHub
  • Thunder Client para VS Code

🎯 Proyectos para practicar:

  • App del clima de tu ciudad
  • Buscador de GIFs
  • Generador de memes
  • Dashboard de crypto precios
  • Buscador de recetas