--- links-as-notes: true toc: true title: Documentación subtitle: Desarrollo de aplicaciones con tecnologías Web author: "`Ekaitz Zárraga `" author-meta: Ekaitz Zárraga lang: es-ES polyglossia-lang: name: spanish license: CC-BY-SA --- # Introducción a la Web La Web nace como una tecnología para intercambio de documentos de hipertexto. Para habilitar el intercambio de hipertexto hace uso de tres componentes principales: - Protocolo de intercambio -> HTTP - Identificación de documentos en la red -> URL - Formato de documentos que soporten enlaces de hipertexto -> HTML Para poder navegar la red de documentos de hipertexto es necesario un software concreto: un navegador. El navegador tiene diferentes tareas: - Visualizar documentos - Descargar documentos - Permitir la navegación a otros documentos (navegar = descargar + visualizar) Los navegadores modernos realizan muchas más tareas de las descritas, pero esa es su esencia. # Protocolo de intercambio: HTTP(s) *HyperText Transfer Protocol*. Protocolo a nivel de aplicación, que funciona sobre TCP. Es un protocolo de intercambio de mensajes en formato texto. Dos versiones: segura (HTTPs), cifrada, y no segura (HTTP), comunicación cruda sin cifrar. Arquitectura cliente-servidor: - El cliente envía consultas - El servidor responde Diferentes métodos para consultar: - *GET* - *HEAD* - *OPTIONS* - *TRACE* - *PUT* - *POST* - *PATCH* - *DELETE* - *CONNECT* Diferentes modos de respuesta - `1XX` - *Info* - `2XX` - *OK* - `3XX` - *Redirect* - `4XX` - *Client error* - `5XX` - *Server error* Estructura de las peticiones y respuestas: - Método / Código de respuesta - Cabeceras (*headers*): parejas clave-valor que indican conceptos adicionales opcionales, relacionados con la conexión - Cuerpo (*body*): Campo opcional para envío de datos Petición de ejemplo (Wikipedia): GET / HTTP/1.1 Host: www.example.com Respuesta de ejemplo (Wikipedia): HTTP/1.1 200 OK Date: Mon, 23 May 2005 22:38:34 GMT Content-Type: text/html; charset=UTF-8 Content-Length: 138 Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux) ETag: "3f80f-1b6-3e1cb03b" Accept-Ranges: bytes Connection: close An Example Page

Hello World, this is a very simple HTML document.

