Guía 09: Promesas, XML y JSON#
Actividades previas#
HTTP: Requerimientos y respuestas#
Visite el sitio web de ReqBin.
Realice las siguientes peticiones HTTP, p.e.:
Petición GET de los productos:
URL: https://data-dawm.github.io/datum/reseller/products.json
Método: GET
Petición GET de las categorías:
URL: https://data-dawm.github.io/datum/reseller/categories.xml
Método: GET
Explore la petición HTTP y la respuesta HTTP en la interfaz.
Utilice un cliente de IAG para explicar cómo se estructura la petición y la respuesta de la API; además de los formatos JSON y XML.
Ambiente de desarrollo#
Acceda a su proyecto landing en Codespaces o en su máquina local.
Cree y utilice la(s) rama(s) de desarrollo.
Instale los paquetes y levante el servidor, con:
npm install npm run dev
Actividades en clases#
HTML#
En el documento index.html, agregue una sección para mostrar los datos obtenidos de los productos y sus categorías.
Ver el código
<section class="bg-slate-50 dark:bg-gray-900"> ... </section> <section class="bg-slate-50 dark:bg-gray-900"> <div id="container-05" class="px-4 pt-8 mx-auto max-w-md md:max-w-xl"> <div class="grid grid-cols-1 gap-4 md:grid-cols-1"> <h2 class="text-4xl font-extrabold tracking-tight text-gray-900 dark:text-white text-center">Productos más vendidos</h2> </div> </div> <div id="container-06" class="max-w-4xl pt-8 mx-auto"> <form class="max-w-sm mx-auto"> <select id="categories" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"> <option selected>Seleccione una categoría</option> <option value="1">Category01</option> <option value="2">Category02</option> <option value="3">Category03</option> </select> </form> </div> <div id="container-07" class="max-w-4xl pt-5 pb-5 mx-auto"> <div id="products-container" class="grid grid-cols-1 md:grid-cols-3 gap-3 p-6"> <!-- Products Card --> <div class="animate-pulse space-y-4 bg-white dark:bg-gray-800 p-4 rounded-2xl shadow"> <div class="w-full h-40 bg-gray-300 dark:bg-gray-700 rounded-lg"></div> <div class="h-6 bg-gray-300 dark:bg-gray-700 rounded w-3/4"></div> <div class="h-5 bg-gray-300 dark:bg-gray-700 rounded w-1/2"></div> <div class="space-y-2"> <div class="h-6 bg-gray-300 dark:bg-gray-700 rounded w-full"></div> </div> </div> <!-- Products Card --> <div class="animate-pulse space-y-4 bg-white dark:bg-gray-800 p-4 rounded-2xl shadow"> <div class="w-full h-40 bg-gray-300 dark:bg-gray-700 rounded-lg"></div> <div class="h-6 bg-gray-300 dark:bg-gray-700 rounded w-3/4"></div> <div class="h-5 bg-gray-300 dark:bg-gray-700 rounded w-1/2"></div> <div class="space-y-2"> <div class="h-6 bg-gray-300 dark:bg-gray-700 rounded w-full"></div> </div> </div> <!-- Products Card --> <div class="animate-pulse space-y-4 bg-white dark:bg-gray-800 p-4 rounded-2xl shadow"> <div class="w-full h-40 bg-gray-300 dark:bg-gray-700 rounded-lg"></div> <div class="h-6 bg-gray-300 dark:bg-gray-700 rounded w-3/4"></div> <div class="h-5 bg-gray-300 dark:bg-gray-700 rounded w-1/2"></div> <div class="space-y-2"> <div class="h-6 bg-gray-300 dark:bg-gray-700 rounded w-full"></div> </div> </div> </div> </div> </section> <div id="toast-interactive" ... > </div>
Compruebe la vista previa del resultado en el navegador.
JS: Fetch con cadena de promesas#
Dentro de la carpeta js, cree el documento javascript functions.js. Declare el modo estricto del documento.
Escribe una función flecha llamada fetchProducts que reciba un parámetro url, con las siguientes instrucciones:
Nota
Tome como referencia How to fetch json in JavaScript para realizar una petición http con
fetch.Dentro de la función, utiliza la palabra clave return para devolver el resultado de
fetch(url).Agregue el primer bloque
.then(response => { /* bloque then - 1 */ }). Dentro del bloque then - 1, realice lo siguiente:Use la estructura if con la condición !response.ok para lanzar un error.
throw new Error(`Error HTTP: ${response.status}`);
Caso contrario, si la respuesta es correcta, retorne
response.json()para procesar los datos en el siguiente bloque.
Agregue el segundo bloque
.then(data => { /* bloque then - 2 */ }). Dentro del bloque then - 2, retorne un objeto con las claves success (valor true) y body (contenido de data).Agregue el bloque
.catch(error => { /* bloque catch */ }). Dentro del bloque catch, retorne un objeto con las claves success (valor false) y body (mensaje de errorerror.message).
Exporte la función fetchProducts.
Ver la solución
'use strict'; let fetchProducts = (url) => { return fetch(url) .then(response => { // Verificar si la respuesta no es exitosa if (!response.ok) { throw new Error(`Error HTTP: ${response.status}`); } return response.json(); }) .then(data => { // Respuesta exitosa return { success: true, body: data }; }) .catch(error => { // Error en la solicitud return { success: false, body: error.message }; }); } export { fetchProducts }
JS: Carga de productos#
Nota
Verifique que el documento js/file01.js sea importado como módulo (type="module") en el documento index.html.
Al inicio del documento js/file01.js, importe la función
fetchProductsdesde el documento functions.js.Agregue una función flecha
renderProductsen el documento js/file01.js (antes de la función de autoejecución).Dentro de la función
renderProducts, llame a la funciónfetchProductscon la URL 'https://data-dawm.github.io/datum/reseller/products.json'. Encadena un bloque.then(result => { /* bloque then */ })para procesar el resultado.Dentro del bloque then, utilice una estructura condicional para verificar si
result.successes true o false.En caso que es true:
Almacene en container la referencia al elemento con id "products-container" (utilice el elemento document). Elimine cualquier contenido anterior dentro del elemento usando la propiedad innerHTML.
Almacene en products el contenido de
result.body. Seleccione solo los primeros 6 productos del arreglo con slice.Recorra el arreglo products utilizando el método
.forEach( product => { /* bloque forEach */ }).En el bloque forEach:
Cree una tarjeta HTML con la información del producto (imgUrl, title, price, productURL y category_id), utilizando una plantilla de literales (template literals). Almacene el resultado en la variable productHTML.
Ver el código
... let productHTML = ` <div class="space-y-4 bg-white dark:bg-gray-800 p-4 rounded-2xl shadow"> <img class="w-full h-40 bg-gray-300 dark:bg-gray-700 rounded-lg object-cover transition-transform duration-300 hover:scale-[1.03]" src="[PRODUCT.IMGURL]" alt="[PRODUCT.TITLE]"> <h3 class="h-6 text-xl font-semibold tracking-tight text-gray-900 dark:text-white hover:text-black-600 dark:hover:text-white-400"> $[PRODUCT.PRICE] </h3> <div class="h-5 rounded w-full">[PRODUCT.TITLE]</div> <div class="space-y-2"> <a href="[PRODUCT.PRODUCTURL]" target="_blank" rel="noopener noreferrer" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800 w-full inline-block"> Ver en Amazon </a> <div class="hidden"><span class="1">[PRODUCT.CATEGORY_ID]</span></div> </div> </div> </div>`;
Reemplace los marcadores de posición en productHTML con los valores correspondientes del objeto product, utilizando el método
replaceAllde las cadenas de texto, p.e.:productHTML = productHTML.replaceAll("[PRODUCT.TITLE]", product.title.length > 20 ? product.title.substring(0, 20) + "..." : product.title); ... productHTML = productHTML.replaceAll('[PRODUCT.CATEGORY_ID]', product.category_id); ...
Del objeto container, utilice la propiedad
innerHTMLpara concatenar productHTML.
En caso que es false, muestre una alerta con el mensaje de error.
Llame a la función
renderProductsen la función de autoejecución.Compruebe la vista previa del resultado y la consola del navegador para verificar la ejecución del código.
JS: Fetch con async/await#
Modifique el archivo functions.js.
Defina
fetchCategoriescomo una función flecha asincrónica que recibe el parámetro urllet fetchCategories = async (url) => { /* cuerpo de la función */ }
Modifique el cuerpo de la función fetchCategories con las siguientes instrucciones:
Nota
Tome como referencia Consumiendo una API en JavaScript utilizando Async / Await para realizar una petición http con
fetch.Dentro de la función, defina un bloque
try { /* bloque try */ } catch (error) { /* bloque catch */ }.En el bloque try, almacene en la variable response el resultado esperar la resolución de
await fetch(url).Use la estructura if con la condición !response.ok para lanzar un error.
throw new Error(`Error HTTP: ${response.status}`);
Caso contrario, si la respuesta es correcta:
En la variable text espere por la resolución de
await response.text().En la constante parser cree una nueva instancia de
DOMParser().En la variable data asigne el resultado de convertir el texto a un objeto XML, con el método
parser.parseFromString(text, "application/xml").Retorne un objeto con las claves success (valor true) y body (contenido de data).
En el bloque catch, retorne un objeto con las claves success (valor false) y body (mensaje de error
error.message).
Exporte la función fetchCategories.
Ver la solución
'use strict';
let fetchCategories = async (url) => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Error HTTP: ${response.status}`);
}
let text = await response.text()
const parser = new DOMParser();
const data = parser.parseFromString(text, "application/xml");
return {
success: true,
body: data
};
} catch (error) {
return {
success: false,
body: error.message
};
}
}
let fetchProducts = (url) => { ... }
export { fetchCategories, fetchProducts }
JS: Carga de categorías#
Nota
Verifique que el documento js/file01.js sea importado como módulo (type="module") en el documento index.html.
Al inicio del documento js/file01.js, importe la función
fetchCategoriesdesde el documento functions.js.Defina
renderCategoriescomo una función asincrónica en el documento js/file01.js (antes de la función de autoejecución).Dentro de la función
renderCategories, defina un bloquetry { /* bloque try */ } catch (error) { /* bloque catch */ }.Dentro del bloque try, almacene en result el resultado de esperar la resolución de
await fetchCategories('https://data-dawm.github.io/datum/reseller/categories.xml').Utilice una estructura condicional para verificar si
result.successes true o false.En caso que es true:
Almacene en container la referencia al elemento con id "categories" (utilice el elemento document).
Reemplace el contenido anterior (la propiedad
innerHTML) con la opción predeterminada deshabilitada.container.innnerHTML = `<option selected disabled>Seleccione una categoría</option>`;
Almacene en categoriesXML el contenido de
result.body.De categoriesXML, utilice el método getElementsByTagName para obtener una colección de elementos category. Almacene el resultado en la variable categories.
Recorra la lista de elementos en categories utilizando el método
for (let category of categories) { /* bloque for */ }.En el bloque for:
En la variable categoryHTML cree una opción HTML con la información de la categoría (id y name).
let categoryHTML = `<option value="[ID]">[NAME]</option>`;
Del elemento category, utilizando los métodos getElementsByTagName y textContent para extraer el valor de id y name.
Reemplace los marcadores de posición en categoryHTML con los valores correspondientes de id y name.
Del objeto container, utilice la propiedad
innerHTMLpara concatenar categoryHTML.
En caso que es false o dentro del bloque catch, muestre una alerta con el mensaje de error.
Llame a la función
renderCategoriesen la función de autoejecución.Compruebe la vista previa del resultado y la consola del navegador para verificar la ejecución del código.
JSDoc#
Utilice un cliente de IAG en el documento javascript para generar la documentación JSDoc de las funciones creadas. Asegúrese de que los comentarios JSDoc incluyan descripciones, parámetros y tipos de retorno.
Valide su respuesta con JSDoc: La Guía Definitiva para Documentar tu Código JavaScript.
Versionamiento#
Versione local y remotamente la(s) rama(s) de desarrollo en el repositorio landing.
Genere la(s) solicitud(es) de cambios (pull request) para la rama principal y apruebe los cambios.
Vercel#
Verifique el despliegue continuo (CD) del proyecto en Vercel.
Conclusiones#
Actividades autónomas#
Recursos extras#
En redes:
Promesas en JavaScriptAPIs públicas para probarJavaScript's Fetch API: A Beginner’s Guide 🧵 pic.twitter.com/K3EUdD72F5
— Csaba Kissi (@csaba_kissi) March 24, 2025
Try Public APIs for freehttps://t.co/YKUy0OdgTA
— SwiftUIX (@SwiftUIHome) April 29, 2025