Volver al inicio
Lección 14

Fetch API y async/await

Aprende la forma moderna de hacer peticiones HTTP y manejar código asíncrono de manera elegante con async/await.

1. Fetch API - La forma moderna

Fetch API es la forma moderna de hacer peticiones HTTP. Es mucho más simple y usa Promesas.

Ejemplo básico GET:

fetch-basico.jsjavascript
1// Con Fetch es mucho más simple
2fetch('https://jsonplaceholder.typicode.com/users/1')
3 .then(response => response.json())
4 .then(datos => {
5 console.log('Usuario:', datos);
6 })
7 .catch(error => {
8 console.log('Error:', error);
9 });

Ventajas de Fetch:

  • Sintaxis mucho más simple y limpia
  • Usa Promesas (se puede encadenar con .then)
  • Compatible con async/await
  • Más fácil manejar errores

2. ¿Qué son las Promesas?

Una Promesa es un objeto que representa una operación que todavía no ha terminado, pero que terminará en el futuro.

Puede tener 3 estados:

Pending

Esperando (aún no terminó)

Fulfilled

Completada con éxito

Rejected

Falló (error)

promesas.jsjavascript
1// Fetch devuelve una Promesa
2const promesa = fetch('https://jsonplaceholder.typicode.com/users/1');
3
4console.log(promesa); // Promise {<pending>}
5
6// Usamos .then() para cuando se complete
7promesa
8 .then(response => response.json())
9 .then(datos => {
10 console.log('✅ Datos recibidos:', datos);
11 })
12 .catch(error => {
13 console.log('❌ Error:', error);
14 });

3. async/await - Código más limpio

async/await es una forma más moderna de trabajar con Promesas. Hace que el código asíncrono se vea como código síncrono.

Sin async/await (con .then):

sin-async.jsjavascript
1fetch('https://jsonplaceholder.typicode.com/users/1')
2 .then(response => response.json())
3 .then(datos => {
4 console.log('Usuario:', datos);
5 })
6 .catch(error => {
7 console.log('Error:', error);
8 });

Con async/await (más limpio):

con-async.jsjavascript
1async function obtenerUsuario() {
2 try {
3 const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
4 const datos = await response.json();
5 console.log('Usuario:', datos);
6 } catch (error) {
7 console.log('Error:', error);
8 }
9}
10
11obtenerUsuario();

Reglas de async/await:

  • async se pone antes de la función
  • await solo funciona dentro de funciones async
  • await espera a que la Promesa se complete
  • Usa try/catch para manejar errores

4. Métodos HTTP (GET, POST, PUT, DELETE)

Los métodos HTTP indican qué tipo de operación queremos realizar en el servidor:

GET

Obtener/Leer datos del servidor

POST

Crear/Enviar datos nuevos al servidor

PUT

Actualizar/Reemplazar datos existentes

DELETE

Eliminar datos del servidor

GET - Obtener datos:

Es el método por defecto. Lee datos sin modificarlos.

fetch-get.jsjavascript
1async function obtenerUsuario() {
2 try {
3 const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
4 const usuario = await response.json();
5 console.log('Usuario obtenido:', usuario);
6 } catch (error) {
7 console.log('Error:', error);
8 }
9}

POST - Crear datos nuevos:

Envía datos al servidor para crear un nuevo recurso.

fetch-post.jsjavascript
1async function crearPost() {
2 try {
3 const nuevoPost = {
4 title: 'Mi primer post',
5 body: 'Contenido del post',
6 userId: 1
7 };
8
9 const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
10 method: 'POST',
11 headers: {
12 'Content-Type': 'application/json'
13 },
14 body: JSON.stringify(nuevoPost)
15 });
16
17 const datos = await response.json();
18 console.log('Post creado:', datos);
19 } catch (error) {
20 console.log('Error:', error);
21 }
22}

PUT - Actualizar datos existentes:

Reemplaza completamente un recurso existente.

fetch-put.jsjavascript
1async function actualizarPost() {
2 try {
3 const postActualizado = {
4 id: 1,
5 title: 'Post actualizado',
6 body: 'Contenido modificado',
7 userId: 1
8 };
9
10 const response = await fetch('https://jsonplaceholder.typicode.com/posts/1', {
11 method: 'PUT',
12 headers: {
13 'Content-Type': 'application/json'
14 },
15 body: JSON.stringify(postActualizado)
16 });
17
18 const datos = await response.json();
19 console.log('Post actualizado:', datos);
20 } catch (error) {
21 console.log('Error:', error);
22 }
23}

