Fetch data
Clase 9 de 26 • Curso de Asincronismo con JavaScript
Contenido del curso
Jose Carlos Ríos Márquez
Ivan Sangueza Alarcon
Dario Paladines
Maria Gabriela Rodriguez Cuevas
Deniss Bonilla Paredes
Deniss Bonilla Paredes
Julian Jose Sossa Cruz
Dario Paladines
Jaime Frank Villanueva Oré
Francisco Encabo Servián
Julia Gabriela Nieva Paredes
Juan Fernando Yepes Muñoz
Vladimir Hener Steve Sanchez Astoray
Luis Verteliz
Fernando Orozco Velasquez
Ruben Dario Moscoso Carbonel
Jose Francisco Garcia Angeles
Maria del Carmen Valero Carreño
Misael Gomez
Matias Diaz
Javi Llinares
Delaskar Caicedo
Julián Guacaneme
Paulo Anguiano
Misael Gomez
Estefani Yuliana Conislla Atúncar
Erick Martin Meza Alonso
Luis Hernando Sendoya Serrato
Rodrigo Rivas Martinez
Juan Carlos Aguilar
WILDES JARAMILLO HENAO
JACOBO ZAPATA ROJAS
Daniel Triana
Yuliam Rivera González
Henry Alexander Velásquez Rosas
Luis Alberto Ramirez Salas
Victor Areiza
David Hereira
Rubén Ernesto Aragón Gil
Kevin Salazar
VICTOR CAUDILLO
Lisbeth Quintero
Si se les hace complicado entener lo que se vió en la clase les recomiendo documentar el código, ir linea por linea, indagar y consultar que hace cada método, cada función, cada atributo, así es mucho más facil comprender. Les dejo el mio documentado, espero sea de gran ayuda:
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; const API = "https://api.escuelajs.co/api/v1"; //funcion principal que obtendrá la informacion del producto como un objeto function fetchData(urlApi, callback) { //inicializar un objeto de tipo XMLHttpRequest let xhttp = new XMLHttpRequest(); //El metodo .open realiza la petición de apertura de comunicación, el metodo puede ser 'GET' o 'POST', luego se envia la URL, si es asincrono (true o false), usuario y contraseña. En esta caso solo se utiliza el metodo, la url y async xhttp.open('GET', urlApi, true); //en este metodo Almacena el nombre de la función que se ejecutará cuando el objeto XMLHttpRequest cambie de estado xhttp.onreadystatechange = function (event) { //el atributo readyState define el estado del objeto XMLHttpRequest //0 No inicializado //1 Loading //2 ejecutado //3 interactuando //4 completado if (xhttp.readyState === 4) { //si la respuesta de la API es exitosa (200 Ok) if (xhttp.status === 200) { //se ejecuta el callback recibiendo como argumentos un objeto, como la respuesta de la API es un texto plano, el metodo JSON.parse tranformará este texto en un objeto. //El atributo devuelve un DOMString que contiene la respuesta a la consulta como un texto o null si la consulta no tuvo exito o aun no ha sido completada. callback(null, JSON.parse(xhttp.responseText)); //si la respuesta de la API no es exitosa se captura el error } else { //se inicializa un objeto de tipo Error donde se le envian como argumentos un mensaje de error y la URL de la API para conocer en dónde se produjo el error const error = new Error("Error" + urlApi); //se ejecuta el callback recibiendo como argumentos el error y null debido a que no se pudo obtener el objeto return callback(error, null); } } //el método .send() envia la petición al servidor } xhttp.send(); } //se invoca el metodo fetchData() pasandole como argumentos la varible API concatenada con la cadena 'products' para acceder a la URL de la API deseada, y una función anónima que recibe 2 parámetros (un objeto de error y un arreglo que almacena todos los objetos traidos por la API). fetchData(`${API}/products`, function (error1, data1) { //se valida si existe un error, en caso de que exista se detiene el proceso y se imprime el error if (error1) return console.error(error1); //se invoca nuevamente la función fetchData con el fin de acceder a un objeto puntual del arreglo data1, se envia como parámetros la url de la API apuntando al atributo del primer objeto de arreglo data1 y nuevamente una función anónima. fetchData(`${API}/products/${data1[0].id}`, function (error2, data2) { //si en este punto se identifica un error se imprime en consola y se detiene el proceso if (error2) return console.error(error2); //Se invoca nuevamente la funcion fetchData con el fin de acceder a la categoria, se envían como parametros la url de la API con la concatenación de 'Categories' y el atributo Id de categoria del objeto data2 de la función anterior //en este caso puntual se hace uso de Optional Caining el cual hace una evalucación de las propiedades de un objeto y en vez de arrojar un error devuelve undefined en caso que la propiedad no exista o sea null. //igual que las anteriores e envia una funcion anonima con 2 argumentos, un objeto Error y un objeto de datos fetchData(`${API}/categories/${data2?.category?.id}`, function (error3, data3) { //se valida si existe error, en caso de que exista se detiene el proceso y se imprime el error if (error3) return console.error(error3); //Se imprime el objeto en la posición 1 del arreglo de los objetos obtenidos en el metodo invocado inicialmente console.log(data1[0]); //Se imprime el titulo del objeto que se consultó en la seguna invocación de la función console.log(data2.title); //Se imprime el nombre de la categoria a la que pertenece el objeto que se consultó en la seguna invocación del método. console.log(data3.name); }); }); });
Gracias !! 🤠
Es una buena técnica yo la hago igualmente, comentar absolutamente todo, ya que hay veces que vuelves a los dias a ver el código y no te acuerdas. E igual fundamenteal si no entienden ir colocando console.log por secciones o líneas a que vean que esta haciendo el programa
𝗖𝗹𝗮𝘀𝗲 #𝟴: 𝗙𝗲𝘁𝗰𝗵 𝗱𝗮𝘁𝗮 𝟴/𝟮𝟭 .
console.info("info"); //muestra un mensaje de información en la consola web console.error("error"); //muestra mensaje de un error console.warn("warn"); //muestra mensaje de advertencia console.log("log"); //para mensajes generales de registro de información
. ++Siguiendo con el proyecto:++ . En el archivo ++challenge.js++ se agrega el siguiente código:
fetchData(`${API}/products`, function (error1, data1) { if (error1) return console.error(error1); //si hay error, devuelve el error fetchData (`${API}/products/${data1[0].id}`, function(error2, data2){ if(error2) return console.error(error2); //valida el error 2 //se usa Optional chaining '?.' que es una forma segura de acceder a las propiedades de los objetos anidados, incluso si no existe una propiedad intermedia: fetchData(`${API}/categories/${data2?.category?.id}`, function(error3, data3){ if(error3) return console.error(error3); //evitar el callback hell console.log(data1[0]); console.log(data2.title); console.log(data3.name); }); }); });
Por cuestiones de mi versión de Node y a que aún no he podido actualizarla solo llegué al segundo anidamiento, pero muestro el resultado que me dio.
{ id: 116, title: 'Generic Fresh Computer', price: 405, description: 'New range of formal shirts are designed keeping you in mind. With fits and styling that will make you stand apart', category: { id: 5, name: 'Others', image: 'https://api.lorem.space/image?w=640&h=480&r=407' }, images: [ 'https://api.lorem.space/image?w=640&h=480&r=1746', 'https://api.lorem.space/image?w=640&h=480&r=503', 'https://api.lorem.space/image?w=640&h=480&r=2218' ] } Generic Fresh Computer
Quité los optional chaining de la tercera petición y esta fue la información que me salió
{ id: 116, title: 'Generic Fresh Computer', price: 405, description: 'New range of formal shirts are designed keeping you in mind. With fits and styling that will make you stand apart', category: { id: 5, name: 'Others', image: 'https://api.lorem.space/image?w=640&h=480&r=407' }, images: [ 'https://api.lorem.space/image?w=640&h=480&r=1746', 'https://api.lorem.space/image?w=640&h=480&r=503', 'https://api.lorem.space/image?w=640&h=480&r=2218' ] } Generic Fresh Computer Others
La duda que me queda es porque podría acabar en un callback hell, es decir yo podría y podría seguir haciendo peticiones, pero también no podría hacerlo, es decir solo hago una petición con un if y ya no? digo nose, no he trabajado con callbacks, sino solo con async por eso no entiendo como se puede llegar a un callback hell
Un ejemplo es cuando tienes que transformar info que traes de la BD y como puede tener "n" niveles, llegas a tener callbackHell y eso era lo que sucedía hasta que se agrego el async / await a javascript
Inmejorable la idea de colar un error para explicarnos como buscar en el navegador, como consultar en Stack Overflow. Parece una tontería pero es de una ayuda inmensa que un profesor haga esto en un curso. Felicitaciones.
Muy cierto. Algunos ni siquiera saben que existe Stack Overflow. Y como dices, parece una tontería, pero es bueno para quien no lo sepa.
Este tema es muy complejo, y entiendo que el profe ha ido mejorando en su pedagogía, pero es que es bien difícil entenderle algunas cosas porque no explica bien la razón o la forma en la que un elemento va a ir interactuando con otro.
pero con la practica ya vas entendiendo..
Me perturba que onreadystatechange no esté en camel case.
x2 arruinan la estética de mi código xD
Deberían hacer ejercicios mas simples e ir subiendo la complejidad de los mismo de a poco. La verdad es que para una persona que recién esta aprendiendo estos temas, es sumamente complicado.
hola, yo igual voy aprendiendo y la primera vez que tome esta clase no entendi mucho, la verdad es que estos ejemplos si son muy simples solo que nos cuesta trabajo porque estos son temas dificiles de abordar, te recomiendo que veas las clases varias veces es la mejor forma que tenemos de entender algo, yo tengo la costubre de ver las clases mas de una vez y documentar el codigo, si es necesario lo hago linea a linea, te recomiendo que hagas lo mismo que yo, creeme que con un poco de paciencia y dedicacion aprenderas los temas que vamos manejando. Saludos!
No entiendo nada, estas clases son las que me hacen plantearme si voy a ser capaz o no...
Poco a poco, no te desanimes, es un proceso, la programación es como tu pareja, primero te llena de amor y pasión, después te vuelve loc@ porque te salen bugs o no entiendes algo, pero después de pasar por ese oscuro sendero, lo resuelves y lo amas más que antes. Solo es paciencia, cuando ya lo apliques a un proyecto todo cobra sentido, porque ya vas a ser tu y el código
Claro que vas a ser capas! Todos lo somos. Es medio complejo sumado a que estas ultimas dos clases de Oscar no fueron las mejores. Pero dedícale tiempo, busca otros recursos. Tomate tu tiempo entre un video y el otro, si no lo entendiste bien vuelve a verlo mañana. Pero no te detengas!
Yo mira que lo intento con Óscar... pero de verdad no entiendo esa manera de explicar tan técnica en una escuela para APRENDER un lenguaje, pasa absolutamente en todos sus cursos.
Obvio que los programadores tenemos que lidiar con documentación técnica a lo largo de nuestro desempeño profesional, pero esto es un curso de formación y educativo para hacernos mejores profesionales y se debería dar la información de una manera más divulgativa sin perder el componente técnico. Otros profesores de Platzi lo consiguen a la perfección, se me viene a la mente Diego de Granda, o Juan.
Ojalá este mensaje lo lea y lo intente aplicar a sus futuros cursos.
Concuerdo contigo, se supone que este tipo de cursos debería de digerirse de una manera mucho mas fácil y sencilla, algo simple. Pero lo complica demasiado con tanto tecnicismo que utiliza. Parece que tratara de ser perfecto en sus palabras pero lo complica demasiado... Por lo visto no soy el único que le cuesta entender lo que Oscar esta tratando de enseñar.
Yo pensaba que era persepción mia, pero la verdad es que no logro engancharme con esta clase, como si lo hacia con las de Dieogo o Juan
Les comparto el link de un video que me ayudó a entender mejor lo que es Optional Chaining!
Me encanto esta nueva versión :)
Sí, está super buena la verdad. Aunque haber usando la API de R&M también fue super.
si es necesario aprender XMLHttpRequest, o saltamos directo a las promesas?
En mi opinión no es necesario, pero si muy útil en caso de que alguna vez te topes con código de legado escrito con este tipo de herramientas puedas tener una noción de que se trata
Me pareció muy genial que se buscara el error. Obviamente le profe ya sabe porque se debe este error, pero la forma de afrontarlo es como la que deberíamos tener, aceptar que no lo sabemos todo y pedir ayuda.
x1000, está saliendo un curso muy bueno, muy real
I don't think this is a good starting point to learn these topics. Asynchronism in JavaScript cannot be learnt just with a basic course completed. You also need to know at least some backend theory just to understand what a request even is. In this classes the professor is just spitting out a lot of information without context and that makes it harder to fully understand what he is doing in code
Hola, solo queria compartirles lo siguiente. . Existen 5 categorias de producto:
. La llamada a la API para obtener la categoria, no obtiene la categoria asociada al producto, obtiene el primer tipo de categoria ('nuevo'). Esto debido a como esta construida la API. . Tambien mencionar que para obtener la información no era necesario hacer tantos callbacks, solo con este bloque se podia obtener lo mismo y la categoria real asociada al producto
fetchData(`${API}/products`, function (error, all) { if (error) return console.log(error); const product = all[0]; console.log(product) console.log(product.title) console.log(product.category.name) })
Aunque claro que todo se hizo para illustrar un poco el callback hell y llamadas que podian ser dependientes (o eso creo). . Ademas tambien en el manejo de errores, al no ser tan personalizado pues no veo necesario declararlos explicitamente, ya que la misma consola nos los arroja. . Yo tambien apenas estoy aprendiendo del tema, asi que cualquier cosa que vean que me equivoco, agradeceria su retroalimentación.
estás en lo cierto chapatín, el profe complicó el codigo un poquito con fines educativos.
🔥 9. Fetch data (Resumen, Notas, Apuntes)
Esta es una explicación de lo que entendí. Falta pulir detalles pero espero sirva de algo. ✨Al final dejo una forma de hacer lo mismo pero mas sencilla, código extraido de este comentario.
Código de la clase
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; const API = 'https://api.escuelajs.co/api/v1'; function fetchData(urlApi, callback) { let xhttp = new XMLHttpRequest(); xhttp.open('GET', urlApi, true); xhttp.onreadystatechange = function (event) { if (xhttp.readyState === 4) { if (xhttp.status == 200) { // Puedes quitarle el JSON.parse para ver como viene toda la información (DOMString cadena de caracteres) callback(null, JSON.parse(xhttp.responseText)); } else { const error = new Error('Error en ', urlApi); callback(error, null); } } } xhttp.send(); } // Template strings y Optional chaining '?.' fetchData(`${API}/products`, function (error1, data1) { 👈👀 if (error1) return console.error(error1); fetchData(`${API}/products/${data1[0].id}`, function (error2, data2) { if (error2) return console.error(error2); fetchData(`${API}/categories/${data2?.category?.id}`, function (error3, data3) { if (error3) return console.error(error3); console.log(data1[0]); console.log(data2.title); console.log(data3.name); }); }); }); // Obtenemos: { id: 2, title: 'Oriental Bronze Car', price: 342, description: "Boston's most advanced compression wear technology increases muscle oxygenation, stabilizes active muscles", images: [ 'https://picsum.photos/640/640?r=2863', 'https://picsum.photos/640/640?r=4222', 'https://picsum.photos/640/640?r=3311' ], creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z', category: { id: 3, name: 'Furniture', image: 'https://picsum.photos/640/640?r=2068', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' } } Oriental Bronze Car Furniture
¿Cómo llegamos a ese resultado?
Ya vimos lo que obtenemos como resultado final, pero, ¿Cómo llegamos a ese resultado?
fetchData obtenemos un array enorme con muchos objetos dentro:fetchData(`${API}/products`, function (error1, data1) { if (error1) return console.error(error1); console.log(data1); }); // Obtenemos esto y más: [ { id: 2, title: 'Oriental Bronze Car', price: 342, description: "Boston's most advanced compression wear technology increases muscle oxygenation, stabilizes active muscles", images: [ 'https://picsum.photos/640/640?r=2863', 'https://picsum.photos/640/640?r=4222', 'https://picsum.photos/640/640?r=3311' ], creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z', category: { id: 3, name: 'Furniture', image: 'https://picsum.photos/640/640?r=2068', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' } }, { id: 4, title: 'Tasty Frozen Table', price: 962, description: 'Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals', images: [ 'https://picsum.photos/640/640?r=7246', 'https://picsum.photos/640/640?r=9914', 'https://picsum.photos/640/640?r=1496' ], creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z', category: { id: 4, name: 'Shoes', image: 'https://picsum.photos/640/640?r=260', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' } }, ... { id: 102, title: 'Awesome Granite Bacon', price: 1, description: 'New ABC 13 9370, 13.3, 5th Gen CoreA5-8250U, 8GB RAM, 256GB SSD, power UHD Graphics, OS 10 Home, OS Office A & J 2016', images: [ 'https://picsum.photos/640/640?r=4809', 'https://picsum.photos/640/640?r=8923', 'https://picsum.photos/640/640?r=8980' ], creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z', category: { id: 2, name: 'Electronics', image: 'https://picsum.photos/640/640?r=4582', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' } } ... 100 more items
fetchData obtenemos solo el primer objeto y extraemos el title usando console.log(data2.title);:fetchData(`${API}/products`, function (error1, data1) { if (error1) return console.error(error1); /* console.log(data1); */ fetchData(`${API}/products/${data1[0].id}`, function(error2, data2){ if(error2) return console.error(error2); console.log(data2); }); }); // Obtenemos el objeto de la posición [0], lo que no logro entender es el porqué le agregan un .id, ya que, sin eso no funciona :v { id: 2, title: 'Oriental Bronze Car', 👈👀 price: 342, description: "Boston's most advanced compression wear technology increases muscle oxygenation, stabilizes active muscles", images: [ 'https://picsum.photos/640/640?r=2863', 'https://picsum.photos/640/640?r=4222', 'https://picsum.photos/640/640?r=3311' ], creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z', category: { id: 3, name: 'Furniture', image: 'https://picsum.photos/640/640?r=2068', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' } }
fetchData buscamos a qué categoría pertenece el producto que obtuvimos anteriormente, pero primero veamos las categorías existentes... :fetchData(`${API}/products`, function (error1, data1) { if (error1) return console.error(error1); /* console.log(data1); */ fetchData(`${API}/products/${data1[0].id}`, function(error2, data2){ if(error2) return console.error(error2); /* console.log(data2); */ fetchData(`${API}/categories/`, function (error3, data3){ if(error3) return console.error(error3); console.log(data3); }); }); }); // Obtenemos: [ { id: 1, name: 'Clothes', image: 'https://picsum.photos/640/640?r=193', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' }, { id: 2, name: 'Electronics', image: 'https://picsum.photos/640/640?r=4582', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' }, { id: 3, name: 'Furniture', 👈👀 // Esto es lo que necesitamos image: 'https://picsum.photos/640/640?r=2068', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' }, { id: 4, name: 'Shoes', image: 'https://picsum.photos/640/640?r=260', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' }, { id: 5, name: 'Others', image: 'https://picsum.photos/640/640?r=5088', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' }, { id: 32, name: 'New Category', image: 'https://placeimg.com/640/480/any', creationAt: '2023-07-16T23:28:51.000Z', updatedAt: '2023-07-16T23:28:51.000Z' }, { id: 33, name: 'New Category', image: 'https://placeimg.com/640/480/any', creationAt: '2023-07-16T23:31:07.000Z', updatedAt: '2023-07-16T23:31:07.000Z' } ]
Ahora filtremos la categoría de nuestro producto, para lo cual concatenamos el ID que debe buscar ${API}/categories/${data2?.category?.id}, con esto a través de los datos del producto obtenidos en data2 entramos a producto.categoria.id que si nos fijamos es igual a 3. Usando console.log(data3.name); podemos tener el nombre de la categoría a la que pertenece nuestro producto:
fetchData(`${API}/products`, function (error1, data1) { if (error1) return console.error(error1); /* console.log(data1); */ fetchData(`${API}/products/${data1[0].id}`, function(error2, data2){ if(error2) return console.error(error2); /* console.log(data2); */ fetchData(`${API}/categories/${data2?.category?.id}`, function (error3, data3){ if(error3) return console.error(error3); console.log(data3); }); }); }); // Obtenemos { id: 3, name: 'Furniture',👈👀 // Fin image: 'https://picsum.photos/640/640?r=2068', creationAt: '2023-07-16T06:10:35.000Z', updatedAt: '2023-07-16T06:10:35.000Z' }
Otra forma
✨ Esta es otra forma de hacer lo mismo, pero más sencilla de entender.
fetchData(`${API}/products`, function (error, all) { if (error) return console.log(error); const product = all[0]; /* console.log(all); */ //👈👀 Muestra un array de objetos console.log(product); console.log(product.title) console.log(product.category.name) })
🔥 Aquí puedes ver más apuntes.
No me habia topado durante los cursos alguno que tuviera tantos comentarios negativos.. Arreglen este curso Platzi
no entiendo su forma de explicar la verdad
No tengo claro es donde está la parte asincrónica. pues entendí que el uso solo de callback no te hace asíncrono. En otros ejemplos he visto que usan "setTimeout" para eso, pero aquí no lo hacen. ¿Dónde está lo asíncrono? ¿en el uso de "onreadystatechange" ?
No sé mucho bro, pero pienso que se encuentra en esta función:
function fetchData(urlApi, callback) { let xhttp = new XMLHttpRequest(); xhttp.open('GET', urlApi, true); xhttp.onreadystatechange = function (event) { if(xhttp.readyState === 4) { if (xhttp.status === 200) { callback(null, JSON.parse(xhttp.responseText)) } else { const error = new Error('Error' + urlApi); return callback(error, null); } } } xhttp.send(); }
La parte asíncrona se declara cuando usamos en método open(), del objeto XMLHttpResquest(), ya que al introducir true como tercer parámetro le decimos que queremos que la petición sea asíncrona.
Ya al momento de usar en evento onreadystatechange, el navegador empieza a monitorear ese request, por eso es que cuando tenemos el else en el primer if, empezamos a obtener errores, porque empieza a cambiar de .readyState 0 hasta el 4, que es el completed.
Es claro que el ejemplo tiene como intensión la venja de usar promesas.
No se claven tanto sigan adelante
Bueno, les comento, que me cuesta un poco entender, pero estas dos últimas clases lo que hice fue empezar a tomar apuntes, línea de código por línea de código, y creo que lo estoy entendiendo ya un poco más, estoy segura que con el pasar de las clases y mientras se toma más experiencia, todo será mucho más claro. Aquí les dejo mis apunte. En esta clase hacemos el llamado a la función "fechData" que creamos en la clase anterior, pasando como primer parámetro, la constante que creamos con el link de la API, mas el “/productos”, que nos redireccionará hacia la página donde están los productos directamente, como segundo parámetro, ponemos una función anónima, con los parámetro error y data.
Luego creamos un if, pasando el parámetro “error1”, de la función que creamos dentro de nuestro fetch data, y retornamos error, esto hará que nos muestre error si no llega a funcionar la conexión a la API, y nos dirá qué fue lo que falló exactamente.
fetchdata(`${API}/products`, function(error1, data1) { if (error1) return console.error(error1); })
Posterior llamamos la función fetchData, pero como parámetros, pasamos la constante con el link, accedemos a products y adicional a la id de posición 0, de la data1, que pusimos de parámetro en la anterior, y de segundo parámetro una función anónima nuevamente, con los parámetros error2 y data2, con un if por si ocurre un error no lo muestre o si no, que entre al siguiente fetchData que crearemos, pero esta vez entraremos como primer parámetro, al link de la API, pero entramos a categories, y buscaremos en esta el id de la categoría de los productos, dentro del data2, que es la información que obtuvimos en el anterior fetchData (se recomienda incluir el “?”, optional chaining, para evitar el error, por si algún valor no está bien?, ahora como segundo parámetro haremos otra función, pasando error3 como primer parámetro, y el data3, serían 3 peticiones para 3 valores distintos. aquí ya terminaremos este ejercicio para evitar en calbackHell.
fetchdata(`${API}/products`, function(error1, data1) { if (error1) return console.error(error1); fetchdata(`${API}/products/${data1[0].id}`, function(error2, data2) { if (error2) return console.log(error2); fetchdata(`${API}/categories/${data2?.category?.id}`, function(error3, data3) { if (error3) return console.log(error3); }); }); });
Ahora haremos console.log, para obtener la información de los 3 llamados o peticiones (fetchData).
console.log(data1[0]); // nos dará la información del primer producto de la API console.log(data2.title); // Nos da el título del primero producto de la API console.log(data3.name); // nos da el nombre de la categoría dentro del primer producto de la API
Aquí todo el código
const XMLHTTpRequest = require('xmlhttprequest').XMLHttpRequest; const API= 'https://api.escuelajs.co/api/v1'; function fetchdata(urlApi, callback) { let xhttp = new XMLHTTpRequest(); xhttp.open('GET', urlApi, true); xhttp.onreadystatechange = function(evento) { if (xhttp.readyState ===4){ // 0 no se ha inicializado 1 loading 2 se ejecutó, 3 cargando e interactuando, 4 información completa if(xhttp.status === 200){ // 200 correcta callback(null, JSON.parse(xhttp.responseText)); }else { const error = new Error('Error' + urlApi); return callback(error, null); } } } xhttp.send(); } fetchdata(`${API}/products`, function(error1, data1) { if (error1) return console.error(error1); fetchdata(`${API}/products/${data1[0].id}`, function(error2, data2) { if (error2) return console.log(error2); fetchdata(`${API}/categories/${data2?.category?.id}`, function(error3, data3) { if (error3) return console.log(error3); console.log(data1[0]); // nos dará la información del primer producto de la API console.log(data2.title); // Nos da el título del primero producto de la API console.log(data3.name); // nos da el nombre de la categoría dentro del primer producto de la API }); }); });
Finalmente este el resultado que nos da cada console:
console.log(data1[0]); // nos da la información del primer producto de la API
{ id: 35, title: 'Incredible Steel Bacon', price: 730, description: 'Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals', category: { id: 1, name: 'Clothes', image: 'https://api.lorem.space/image/fashion?w=640&h=480&r=2981' }, images: [ 'https://api.lorem.space/image/fashion?w=640&h=480&r=4222', 'https://api.lorem.space/image/fashion?w=640&h=480&r=7355', 'https://api.lorem.space/image/fashion?w=640&h=480&r=1163' ] }
console.log(data2.title); // Nos da el título del primero producto de la API
Incredible Steel Bacon
console.log(data3.name); // nos da el nombre de la categoría dentro del primer producto de la API
Clothes