
<br/>
<br/>
<p style="text-align: center">
<img src="https://i.imgur.com/PKrnUo7.png" />
</p>
<h1 style="text-align: center;">Máster Universitario en Ingeniería de Software y Sistemas Informáticos</h1>
<h2 style="text-align: center;">Computación en el Cliente Web</h2>
<h3 style="text-align: center;">INTEGRANTES:<br/>
Carlos Muñoz<br/>
Carlos Román<br/>
Gabriel Villamagua<br/>
Miguel Yachimba
</h3>
<br/>
<br/>
<br/>
<br/>
# Contenido
1. [Introducción](#introduction)
2. [Extensiones](#extensiones)
3. [Librerías](#librerias)
4. [Desarrollo](#desarrollo)
4.1. [Técnicas 2005](#version2005)
4.2. [Técnicas 2006](#version2006)
4.3. [Técnicas 2013](#version2013)
4.4. [Técnicas hasta 2014](#version2014)
4.5. [Web Components](#web-components)
5. [Conclusiones](#result)
6. [Bibliografía](#references)
## Introducción <a name="introduction"></a>
El presente ejercicio tiene como finalidad poner en práctica las diferentes maneras de hacer llamadas AJAX.
## Extensiones VS Code <a name="extensiones"></a> 
Las extensiones de VS Code permiten agilizar el desarrollo de código, VS Code en este momento tiene un marketplace con muchas extensiones disponibles.
Para el desarrollo de nuestros ejercicios vamos a usar dos extensiones:
- [HTML Snippets](https://marketplace.visualstudio.com/items?itemName=abusaidm.html-snippets)
- [HTML Bolierplate](https://marketplace.visualstudio.com/items?itemName=sidthesloth.html5-boilerplate)
## Librerías <a name="librerias"></a>
- [Bootstrap 4](https://getbootstrap.com)
- [Skeleton](http://getskeleton.com/)
- [jQuery](https://jquery.com/)
## Desarrollo <a name="desarrollo"></a>
Siguiendo los pasos del documento proporcionado como guía, se debe instalar y configurar las herramientas necesarias, para realizar interacciones con la [API de Chistes de Chuck Norris](http://www.icndb.com/api/). Estas interacciones se harán a través de técnicas distintas que permitirán comprender cronológicamente la evolución de las peticiones web desde el año 2005 hasta el presente. Los ejercicios realizados comprenden:
Técnica | Tecnología usada
------------ | -------------
Año 2005 |XMLHttpRequest
Año 2006 | jQuery
Año 2013 | jQuery con plugin
Año 2014 | Fetch y node-fetch
Actuales 2019 | Web components
### Técnicas 2005 <a name="version2005"></a>
Mediante el uso de una petición de tipo [XMLHttpRequest](https://developer.mozilla.org/es/docs/Web/API/XMLHttpRequest) se envía un Request a la [API](http://api.icndb.com) usando una [URL](http://api.icndb.com/jokes/random/) para obtener un chiste aleatorio, como se muestra a continuación:
```javascript=
<html>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script type="text/javascript">
window.onload = function () {
let xmlhttp = new XMLHttpRequest();
// Comando (get), url : 'http://api.icndb.com/jokes/random/', asincrono?? => true
xmlhttp.open('GET', 'http://api.icndb.com/jokes/random/', true);
// Asignamos la función callback de respuesta
xmlhttp.onreadystatechange = function(){
// Creamos un objeto con JSON
let textoChiste = JSON.parse(this.response).value.joke;
// Imprimimos en consola el texto del chiste
console.log('chiste recibido: ' + textoChiste);
// Buscamos el elemento <p> y lo asignamos a la variable usando querySelector
let p = document.querySelector('p');
// Equivalente => let p = document.getElementsByTagName('p');
p.innerHTML = textoChiste;
}
// Se envia la petición get
xmlhttp.send();
};
</script>
<head> <title>Chuck 2005</title> </head>
<body>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4">Chuck Norris 2005</h1>
<p class="lead">Chiste</p>
</div>
</div>
</body>
</html>
```

*Figura 1: Demostración en el navegador con XMLHttpRequest*
Al hacer uso de un <code>querySelector()</code> en el ejemplo, cargamos el resultado del Chiste Random en el elemento <code>p</code> sin considerar una clase, identificador o posición, por lo tanto, si existieran más elementos de tipo párrafo, el chiste Random se cargaría en todos ellos.
### Técnicas 2006 <a name="version2006"></a>
Mediante una petición usando la librería [jQuery](https://jquery.com/), se envía un Request a la [API](http://api.icndb.com), utilizando una [URL](http://api.icndb.com/jokes/random/) para obtener un chiste aleatorio.
A diferencia de la petición realizada anteriormente, se reduce a pocas líneas la cantidad de código fuente escrito, esto se debe a que la librería jQuery define internamente los mecanismos para enviar una petición (request) y que esta sea de la manera más simplificada y transparente posible para el desarrollador.
jQuery nos permite realizar consultas sobre la estructura del DOM de la web y realizar personalizaciones a medida, como aplicar diferentes estilos y efectos en función de los eventos que definamos. Todo esto mediante el uso de una sintaxis simplificada y fácil de entender, que permite un desarrollo ágil en nuestros proyectos y dismuniye la probabilidad de cometer errores en la codificación.
Si bien es posible realizar la petición utilizando solamente JavaScript, jQuery es mucho menos verboso, es decir, se puede hacer lo mismo con muchas menos líneas de código, y esa es la clave de su éxito. El lema de jQuery es *"escribe menos, haz más"*.
La ejecución usada es la siguiente:
```javascript=
<!DOCTYPE html>
<html lang="en">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<script type="text/javascript">
// $.get es la forma de conectarse por le método get con jQuery
// El segundo parámetro es el callback.
$.get("http://api.icndb.com/jokes/random", (response) => {
// El response ya viene con le json procesado
var textoChiste = response.value.joke;
// Para buscar con jQuery un elemento usamos $(etiqueta)
$('p').text(textoChiste);
})
</script>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chuck 2006 con jQuery</title>
</head>
<body>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4">Chuck Norris 2006 - jQuery</h1>
<p class="lead">Chiste</p>
</div>
</div>
</body>
</html>
```

*Figura 2: Demostración en el navegador con jQuery*
### Técnicas 2013 <a name="version2013"></a>
Se mejora la petición usada con la librería [jQuery](https://jquery.com/), ya que se ejecuta un Request a la [API](http://api.icndb.com) usando una extensión ([plugin](http://code.icndb.com/jquery.icndb.min.js)) propia de la [API](http://api.icndb.com) diseñada para interactuar con jQuery, obteniendo así un listado de chistes aleatorios.
A diferencia de la petición realizada anteriormente, se simplifica aún más la forma de realizar la petición, ya que mediante la invocación de la función <code>icndb.getRandomJokes()</code> podemos enviar como parámetro la cantidad de chistes que deseamos recibir, y si la petición tiene éxito, se retornará un listado de chistes aleatorios.
En el ejemplo se puede diferenciar la forma de escribir las funciones, ya que se hace uso de [Funciones tipo flecha (arrow)](https://www.neoguias.com/funciones-flecha-es6/). Con la función arrow => de ES6, el código del ejemplo anterior se escribe en una sola línea de manera mucho más limpia y clara. CoffeeScript (un metalenguaje que compila a JavaScript) usa también un esquema parecido.
Las Funciones Flecha o Arrow Functions son una nueva sintaxis para definir funciones anónimas en JavaScript de un modo más conciso. Al ser una sintaxis abreviada, nos ahorrará bastante tiempo, además de simplificar el ámbito de la función. Es una de las características más utilizadas de ES6.
El resultado se muestra a continuación:
```javascript=
<!DOCTYPE html>
<html lang="en">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<script type="text/javascript" src="http://code.icndb.com/jquery.icndb.min.js"></script>
<script type="text/javascript">
// Esta línea de código hace todo el trabajo, enviamos la cantidad de chistes que se desea recibir, y se retorna un listado de tipo array, el resultado es cargado a los elementos de una lista HTML
$.icndb.getRandomJokes({number:10,success:(response) =>{response.forEach(element =>{$("ul").append('<li class="list-group-item">'+element.joke+'</li>');});}});
</script>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chuck 2013 con plugin jQuery</title>
</head>
<body>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4">Chuck Norris 2013 - jQuery plugin </h1>
<ul class="list-group">
</ul>
</div>
</div>
</body>
</html>
```

*Figura 3: Demostración en el navegador con plugin jQuery*
### Técnicas 2014 <a name="version2014"></a>
Mediante el uso de una petición basada en la [API FETCH](https://developer.mozilla.org/es/docs/Web/API/Fetch_API), se ejecuta un Request a la [API](http://api.icndb.com) usando una [URL](http://api.icndb.com/jokes/random/) para obtener un chiste aleatorio.
La API Fetch es un estándar publicado por el Grupo de trabajo de tecnología de aplicaciones de hipertexto web, por sus siglas en inglés [WHATWG](https://en.wikipedia.org/wiki/WHATWG), el cual es una organización que mantinene y desarrolla HTML y APIs para las aplicaciones Web. Antiguos empleados de Apple, Mozilla y Opera establecieron el WHATWG en el 2004. Los editores de especificación en el WHATWG investigan y recopilan comentarios para los documentos de especificación.
El grupo WHATWG también tiene un pequeño comité de miembros invitados y autorizados para anular o reemplazar editores de especificación. De acuerdo con su sitio web, WHATWG es una respuesta al W3C's lento progreso en los estándares Web, especialmente HTML, que el W3C dejó de desarrollar para concentrarse en XHTML. El WHATWG mantiene especifiaciones para HTML, DOM, y JavaScript.
A diferencia de las peticiones realizadas anteriormente, el código fuente requerido es poco, y se aborda el uso de promesas ([Promise](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Promise)) las cuales son objetos que nos ayudarán a gestionar de mejor manera las operaciones asíncronas, debido a que una promesa representa un valor que puede estar disponible ahora, en el futuro, o nunca, y mediante el método <code>fetch()</code> se puede gestionar de manera adecuada la petición y sus posibles escenarios.
El código usado se muestra a continuación:
```javascript=
<!DOCTYPE html>
<html lang="en">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<script type="text/javascript">
window.onload = function (){
fetch('http://api.icndb.com/jokes/random')
// Cuando se haya realizado la petición "then" habrá un response
.then(response => {
// Si el response es correcto
if (response.status === 200) {
// Devuelve la respuesta como objeto json
return response.json();
} else {
// De lo contrario nos devolverá un mensaje de error
throw new Error('¡Error con la API!');
}
})
//Luego de haberse ejecutado el window.onload
.then(myJson => {
// Tomamos del ojeto json el valor del chiste
let textoChiste = myJson.value.joke;
// Seleccionamos un elemento HTML <p> usando querySelector
let p = document.querySelector('p');
// Cargamos el chiste al elemento HTML
p.innerHTML = textoChiste;
console.log(myJson);
}).catch(error => {
// Se imprime un error si no se puede ejecutar.
console.error(error);
});
};
</script>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chuck 2014 con Fetch</title>
</head>
<body>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4">Chuck Norris 2014 - Fetch</h1>
<p class="lead">Chiste</p>
</div>
</div>
</body>
</html>
```

*Figura 4: Demostración en el navegador con fetch*
### Web Components <a name="web-components"></a>
Mediante el uso de una petición basada en la [Web Components](https://developer.mozilla.org/es/docs/Web/Web_Components), se ejecuta un Request a la [API](http://api.icndb.com) usando una [URL](http://api.icndb.com/jokes/) para obtener un chiste como resultado del envío de parámetros, dicho chiste se colocará en un web component con etiqueta <code><chuck-norris-joke></code>.
Esta es una manera muy elegante y limpia de realizar peticiones, pues mediante el Web Component, se pueden crear tags personalizados y los mismos serán colocados en cualquier lugar dentro del DOM.
```javascript=
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Chuck 2020 con Web Components</title>
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/skeleton.css">
<script>
(function() {
// Crea el objeto
var HTMLChuckNorrisJokeElement = Object.create(HTMLAnchorElement.prototype);
// Adjunta una función callack
HTMLChuckNorrisJokeElement.attachedCallback = function() {
// Define la lista de parámetros
var queryParameters = [];
// Obtiene el parámetro firstName si es proporcionado
if (this.hasAttribute('firstName')) {
queryParameters.push('firstName=' + this.getAttribute('firstName'));
}
// Obtiene el parámetro lastName si es proporcionado
if (this.hasAttribute('lastName')) {
queryParameters.push('lastName=' + this.getAttribute('lastName'));
}
// Obtiene el parámetro limito si es proporcionado
if (this.hasAttribute('limitTo')) {
queryParameters.push('limitTo=[' + this.getAttribute('limitTo') + ']');
}
// Crea el request
var xhr = new XMLHttpRequest();
// Parametriza el request
xhr.open('GET', 'http://api.icndb.com/jokes/' + (this.getAttribute('joke-id') || 'random') + '?' + queryParameters.join('&'));
// En el evento onload adjunta una función con el response
xhr.onload = function(response) {
// Hace un parse del response como objeto json
var data = JSON.parse(response.currentTarget.response);
// Asigna el chiste al atributo innerHTML del ojeto que creamos
this.innerHTML = data.value.joke;
// Agrega los atributos jokeid y categories
this.setAttribute('jokeid', data.value.id);
this.setAttribute('categories', data.value.categories);
// Hace un bind del objeto
}.bind(this);
// Envía el request
xhr.send();
};
// Agrega al documento la equiteta nueva chuck-norris-joke
document.registerElement('chuck-norris-joke', { prototype: HTMLChuckNorrisJokeElement });
})();
</script>
</head>
<body>
<div class="container">
<div class="row">
<div class="column" style="margin-top: 15%">
<h4>Web Component</h4>
<p>Lista de 6 chistes retornados con distintos parámetros</a>.</p>
<table class="u-full-width">
<thead>
<tr>
<th>Chistes de Chuck Norris</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<chuck-norris-joke></chuck-norris-joke>
</td>
</tr>
<tr>
<td>
<!-- Usamos el Web Component con el parámetro id-->
<chuck-norris-joke joke-id="26"></chuck-norris-joke>
</td>
</tr>
<tr>
<td>
<!-- Usamos el Web Component con el parámetro firstName y lastName-->
<chuck-norris-joke firstName="Carlos" lastName="Román"></chuck-norris-joke>
</td>
</tr>
<tr>
<td>
<!-- Usamos el Web Component con el parámetro firstName y lastName-->
<chuck-norris-joke firstName="Carlos" lastName="Muñoz"></chuck-norris-joke>
</td>
</tr>
<tr>
<td>
<!-- Usamos el Web Component con el parámetro firstName y lastName-->
<chuck-norris-joke firstName="Gabriel" lastName="Villamagua"></chuck-norris-joke>
</td>
</tr>
<tr>
<td>
<!-- Usamos el Web Component con el parámetro firstName y lastName-->
<chuck-norris-joke firstName="Miguel" lastName="Yachimba"></chuck-norris-joke>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="myDIV">
</div>
</body>
</html>
```

*Figura 5: Demostración en el navegador con Web Component*
### Conclusiones <a name="result"></a>
- Con el tiempo se han venido mejorando las técnicas para realizar peticiones (request) hasta lograr que el proceso sea muy simplificado en la actualidad gracias a librerías, APIs o tecnologías como los Web Components.
- Si bien la aparición de ES6 trajo muchas ventajas, en el ejemplo desarrollado con fetch se pudo observar la gran simplicidad y utilidad de las promesas.
- La existencia de Web Hypertext Application Technology Working Group (WHATWG) denota que hay aspectos por mejorar en cuanto a los tiempos de respuesta y difusión de nuevas tecnologías por parte de la World Wide Web Consortium (W3C).
### Bibliografía <a name="references"></a>
- The Internet Chuck Norris Database. (2020, Mayo 1). [API](http://www.icndb.com/api/) Recuperado de: http://www.icndb.com/api/
- Mozilla Foundation. (2020, Mayo 1). [XMLHttpRequest](https://developer.mozilla.org/es/docs/Web/API/XMLHttpRequest) Recuperado de: https://developer.mozilla.org/es/docs/Web/API/XMLHttpRequest
- Resig, J. (2020, Mayo 1). [jQuery](https://jquery.com/) Recuperado de: https://jquery.com/
- The Internet Chuck Norris Database. (2020, Mayo 1). [Plugin jQuery ICNDB](http://code.icndb.com/jquery.icndb.min.js) Recuperado de: http://code.icndb.com/jquery.icndb.min.js
- Lázaro, E. (2020, Mayo 1). [Funciones Arrow](https://www.neoguias.com/funciones-flecha-es6/) Recuperado de: https://www.neoguias.com/funciones-flecha-es6/
- Mozilla Foundation. (2020, Mayo 1). [API Fetch](https://developer.mozilla.org/es/docs/Web/API/Fetch_API) Recuperado de: https://developer.mozilla.org/es/docs/Web/API/Fetch_API
- Mozilla Foundation. (2020, Mayo 1). [Promise](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Promise) Recuperado de: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Promise
- Wikimedia Foundation (2020, Mayo 1). [WHATWG](https://en.wikipedia.org/wiki/WHATWG) Recuperado de: https://en.wikipedia.org/wiki/WHATWG
- Mozilla Foundation. (2020, Mayo 1). [Web Components](https://developer.mozilla.org/es/docs/Web/Web_Components) Recuperado de: https://developer.mozilla.org/es/docs/Web/Web_Components