En este proyecto usaremos la API de Rick and Morty, al trabajar con una API es obligatorio leer su documentación para conocer la estructura de esta, conocer los atributos y elementos que tiene, también podemos explorar con herramientas como postman. Si no conocemos la estructura de la API no podremos hacer lo que buscamos, así que por favor no te olvides de leer toda la información de la API con la que trabajes.
De la API queremos:
debemos instalar una dependencia para poder hacer HTTP requests, instalamos la dependencia XMLHTTPRequest de la siguiente manera:
npm install xmlhttprequest --save
Instanciamos la dependencia en una variable de la siguiente forma:
let XMLHttpRequest = required('xmlhttprequest').XMLHttpRequest;
Creamos una función que reciba el callback.
functionfetchData(url_api, callback) {
}
Dentro de la función debemos crear un nuevo objeto XMLHTTPRequest:
functionfetchData(url_api, callback) {
let xhttp = **new***XMLHttpRequest*();
}
Hacemos una petición de tipo “GET”, enviando el URL al que haremos la petición e indicando que se hará uso del asincronismo:
functionfetchData(url_api, callback) {
let xhttp = **new***XMLHttpRequest*();
xhttp.open('GET', url_api, true);
}
Usamos otro método para escuchar lo que hace nuestra petición, dentro de este método usaremos una función.
functionfetchData(url_api, callback) {
let xhttp = **new** *XMLHttpRequest*();
xhttp.open('GET', url_api, true);
xhttp.onreadystatechange = function (event) {
}
}
En esta nueva función escucharemos el estado de nuestra petición, usaremos el atributo readySate
que nos indica el estado actual de la petición, esperamos que el estado sea igual a “4” o sea que ya se terminó la petición.
functionfetchData(url_api, callback) {
let xhttp = **new** *XMLHttpRequest*();
xhttp.open('GET', url_api, true);
xhttp.onreadystatechange = function (event) {
if (xhttp.readyState === 4) {
}
}
}
Sin embargo, hay un problema, no sabemos si la petición fue exitosa, para saberlo usaremos el atributo status
y esperaremos que su status sea “200” o sea, exitoso, luego llamaremos al callback entregando como primer argumento un error y como segundo el estado de la petición. El estado será un string, por lo que debemos parsearla para poder utilizarla. También, añadiremos un else para ejecutar en caso de que la petición fallara.
functionfetchData(url_api, callback) {
let xhttp = **new** *XMLHttpRequest*();
xhttp.open('GET', url_api, true);
xhttp.onreadystatechange = function (event) {
if (xhttp.readyState === 4) {
if (xhttp.status === 200) {
callback(null, JSON.parse(xhttp.responseText));
} else {
const error = newError('Error' + url_api);
return callback(error, null);
}
}
}
}
Por último, dentro de la función fetchData enviaremos nuestra petición con el método send
.
functionfetchData(url_api, callback) {
let xhttp = **new** *XMLHttpRequest*();
xhttp.open('GET', url_api, true);
xhttp.onreadystatechange = function (event) {
if (xhttp.readyState === 4) {
if (xhttp.status === 200) {
callback(null, JSON.parse(xhttp.responseText));
} else {
const error = newError('Error' + url_api);
return callback(error, null);
}
}
}
xhttp.send();
}
Muy bien, ya tenemos la función que llamara el callback.
Ya tenemos la función que recibirá el callback, es momento de crear el callback llamando a la función fetchData
.
Primero guardamos nuestra API en una variable.
let API = 'https://rickandmortyapi.com/api/character/'
A continuación llamamos a la función fetchData
para enviar como argumento nuestra API y una función que generaremos en el momento, el callback. Esta función tendrá dos parámetros, el error que suceda y el resultado de la petición.
fetchData(API, function(error1, data1){
}
Dentro de la función se usa una condicional en caso de que salte un error, para retornar este error. Con este primer callback podemos obtener el número de personajes, solo debemos entrar al atributo count
que está dentro del atributo info
.
fetchData(API, function (error1, data1) {
if (error1) returnconsole.error(error1);
console.log(data1.info.count); // 826
}
Ya cumplimos nuestro primer objetivo, ahora debemos anidar un nuevo callback para ir un nivel más “profundo” en la API. En esta función enviaremos la API ya usada, pero añadiendo un nuevo elemento que obtendremos del atributo id
del primer elemento ([0]) del atributo results
, todo esto se encuentra dentro del segundo parámetro del previo callbackdata1
. Como segundo argumento crearemos un nuevo callback con los mismos parámetros error2
y data2
. Al igual que antes generaremos una condicional que retornara un error en caso de que se genere uno.
fetchData(API, function (error1, data1) {
if (error1) returnconsole.error(error1);
console.log(data1.info.count); // 826
fetchData(API + data1.results[0].id, function (error2, data2) {
console.log(API + data1.results[0].id);
}
}
¿Pero qué me devuelve todo eso en el primer argumento de fetchData
? Te debes preguntar, bueno el resultado de esta unión API + data1.results[0].id
regresa simplemente este URL “https://rickandmortyapi.com/api/character/1” si hubiéramos entrado en el elemento [1] de results
obtendríamos un URL así “https://rickandmortyapi.com/api/character/1”.
Con el resultado de este segundo callback podremos cumplir el segundo objetivo, pues entramos al primer personaje de la API (data1.results[0]
). Para obtener en nombre debemos buscarlo en el atributo name
.
fetchData(API, function (error1, data1) {
if (error1) returnconsole.error(error1);
console.log(data1.info.count); // 826
fetchData(API + data1.results[0].id, function (error2, data2) {
if (error2) returnconsole.error(error2);
console.log(data2.name); // "Rick Sanchez"
}
}
Perfecto, solo nos queda el último objetivo, para el URL de la función, en este caso tenemos que entrar a otra sección de la API, la URL de esta nueva sección se encuentra en el atributo url
que está dentro del atributo origin
, a la vez este se encuentra en el resultado de la anterior petición (data2
). El callback con los mismos parámetros error3
y data3
. La condicional para el error no debe faltar como siempre
fetchData(API, function (error1, data1) {
if (error1) returnconsole.error(error1);
console.log(data1.info.count); // 826
fetchData(API + data1.results[0].id, function (error2, data2) {
if (error2) returnconsole.error(error2);
console.log(data2.name); // "Rick Sanchez"
fetchData(data2.origin.url, function (error3, data3) {
if (error3) returnconsole.error(error3);
});
});
});
De nuevo, con el primero argumento de fetchData tenemos problemas en saber que es. Como vamos al URL de una nueva sección de la API obtendremos un nuevo URL que no tendrá “characters” y para conseguir el URL entramos a data2.origin.url
que devuelve el URL “https://rickandmortyapi.com/api/location/1”.
Ya casi lo logramos, la dimensión que buscamos está en el atributo dimension
, únicamente debemos imprimirla.
fetchData(API, function (error1, data1) {
if (error1) returnconsole.error(error1);
console.log(data1.info.count); // 826
fetchData(API + data1.results[0].id, function (error2, data2) {
if (error2) returnconsole.error(error2);
console.log(data2.name); // "Rick Sanchez"
fetchData(data2.origin.url, function (error3, data3) {
if (error3) returnconsole.error(error3);
console.log(data3.dimension); // "Dimension C-137"
});
});
});
Todo ese código enmarañado y complicado se lo conoce como callback hell, aunque el verdadero callback hell tiene muchas más anidaciones, ¿te imaginas eso? Para evitar caer en este “infierno” se crearon las promesas, que veremos a lo largo del curso.
PD: Si no entiendes que está haciendo o devolviendo el codigo, intenta jugar con los console.log()
y mira que está pasando “detrás de cámaras” del codigo, en este caso puedes imprimir data1
, data2
y data3
para ver que estamos obteniendo de los requests, anímate a explorar por tu cuenta!
¡Saludos platzinauta, nunca pares de aprender! 🙋🏿♂️🖤
Muchas gracias por el tutorial, justo estaba confundido en la clase del curso de asincronismo y ahora me quedó mucho más claro
Wow! Me alegra mucho leer esto. Que bien que te sirva para comprender mejor el tema 😁. si te sirve acabo de hacer este tutorial para las promesas. 🙋🏿♂️🖤