DELETE - Eliminar datos:

Elimina un recurso del servidor.

fetch-delete.jsjavascript
1async function eliminarPost() {
2 try {
3 const response = await fetch('https://jsonplaceholder.typicode.com/posts/1', {
4 method: 'DELETE'
5 });
6
7 console.log('Post eliminado. Status:', response.status);
8 // Status 200 o 204 indica éxito
9 } catch (error) {
10 console.log('Error:', error);
11 }
12}

¿PUT o PATCH? La diferencia importante

PUT - Actualización completa (✅ Recomendado)

  • Reemplaza el recurso completo
  • Debes enviar todos los campos del recurso
  • Ejemplo: Actualizar un post enviando title, body, userId

PATCH - Actualización parcial

  • Actualiza solo los campos que envías
  • Los demás campos se mantienen sin cambios
  • Ejemplo: Actualizar solo el title, sin tocar body ni userId

💡 Recomendación:

Usa PUT en la mayoría de casos. Es más predecible y evita inconsistencias. PATCH puede ser útil para APIs muy grandes donde enviar todo el recurso sería ineficiente, pero para APIs normales, PUT es la mejor opción.

5. Múltiples peticiones

Una después de otra (secuencial):

secuencial.jsjavascript
1async function obtenerDatos() {
2 try {
3 // Primero obtener el usuario
4 const respuestaUsuario = await fetch('https://jsonplaceholder.typicode.com/users/1');
5 const usuario = await respuestaUsuario.json();
6 console.log('Usuario:', usuario.name);
7
8 // Luego obtener sus posts
9 const respuestaPosts = await fetch('https://jsonplaceholder.typicode.com/users/1/posts');
10 const posts = await respuestaPosts.json();
11 console.log('Posts:', posts.length);
12 } catch (error) {
13 console.log('Error:', error);
14 }
15}
16
17obtenerDatos();

Todas al mismo tiempo (paralelo):

paralelo.jsjavascript
1async function obtenerTodo() {
2 try {
3 // Lanzar todas las peticiones al mismo tiempo
4 const [respuestaUsuario, respuestaPosts, respuestaTodos] = await Promise.all([
5 fetch('https://jsonplaceholder.typicode.com/users/1'),
6 fetch('https://jsonplaceholder.typicode.com/posts?userId=1'),
7 fetch('https://jsonplaceholder.typicode.com/todos?userId=1')
8 ]);
9
10 const usuario = await respuestaUsuario.json();
11 const posts = await respuestaPosts.json();
12 const todos = await respuestaTodos.json();
13
14 console.log('Usuario:', usuario.name);
15 console.log('Posts:', posts.length);
16 console.log('Todos:', todos.length);
17 } catch (error) {
18 console.log('Error:', error);
19 }
20}
21
22obtenerTodo();

Tip: Usa Promise.all() cuando las peticiones no dependan una de otra. Será mucho más rápido.

6. XMLHttpRequest vs Fetch vs async/await

XMLHttpRequest

  • • Muy verboso
  • • Callbacks anidados
  • • Difícil de leer
  • • Forma antigua

Fetch + .then

  • • Más simple
  • • Usa Promesas
  • • Puede anidar .then
  • • Mejor que XHR

async/await

  • • Muy limpio
  • • Fácil de leer
  • • Código lineal
  • • La mejor opción

Ejercicio práctico

Galería de Usuarios con Fetch y async/await

Vas a crear una aplicación web que muestre información de usuarios y sus publicaciones. Practicarás async/await para obtener datos de una API y manipulación del DOM para crear la interfaz dinámica.

1 Crear la estructura HTML

Crea un archivo index.html con esta estructura básica:

  • Un título h1 que diga "Galería de Usuarios"
  • Un botón con id cargar-btn y texto "Cargar Usuarios"
  • Un div contenedor con id usuarios-container donde aparecerán las tarjetas
  • Un tag script que importe el archivo app.js antes del cierre del body

Consejo: Puedes usar Bootstrap para estilizar las tarjetas fácilmente.

Agrega el CDN de Bootstrap en el head de tu HTML y usa clases como card, btn btn-primary, container, etc.

📚 Ver documentación de Bootstrap

2 Crear la función para obtener datos (async/await)

