Skip to content

Unidad 3: Trabajo con APIs y Datos Externos

Objetivo: Aprender a consumir APIs externas y manejar datos en el frontend, utilizando fetch(), JSON y promesas para realizar operaciones asíncronas.


3.1 Introducción a fetch() y Consumo de APIs REST

¿Qué vamos a aprender?

En esta sección aprenderemos a realizar peticiones HTTP a una API utilizando fetch(). Veremos cómo obtener datos (GET), enviar información (POST) y manejar respuestas de manera asíncrona con async/await.

Peticiones GET y POST con fetch

A continuación, se muestra un ejemplo de cómo realizar una petición GET a una API pública y cómo enviar datos con POST:

Ejemplo de una petición GET a una API pública

1
2
3
4
fetch("https://jsonplaceholder.typicode.com/posts")
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error("Error al obtener datos", error));
En este ejemplo, realizamos una petición GET para obtener datos de una API pública y los mostramos en la consola.

Importante la propiedad headers en la petición POST para especificar el tipo de contenido, y body para enviar los datos. La propiedad headers usualmete utiliza:

  • Content-Type: application/json para enviar datos en formato JSON.
  • Content-Type: text/plain para enviar datos en texto plano.
  • Content-Type: application/xml para enviar datos en formato XML.

Ejemplo de una petición POST enviando datos

fetch("https://jsonplaceholder.typicode.com/posts", {
    method: "POST",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify({
        title: "Nuevo Post",
        body: "Este es el contenido del post",
        userId: 1
    })
})
.then(response => response.json())
.then(data => console.log("Post creado:", data))
.catch(error => console.error("Error en la petición POST", error));
Aquí enviamos un nuevo post a la API con POST y mostramos la respuesta.

Para eliminar datos, se utiliza el método DELETE en la petición. La propiedad method en la petición fetch() se utiliza para especificar el tipo de petición HTTP. Un ejemlo de petición DELETE sería:

Ejemplo de una petición DELETE

1
2
3
4
5
fetch("https://jsonplaceholder.typicode.com/posts/1", {
    method: "DELETE"
})
.then(response => console.log("Post eliminado:", response))
.catch(error => console.error("Error al eliminar post", error));

Uso de async/await en llamadas a APIs

async/await es una forma más moderna y legible de trabajar con operaciones asíncronas en JavaScript. A continuación, se muestra un ejemplo de cómo obtener datos de una API utilizando async/await:

Ejemplo con async/await

async function obtenerPosts() {
    try {
        let response = await fetch("https://jsonplaceholder.typicode.com/posts");
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.error("Error al obtener los posts", error);
    }
}
obtenerPosts();
async/await nos permite escribir código más limpio y fácil de entender cuando trabajamos con operaciones asíncronas.

Podemos utilizar async/await en peticiones POST y DELETE de la misma manera que en el ejemplo anterior.

Ejemplo con async/await en una petición POST

async function crearPost() {
    try {
        let response = await fetch("https://jsonplaceholder.typicode.com/posts", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ title: "Nuevo Post", body: "Contenido del post", userId: 1 })
        });
        let data = await response.json();
        console.log("Post creado:", data);
    } catch (error) {
        console.error("Error al crear el post", error);
    }
}
crearPost();
En este ejemplo, creamos un nuevo post con async/await y manejamos la respuesta.

Ejercicios

Practica con fetch()

  1. Realiza una petición GET a https://jsonplaceholder.typicode.com/users y muestra los usuarios en consola.
  2. Envía un POST con tu propio usuario a la misma API y muestra la respuesta.
Solución
// Solución Ejercicio 1
fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error("Error al obtener usuarios", error));

// Solución Ejercicio 2
fetch("https://jsonplaceholder.typicode.com/users", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ nombre: "Alumno", email: "alumno@example.com" })
})
.then(response => response.json())
.then(data => console.log("Usuario creado:", data))
.catch(error => console.error("Error al crear usuario", error));

3.2 Uso de JSON y Promesas en el Frontend

¿Qué vamos a aprender?

En esta sección aprenderemos a convertir datos entre JSON y objetos de JavaScript, y a manejar operaciones asíncronas con promesas.

Conversión entre JSON y objetos JavaScript

Conversión entre JSON y JavaScript

let usuario = {
    nombre: "Carlos",
    edad: 25,
    ciudad: "Madrid"
};

let usuarioJSON = JSON.stringify(usuario);
console.log(usuarioJSON); // Convierte objeto a JSON

let usuarioObjeto = JSON.parse(usuarioJSON);
console.log(usuarioObjeto); // Convierte JSON a objeto
JSON.stringify() convierte un objeto en JSON y JSON.parse() hace lo contrario.