Protocolo **sin estado** usa otros mecanismos para mantener el estado (sesiones): - Cookies: se obtienen por la cabecera Set-Cookie entregada por el servidor y se devuelven en la cabecera Cookie - Campos ocultos en formularios - Tokens: En la cabecera, en cuerpo de la consulta o, a veces, en el querystring > Esto se verá más adelante # Identificador de documentos en la red: URL El esquema completo de un identificador de documento en la red es el siguiente: ``` schema://user:password@host:port/path?querystring#anchor ``` Los campos indicados en la URL son en su mayoría opcionales. En la web, normalmente no se utilizan el campo `user` ni el campo `password`, porque no es una forma segura de conectars, así que el URL queda así (se elimina el caracter `@`): ``` schema://host:port/path?querystring#anchor ``` - El `schema` se refiere al *protocolo* de comunicación a utilizar. En el caso de la web, será `http` o `https`, siendo preferible el segundo para conexiones cuyo contenido deba protegerse. - El `host` indica un identificador de un equipo. Puede ser un nombre de dominio o una dirección IP. - El `puerto` puede ignorarse (quitando también los dos puntos, `:`), y en tal caso tomará por defecto el valor del puerto asignado al `schema` elegido: 80 para HTTP y 443 para HTTPs. - El `path` identifica el documento a seleccionar. Se indica mediante un `path` estilo UNIX desde la raíz del servidor. - El `querystring` indica información adicional de la consulta, su formato es el de parejas *clave* y *valor*, separadas por `&`. Con este formato: `?clave=valor&clave2=valor2&clave3=valor3` - El `anchor` se refiere a un *ancla* que no se envía en la petición pero el navegador utiliza para mover la vista de la página a la zona indicada por el *ancla*, normalmente mediante un atributo `id` en una etiqueta HTML. ## URL relativas y absolutas En caso de que una URL se reciba en el contenido de un documento, no es necesario incluir en ella el `host`, el `schema`, etc. para señalar a otro documento dentro del mismo `host`. Por ejemplo, si se entrega la página: `https://server.com/pages/index.html`, y en el contenido de ésta existe un enlace a la URL `/css/style.css`, el navegador resolverá la URL completa a ese recurso usando la información de la URL actual. Es decir, creará `https://server.com/css/style.css`. Además, el navegador tratará las URLs que sólo incluyan el `path` pero que no parta desde la raíz (`/`) como URLs relativas. > El formato del `path` en la funciona como en un sistema de archivos de UNIX. > Igual que en el sistema de archivos UNIX, usar `..` se refiere a la carpeta > superior. - Las URL **absolutas** parten siempre desde la raíz `/` e indican qué documento debe accederse desde la raíz del servidor. Ejemplo: `/css/style.css` - Las URL **relativas** se resuelven desde el documento actual. Ejemplo: `usuario.html`. Estas URLs por sí mismas no identifican de forma inequívoca un documento, son dependientes del documento donde están escritas. Por ejemplo, si `/paginas/index.html` tiene un enlace a `usuario.html`, éste se resolverá a `/paginas/usuario.html` pero si la página con el enlace es simplemente `/index.html` éste se resolverá a `/usuario.html`. Conocer los diferentes tipos de URL es muy útil a la hora de estructurar el contenido de modo que sea fácil de reorganizar. Tratar de reducir la longitud de las URLs escritas en un documento HTML es fundamental para facilitar la lectura del documento. # HTML *HTML: HyperText Markup Language* HTML es un **formato semántico** basado en XML. Para aprender HTML lo mejor es seguir la documentación en [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Learn/HTML) Muestra contenido, basándose en su significado lingüístico/lógico: párrafo (`p`), imagen (`img`), enlace (`a`), sección (`section`), artículo (`article`), cita (`quote`, `blockquote`), títulos de diferentes niveles (`h1`, `h2`...), etc ## Sintaxis HTML ``` xml cuerpo ``` También existen elementos vacíos, cuya etiqueta de apertura también aplica el cierre, ya que no pueden tener contenido: ``` html ``` ## Un documento HTML Plantilla de un documento HTML mínimo: ``` html Título de HTML mínimo ... ``` ## La cabecera (head) El HTML también sirve para indicar metadatos para que el navegador conozca información adicional sobre el documento. Estos se incluyen en el apartado ``. Algunos interesantes son: - La declaración del encoding: `` - La declaración de viewport, interesante para visualización en dispositivos móviles: `` - El título de la página: `` - La inclusión de documentos relacionados como hojas de estilo e iconos mediante `<link>` ## El cuerpo (body) El cuerpo (`<body>`) del HTML debe incluir el apartado visible del documento. Usa etiquetas semánticas para describir el contenido. Algunos ejemplos: - `<main>`: Indica la parte principal del contenido del documento. - `<section>`: Indica una sección del documento. - `<article>`: Indica una pieza de información que se puede considerar una entidad única. Existen muchos componentes HTML. [MDN mantiene una referencia actualizada][html-ref] de todos los componentes HTML disponibles, su significado, su compatibilidad con los principales navegadores y una detallada explicación de qué atributos estándar pueden utilizar. [html-ref]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element ### Formularios Los formularios son un componente muy importante de la web. > TODO discutir los formularios cuando haya un back-end con el que probar # CSS *CSS: Cascading StyleSheets* El HTML sólo almacena información semántica. Las hojas de estilos son documentos adicionales que pueden enlazarse a documentos HTML para indicar el estilo de éstos. Para aprender CSS lo mejor es seguir la documentación de [MDN Web Docs][css] [css]: https://developer.mozilla.org/en-US/docs/Learn/CSS Este es el formato de una regla CSS mínima: ``` css selector { propiedad: valor; /* Esta pareja se conoce como "declaración" */ } ``` Los [selectores][selector] funcionan en [cascada][cascade], de más genérico a más concreto (especificidad, *specificity*). Siendo los más concretos aplicados después, añadiendo sobre (y sobreescribiendo) las declaraciones aplicadas previamente. El órden de declaración también es relevante. [selector]: https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors [cascade]: https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance > Recientemente se ha añadido el concepto [*Cascade > Layer*](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_layers) > lo que permite controlar de forma más avanzada los conceptos de especificidad > y cascada. La [herencia][cascade] también es un concepto importante. Indica que si un elemento está contenido en otro hereda las propiedades del componente padre. Por ejemplo, si un `body` define la fuente con un tamaño concreto, todos sus hijos (y los hijos de estos) aplicarán ese tamaño de fuente, a no ser que se especifique lo contrario. La herencia permite, por tanto, aplicar propiedades a objetos sin tener que seleccionarlos de forma directa con un selector. Esto también significa que mover un elemento HTML de un contenedor a otro puede cambiar su estilo, debido a que puede heredar nuevas reglas CSS de su nuevo contenedor. Aprender CSS requiere de tiempo, ya que existen varios tipos de selectores y combinaciones entre ellos e infinidad de propiedades, cada una con una gran variedad de valores posibles. Una vez entendidos los conceptos de la [guía de MDN][css] de forma general, la mejor manera de aprender es ir trabajando y aprendiendo a realizar operaciones concretas con el tiempo. Tener los conceptos básicos es primordial, eso sí, pero tampoco son demasiados. # JavaScript [Curso rápido de JavaScript][js-crash] [Curso de JavaScript][js] [Curso detallado de JavaScript][js-deep] [Contexto de las tecnologías de JavaScript][js-overview] [js-crash]: https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics [js]: https://developer.mozilla.org/en-US/docs/Learn/JavaScript [js-deep]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide [js-overview]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/JavaScript_technologies_overview La estructura básica del lenguaje es primordial conocer. Diferenciar los tipos de dato básicos, qué es una **sentencia** (*statement*) y qué es una **expresión** (*expression*). En JavaScript las funciones son valores, como cualquier otro. Y pueden recibirse como argumentos y retornarse como valores de retorno. ## Scope Las variables declaradas con `var` viven en todo el cuerpo de la función donde se declararon. Aplica [*hoisting*][hoisting]. Las declaraciones de función son equivalentes a usar `var`. [hoisting]: https://developer.mozilla.org/en-US/docs/Glossary/Hoisting Con la aparición de ES6 (ECMAScript 6) se añaden `let` y `const` cuyo ámbito (*scope*) se limita al bloque actual. No aplica [*hoisting*][hoisting]. ## Closures El *scope* (ámbito) en JavaScript es **léxico** (*lexical scope*) y para implementarlo se utilizan *closures*. Una *closure* aparece cuando una función captura el contexto en el que fue creada para recordar una o más variables: ``` javascript function incrementador( incremento ){ return (function (valor){ // Se captura el contexto porque `incremento` no está definido en la // función interna, sino en `incrementador` return valor + incremento; }) } let masDiez = incrementador (10); let masVeinte = incrementador (20); masDiez(1) // => 11 masVeinte(1) // => 21 ``` ## Objetos Los objetos son fundamentales en JavaScript. Son colecciones de valores, cada uno asignado a una clave (string). > Los `Array` son realmente un tipo de objeto con claves numéricas ### Programación orientada a objetos (OOP) Conceptos principales de la **programación orientada a objetos basada en clases**: - **Polimorfismo**: no es aplicable en JavaScript, porque al ser un lenguaje dinámico se acerca más al [*duck-typing*](https://en.wikipedia.org/wiki/Duck_typing). - **Herencia**: que las clases puedan definirse como subclases de otras, adquiriendo sus características. Las subclases pueden especificar comportamiento propio sobreescribiendo el comportamiento de la superclase. - **Encapsulación**: aislar los campos internos de los objetos del exterior para mantener sus invariantes y asegurarse de que la información dentro del objeto es siempre coherente. - **Identidad**: que cada objeto tenga noción de sí mismo. Se realiza mediante el `this`. #### Orientación a prototipos **Realmente JavaScript implementa un sistema de orientación a objetos basado en prototipos** que permite emular el comportamiento de un sistema basado en clases, pero que es en realidad mucho más flexible. La programación orientada a objetos basada en prototipos nace con el objetivo de clasificar los objetos en función de su *semejanza* a otros, en lugar de si pertenecen o no a una *clase*. Pero la *semejanza* es un concepto tan fuerte que realmente permite implementar clases. [La guía básica de MDN introduce estos conceptos][js-oop] [js-oop]: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects Los objetos de JavaScript pueden tener un **prototipo** (*prototype*). El prototipo es otro objeto. Cuando se hace referencia a una propiedad o método de un objeto si éste no lo tiene entre sus elementos, se busca en su prototipo. Los prototipos también pueden tener prototipos. Esta cadena de búsqueda se conoce como *prototype chain* (cadena de prototipos) y es la que permite implementar lógicas de relación entre objetos, ya sean basadas en *clases* o en *semejanza*. Es un mecanismo simple pero muy poderoso. Debida a la flexibilidad del lenguaje [hay muchas formas de programar mediante orientación a objetos en JavaScript][csstricks-js-oop-flavors]. La forma más moderna se introdujo en ES6: `class`, pero es equivalente al sistema clásico con funciones constructoras y el operador `new`. [Este artículo muestra la orientación a objetos de forma incremental][oop-codecamp]. [csstricks-js-oop-flavors]: https://css-tricks.com/the-flavors-of-object-oriented-programming-in-javascript/ [oop-codecamp]: https://www.freecodecamp.org/news/a-beginners-guide-to-javascripts-prototype/ #### Identidad En JavaScript es muy importante controlar la identidad de los objetos: el `this`. En ocasiones, como al enviar un método de un objeto como argumento a una función, el `this` se pierde y el método pierde su identidad. Es por eso que debe controlarse con mucho cuidado. Un ejemplo: ``` javascript function Human(name){ this.name = name; this.greet = function(){ console.log(`Hola, soy ${this.name}`); } } let ekaitz = new Human("Ekaitz"); ekaitz.greet() // => "Hola, soy Ekaitz" setTimeout(ekaitz.greet, 100); // => "Hola, soy" // Al separar el método de su objeto, se pierde el `this`, que se vuelve // undefined, y no se imprime en pantalla setTimeout(ekaitz.greet.bind(ekaitz), 100) // => "Hola, soy Ekaitz" // Gracias al método `bind` de las funciones, es posible asignar el this para // el futuro ``` Otro operador interesante a comprender es [`new`][new], que habilita la forma más cómoda y usada de crear nuevos objetos y asignarles un prototipo automáticamente. [new]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new ### JSON JSON es la notación de objetos de JavaScript (*JavaScript Object Notation*), una forma de codificar objetos de JavaScript en texto para facilitar su intercambio. Es muy común (y sencillo), por lo que debe conocerse en detalle. Desde JavaScript, convertir JSON a un objeto y viceversa es trivial: ``` javascript JSON.parse( texto_json ) // Devuelve un objeto obtenido desde el JSON JSON.stringify( objeto ) // Devuelve un string JSON con el contenido del objeto ``` ## Asincronía El entorno de ejecución de JavaScript (*Runtime*) está diseñado de forma asíncrona, alrededor de un bucle de eventos (*Event Loop*). La mayor parte de las operaciones que requieren algún tipo de espera se procesan en un segundo plano por parte del runtime y cuando se resuelven son encoladas para que el programa las procese más tarde. Los procesos encolados sólo se resuelven cuando la pila de ejecución está vacía, por lo que es importante liberar la ejecución lo antes posible y permitir así que el runtime pueda realizar su trabajo. Este sistema es muy característico de JavaScript y debe conocerse en detalle. Para más información, visitar [la documentación de MDN][event-loop] o ver [la famosísima charla de Philip Roberts][charla-jsconf]. [event-loop]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop [charla-jsconf]: https://www.youtube.com/watch?v=8aGhZQkoFbQ ### Promesas Las promesas son un sistema elegante para resolver los casos de ejecución de código asíncrono evitando concatenar muchos *callbacks*. Las promesas son objetos con dos campos principales. Uno que almacena su estado y otro que almacena su valor, en caso de que el estado sea el adecuado. El estado de una promesa puede tener uno de estos tres valores: - `"pending"` para representar que la promesa no se ha resuelto aún - `"fulfilled"` para representar que la promesa ha sido resuelta correctamente y por tanto ya tiene un valor disponible - `"rejected"` para representar que ha ocurrido un error en la resolución de la promesa y no ha podido resolverse Las promesas aportan dos métodos principales, para gestionar el código asíncrono: - `then( funcion )` la función enviada se ejecutará cuando la promesa se resuelva, recibiendo como argumento el valor de la promesa. Si la función enviada retorna un valor, éste se envolverá en una promesa nueva para poder resolverla con un `then` concatenado - `catch( función )` la función enviada se ejecutará cuando la promesa falle con alguna excepción Las llamadas a `then` pueden concatenarse para realizar operaciones de forma secuencial (este es el interés principal de las promesas): ``` javascript function obtenerDitto(){ fetch("https://pokeapi.co/api/v2/pokemon/ditto") // fetch retorna una promesa .then((r)=>r.json()) // Procesa la respuesta como JSON, y retorna otra promesa .then((data)=>console.log(data)) // Recibe los datos ya procesados .catch( procesarError ) // Captura cualquier error ocurrido en el proceso } ``` #### `async` y `await` Las palabras reservadas `async` y `await` son azúcar sintáctico (*syntactic sugar*) sobre el sistema de promesas. Definir una función como `async` permite realizar la operación `await` dentro de ésta, permitiendo tratar código asíncrono de forma similar al código síncrono. El ejemplo anterior traducido a esta sintaxis: ``` javascript async function obtenerDitto(){ try { let respuesta = await fetch("https://pokeapi.co/api/v2/pokemon/ditto"); let data = await respuesta.json(); console.log(data); } catch( err ) { procesarError(err); } } ``` ## Resumen El JavaScript aquí mencionado cubre casi todo el uso básico. La [guía profunda][js-deep] explica todo en mucho más detalle y añade más información. # Programación del lado de cliente ## Web APIs Las Web APIs del navegador aportan a JavaScript infinidad de funcionalidades que le permiten operar con éste. > NOTA: en el lado del servidor la mayoría de las Web APIs no están > disponibles, pero hay otras que realizan tareas más relacionadas con el lado > del servidor: acceso al sistema de archivos, sockets, etc. Un gran ejemplo del uso de la API Canvas, gestión de eventos y la API de audio es la implementación del [Space Invaders de Susam Pal][space-invaders]. [space-invaders]: https://github.com/susam/invaders ### DOM El DOM (*Document Object Model*) es la representación del documento en la memoria. Esto es, la forma en la que el navegador entiende el documento HTML, su estilo y funcionalidad. > Esta API no se limita al navegador, sino que puede implementarse en otros > entornos y lenguajes. Simplemente describe una forma de interactuar con este > sistema de representación. La API del DOM permite acceder al DOM e interactuar con él de forma imperativa. El DOM es un árbol de elementos. Para que algo se visualice es necesario añadirlo al árbol principal, el método `document.createElement(tag)` crea un nuevo elemento, pero aislado del árbol. Este elemento deberá engancharse al árbol para que se procese y visualice. La [introducción de MDN sobre el DOM es bastante accesible][dom-mdn]. La documentación de referencia puede ser demasiado complicada. [dom-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction ### Peticiones Web: fetch La API fetch es el método moderno para realizar peticiones Web. Anteriormente esta funcionalidad se realizaba mediante una API mucho menos amigable conocida como XHR (*XML HTTP Request*). La API fetch está basada en promesas y su uso básico se muestra en el apartado previo sobre éstas. También puede realizar peticiones complejas, procesar datos en streaming, y un largo, etc. [La documentación de MDN describe el uso básico de fetch en la guía correspondiente][fetch-mdn] [fetch-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch ## Librerías Front End comunes ### Mithril Es un mini-framework basado en componentes. Extremadamente sencillo pero muy potente. Dispone de funcionalidades para: - Routing - Peticiones Web simplificadas basadas en promesas (similares a `fetch`) - Renderizado de componentes - Actualización de componentes automática cuando su estado cambia - Soporta sintaxis JSX mediante plugins Es diminuto (~1kLoC) por lo que puede estudiarse con facilidad. ### React [Tutorial de react en video][react-tutorial] [react-tutorial]: https://www.youtube.com/watch?v=QFaFIcGhPoM&list=PLC3y8-rFHvwgg3vaYJgHGnModB54rxOk3&index=1 # Programación en el lado del servidor En este curso se usa el entorno de ejecución NodeJS para trabajar en el lado del servidor, que también se programa en JavaScript. NodeJS es diferente que el entorno de ejecución de JavaScript en el navegador. En en lado del servidor las Web APIs no están disponibles del mismo modo que en el navegador, ya que el entorno en el que se ejecuta es diferente: el navegador es un programa visual, interactivo diseñado para hacer consultas Web que aporta JavaScript como un lenguaje de extensiones mientras que NodeJS es un entorno de ejecución de aplicaciones que por defecto no es gráfico. El entorno del servidor se parece más a la programación clásica, ya que no se ejecuta en el Sandbox del navegador: se dispone de acceso a archivos, interfaces de red y otros recursos del sistema, que en el navegador no están disponibles. ## Frameworks de Back End ### Express [Express][express] es un framework (para NodeJS) de programación Web de lado del servidor. Su funcionamiento interno se centra en un único concepto: el **middleware**. En Express el *middleware* se refiere a funciones que se ejecutan al recibir consultas Web. Cada función *middleware* se registra en la aplicación, para una ruta y método HTTP y se ejecutará cuando esta ruta y método sean accedidos por algún cliente. Como cada ruta y método pueden registrar varias funciones de *middleware* es responsabilidad de cada función de *middleware* decidir si se pasa a la siguiente o si se envía una respuesta, obviando el *middleware* restante. La [documentación de Express dispone de unas guías que describen el funcionamiento a la perfección][express] [express]: https://expressjs.com ### Flask [Flask][flask] es un framework de programación en el lado del servidor, muy similar a Express, pero para el lenguaje Python. [flask]: https://flask.palletsprojects.com/en/2.2.x/ ### Otros Hay infinidad de lenguajes y frameworks en los que realizar aplicaciones web del lado de servidor. Aquí una lista de algunos muy usados: - PHP: Laravel, Symfony - Python: Flask, Django - Java: Spring - Ruby: Sinatra, Ruby on Rails - NodeJS: Express, Koa ## Anatomía de una aplicación Web Una aplicación Web del lado del servidor debe recibir consultas de los clientes, procesarlas y retornar una respuesta. Las repuestas suelen ser documentos HTML, frecuentemente construidos de forma dinámica en el servidor basándose en plantillas de documentos escritas previamente e información adicional, normalmente obtenida desde una base de datos. Además del HTML, las aplicaciones Web suelen ser capaces de servir archivos estáticos tales como imágenes, archivos JavaScript para el lado del cliente, hojas de estilos CSS y otros. Estos se entregarán directamente, sin procesar. <!-- # Apéndice: Test-Driven development (TDD) [Un tutorial con Jest muy sencillo][jest-tuto] [jest-tuto]: https://www.youtube.com/watch?v=G43sWqt8T98 [jest-tuto-mejor]: https://www.youtube.com/watch?v=FgnxcUQ5vho [intro-tdd]: https://khalilstemmler.com/articles/test-driven-development/introduction-to-tdd/ # Apéndice: El gestor de paquetes de NodeJS (NPM) -->