En app.js, crea una función async llamada cargarUsuarios():

🌐 API recomendada: DummyJSON

Una API gratuita y confiable para pruebas y prototipos

Obtener UN usuario específico:

https://dummyjson.com/users/1

→ Datos en: data.firstName, data.lastName, etc.

Obtener MÚLTIPLES usuarios (con límite):

https://dummyjson.com/users?limit=3

→ Datos en: data.users (es un array)

⚠️ Cambia limit=3 por el número que necesites (ej: limit=15 para 15 usuarios)

Posts de un usuario específico:

https://dummyjson.com/posts/user/1

→ Datos en: data.posts (es un array)

⚠️ Reemplaza el 1 por el ID del usuario

💡 Ejemplo rápido: Obtener un usuario y mostrar su nombre

ejemplo-dummyjson.jsjavascript
1async function ejemploRapido() {
2 const response = await fetch('https://dummyjson.com/users/1');
3 const data = await response.json();
4
5 // Los datos del usuario están directamente en 'data'
6 const nombreCompleto = data.firstName + ' ' + data.lastName;
7
8 // Crear y agregar un h3 al DOM
9 const titulo = document.createElement('h3');
10 titulo.textContent = nombreCompleto;
11 document.body.appendChild(titulo);
12}

2.1 Obtener usuarios

  • Usa await fetch() para obtener datos de:
    https://dummyjson.com/users?limit=3
  • Convierte la respuesta a JSON con await response.json()
  • Los datos vienen en data.users (DummyJSON usa esta estructura)

2.2 Obtener posts de cada usuario

  • Para cada usuario, obtén sus posts de:
    https://dummyjson.com/posts/user/1
    (reemplaza el 1 con el id del usuario)
  • Usa Promise.all() para hacer todas las peticiones en paralelo
  • Los posts vienen en data.posts

2.3 Manejo de errores

  • Envuelve todo el código en un bloque try/catch
  • Si hay error, muestra un mensaje en consola con console.error()

⚠️ API alternativa (si DummyJSON no funciona):

Puedes usar Dog API para mostrar razas de perros e imágenes:

  • • Lista de razas: https://dog.ceo/api/breeds/list/all
  • • Imagen aleatoria de una raza: https://dog.ceo/api/breed/shiba/images/random
  • • Múltiples imágenes: https://dog.ceo/api/breed/labrador/images/random/3

(Reemplaza "shiba" o "labrador" con cualquier raza)

3 Crear las tarjetas dinámicamente (Interfaz)

Dentro de la función cargarUsuarios(), después de obtener los datos:

3.1 Limpiar el contenedor

  • Obtén el contenedor con document.getElementById('usuarios-container')
  • Limpia su contenido con container.innerHTML = ''

3.2 Crear una tarjeta para cada usuario

  • Recorre el array de usuarios con forEach
  • Para cada usuario, crea un div con document.createElement('div')
  • Agrega una clase CSS a la tarjeta (ejemplo: 'usuario-card')

3.3 Agregar contenido a cada tarjeta

Usa innerHTML para agregar el HTML de la tarjeta. Debe mostrar:

  • Nombre del usuario en un h2 o h3 (usa usuario.firstName y usuario.lastName)
  • Email en un párrafo (usuario.email)
  • Cantidad de posts (usa posts.length)
  • Títulos de los primeros 3 posts en divs o en una lista (usa posts.slice(0, 3) y post.title)

3.4 Agregar la tarjeta al contenedor

  • Usa container.appendChild(card) para agregar cada tarjeta

4 Conectar el botón con la función

  • Al final de app.js, obtén el botón con document.getElementById('cargar-btn')
  • Agrega un event listener con addEventListener('click', cargarUsuarios)
  • ¡Prueba tu aplicación! Haz clic en el botón y deberían aparecer las tarjetas

Tip: Usa concatenación de strings o template literals para construir el HTML dentro de innerHTML

Extra: Puedes agregar un mensaje de "Cargando..." mientras se obtienen los datos

Resumen

Fetch API es la forma moderna de hacer peticiones HTTP
Promesas representan operaciones asíncronas (pending, fulfilled, rejected)
async/await hace el código asíncrono más limpio y fácil de leer
Usa try/catch para manejar errores con async/await
Promise.all() ejecuta múltiples peticiones en paralelo
async/await es la mejor forma de trabajar con código asíncrono en JavaScript moderno