Promesas (.then(), .catch()) y su importancia en operaciones asíncronas

Las promesas son una forma de trabajar con operaciones asíncronas en JavaScript. Nos permiten manejar el éxito o error de una operación y encadenar múltiples operaciones asíncronas.

Ejemplo de una Promesa

function obtenerDatos() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            let exito = true;
            if (exito) resolve("Datos obtenidos correctamente");
            else reject("Error al obtener datos");
        }, 2000);
    });
}

obtenerDatos()
    .then(mensaje => console.log(mensaje))
    .catch(error => console.error(error));
En este ejemplo, la promesa simula la obtención de datos después de 2 segundos y maneja el éxito o error.

Ejercicios

Practica con JSON y Promesas

  1. Crea una función que convierta un objeto a JSON y lo muestre en consola.
  2. Escribe una promesa que simule una petición a una API y resuelva con datos después de 3 segundos.
Solución
// Solución Ejercicio 1
let objeto = { nombre: "Carlos", edad: 25 };
console.log(JSON.stringify(objeto));

// Solución Ejercicio 2
function simularAPI() {
    return new Promise((resolve) => {
        setTimeout(() => resolve("Datos cargados"), 3000);
    });
}
simularAPI().then(mensaje => console.log(mensaje));

3.3 Manejo de Errores y Respuestas de APIs

¿Qué vamos a aprender?

Aprenderemos a manejar errores al trabajar con APIs y a validar respuestas HTTP.

Uso de try...catch

Ejemplo de try...catch en fetch()

async function obtenerDatos() {
    try {
        let response = await fetch("https://jsonplaceholder.typicode.com/invalid-url");
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.error("Error en la petición", error);
    }
}
obtenerDatos();
Si la URL no es válida, catch manejará el error.

Manejo de errores HTTP (.ok, status)

Verificación del estado de respuesta

async function obtenerUsuarios() {
    try {
        let response = await fetch("https://jsonplaceholder.typicode.com/users");
        if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.error("Error en la petición", error);
    }
}
obtenerUsuarios();
Si el estado HTTP no es 200, lanzamos un error personalizado.

Ejercicios

Práctica con Manejo de Errores

  1. Modifica una petición fetch() para que valide el estado HTTP antes de procesar los datos. Utiliza la URL https://jsonplaceholder.typicode.com/users.
  2. Captura el error si fetch() no puede conectarse a la API y muestra un mensaje en consola. Utiliza la URL https://jsonplaceholder.typicode.com/invalid-url.
Solución

``javascript linenums="1" // Solución Ejercicio 1 async function obtenerUsuarios() { try { let response = await fetch("https://jsonplaceholder.typicode.com/users"); if (!response.ok) throw new Error(HTTP error! Status: ${response.status}`); let data = await response.json(); console.log(data); } catch (error) { console.error("Error en la petición", error); } } obtenerUsuarios();

// Solución Ejercicio 2 async function peticionInvalida() { try { let response = await fetch("https://jsonplaceholder.typicode.com/invalid-url"); if (!response.ok) throw new Error(HTTP error! Status: ${response.status}); let data = await response.json(); console.log(data); } catch (error) { console.error("No se pudo conectar a la API", error); } } peticionInvalida();


Unidad 3: Trabajo con APIs y Datos Externos

📌 Objetivo: Aprender a consumir APIs externas y manejar datos en el frontend, utilizando fetch(), JSON y promesas para realizar operaciones asíncronas.


3.4 Proyecto Final: Aplicación de Gestión de Posts

Objetivo

Construir una aplicación web que permita gestionar posts obtenidos desde una API. La aplicación mostrará los posts en una tabla interactiva, permitirá visualizar el contenido en una ventana modal, eliminar posts, y añadir nuevos posts desde un formulario.

Requisitos

Cargar los posts desde una API (https://jsonplaceholder.typicode.com/posts) y mostrarlos en una tabla.
Cada post debe tener: un ID, título y un botón para visualizar el contenido en una modal.
Cada post tendrá un botón de eliminar que lo eliminará de la tabla.
Formulario en la parte superior para agregar nuevos posts.
Los nuevos posts deben aparecer en la tabla sin necesidad de recargar la página.


Estructura base del HTML

Estructura base del HTML

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Gestión de Posts</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <h1>Gestión de Posts</h1>

    <form id="post-form">
        <input type="text" id="titulo" placeholder="Título" required>
        <textarea id="contenido" placeholder="Contenido" required></textarea>
        <button type="submit">Añadir Post</button>
    </form>

    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Título</th>
                <th>Acciones</th>
            </tr>
        </thead>
        <tbody id="post-list"></tbody>
    </table>

    <div id="modal" class="modal">
        <div class="modal-content">
            <span class="close">&times;</span>
            <h2 id="modal-title"></h2>
            <p id="modal-body"></p>
        </div>
    </div>

    <script src="app.js"></script>
</body>
</html>
Este archivo define la estructura de la aplicación con:

  • Formulario para añadir posts.
  • Tabla donde se mostrarán los posts.
  • Modal para visualizar el contenido de un post.

Estructura del app.js

El archivo app.js contendrá las funciones necesarias para manejar los posts. Se proporcionará el código con funciones vacías para que los alumnos las completen.

Estructura base del app.js con funciones a completar

document.addEventListener("DOMContentLoaded", () => {
    cargarPosts();
});

async function cargarPosts() {
    // TODO: Obtener los posts desde la API y mostrarlos en la tabla.
}

function agregarPost(event) {
    event.preventDefault();
    // TODO: Obtener los datos del formulario y agregar el nuevo post a la tabla.
}

function eliminarPost(id) {
    // TODO: Eliminar un post de la tabla.
}

function mostrarPost(id) {
    // TODO: Mostrar el contenido de un post en la ventana modal.
}

document.getElementById("post-form").addEventListener("submit", agregarPost);
Explicación de las funciones:

  • cargarPosts(): Obtiene los posts de la API y los muestra en la tabla.
  • agregarPost(event): Captura los datos del formulario y agrega un nuevo post a la tabla.
  • eliminarPost(id): Elimina el post correspondiente de la tabla.
  • mostrarPost(id): Muestra el contenido de un post en la ventana modal.

Pasos para la Implementación

1️⃣ Cargar los posts desde la API y listarlos en la tabla.
2️⃣ Completar la función agregarPost() para permitir añadir nuevos posts.
3️⃣ Implementar eliminarPost() para borrar posts de la tabla.
4️⃣ Desarrollar mostrarPost() para mostrar el contenido en una modal.
5️⃣ Estilizar la aplicación con CSS para mejorar la apariencia.

Solución al proyecto

Presentamos una posible solución al proyecto final.

Código completo de app.js
document.addEventListener("DOMContentLoaded", () => {
    cargarPosts();
});

async function cargarPosts() {
    try {
        let response = await fetch("https://jsonplaceholder.typicode.com/posts");
        let data = await response.json();
        mostrarPosts(data.slice(0, 10)); // Mostramos solo los primeros 10
    } catch (error) {
        console.error("Error al cargar los posts", error);
    }
}

function mostrarPosts(posts) {
    let postList = document.getElementById("post-list");
    postList.innerHTML = "";
    posts.forEach(post => {
        let row = document.createElement("tr");
        row.innerHTML = `
            <td>${post.id}</td>
            <td>${post.title}</td>
            <td>
                <button onclick="mostrarPost(${post.id}, '${post.title}', '${post.body}')">Ver</button>
                <button onclick="eliminarPost(this)">Eliminar</button>
            </td>
        `;
        postList.appendChild(row);
    });
}

function agregarPost(event) {
    event.preventDefault();
    let titulo = document.getElementById("titulo").value;
    let contenido = document.getElementById("contenido").value;
    if (!titulo || !contenido) return;
    let postList = document.getElementById("post-list");
    let row = document.createElement("tr");
    row.innerHTML = `
        <td>Nuevo</td>
        <td>${titulo}</td>
        <td>
            <button onclick="mostrarPost('Nuevo', '${titulo}', '${contenido}')">Ver</button>
            <button onclick="eliminarPost(this)">Eliminar</button>
        </td>
    `;
    postList.appendChild(row);
    document.getElementById("post-form").reset();
}

function eliminarPost(button) {
    let row = button.parentElement.parentElement;
    row.remove();
}

function mostrarPost(id, title, body) {
    document.getElementById("modal-title").textContent = title;
    document.getElementById("modal-body").textContent = body;
    document.getElementById("modal").style.display = "block";
}

document.getElementById("post-form").addEventListener("submit", agregarPost);
document.querySelector(".close").addEventListener("click", () => {
    document.getElementById("modal").style.display = "none";
});

Explicación de la solución:

  • cargarPosts(): Obtiene los posts de la API y muestra los primeros 10.
  • mostrarPosts(posts): Llena la tabla con los posts obtenidos.
  • agregarPost(event): Captura los datos del formulario y agrega un nuevo post.
  • eliminarPost(button): Elimina la fila de la tabla.
  • mostrarPost(id, title, body): Muestra el contenido de un post en la ventana modal.