realwebprogramming - repositorio.uniandes.edu.co
TRANSCRIPT
Dissertation
REAL WEB PROGRAMMING
LUIS CARLOS GARAVITO ROMERO
2 de junio de 2020
This thesis is submitted in partial fulfillment of the requirements
for a degree of Bachelor in Systems and Computing Engineering.
Thesis Committee:
Prof. Nicolas Cardozo (Promotor)
REAL WEB PROGRAMMING
© 2020 LUIS CARLOS GARAVITO ROMERO
Systems and Computing Engineering Department
FLAG lab
Faculty of Engineering
Universidad de los Andes
Bogotá, Colombia
This manuscript has been set with the help of TEXShop and PDFLATEX (with BibTEX support).
Bugs have been tracked down in the text and squashed thanks to Bugs in Writing by Dupré [4]
and Elements of Style by Strunk and White [5].
iii
Abstract
Actualmente el desarrollo web se encuentra en una etapa donde frameworks como Node.js,
php, Angular.js o React.js reinan en el mercado. Sin embargo, aveces estas tecnologías no son
lo suficientemente ágiles y seguras para las necesidades actuales de la industria. Es aquí donde
Rust y WebAssembly se presentan como una alternativa moderna y prometedora para el futuro
de la web.
En este documento se presenta un estudio para el desarrollo de aplicaciones web basadas
en código Rust y WebAssembly. En particular, se propone un modelo de desarrollo de manera
práctica haciendo uso de los frameworks más reconocidos actualmente para estas tecnologías,
específicamente Rocket.rs y Yew.rs. En primer lugar, se realiza un estudio del estado actual
de estas tecnologías, para luego desarrollar, de manera incremental, un sistema separado por
back-end y front-end.
El experimento concluye en que estas tecnologías, a pesar de encontrarse en constante evolu-
ción, son una alternativa bastante segura y eficaz a la hora de desarrollar aplicaciones para la
web. Además, cada día los navegadores modernos añaden más soporte para ellas.
v
Índice general
Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iiiÍndice de figuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.1 Contexto: Programación Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32. Preliminares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.1 Rust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2 Web Assembly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63. Evaluación de Frameworks utilizados . . . . . . . . . . . . . . . . . . . . . . . . . 73.1 Nickel.rs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73.2 Rocket.rs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83.3 Yew.rs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94. Aplicación: Sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115. Aplicación: Crear una aplicación con Rust . . . . . . . . . . . . . . . . . . . . . . 136. Aplicación: Implementación del sistema . . . . . . . . . . . . . . . . . . . . . . . 176.1 Back-end . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176.2 Front-end . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207. Conclusión y trabajo futuro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31Bibliografía . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
vi
vii
Índice de figuras
3.1. Hola Mundo en Nickel.rs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83.2. Hola Mundo en Rocket.rs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.1. Arquitectura del sistema a construir . . . . . . . . . . . . . . . . . . . . . . . . . 12
5.1. Estructura de un proyecto creado con Cargo . . . . . . . . . . . . . . . . . . . . . 14
6.1. Arquitectura de una aplicacion con create-yew-app . . . . . . . . . . . . . . . . . 226.2. Interfaz por defecto con create-react-app . . . . . . . . . . . . . . . . . . . . . . . 236.3. Interfaz por defecto con create-yew-app . . . . . . . . . . . . . . . . . . . . . . . 236.4. Componente “topics” de la aplicación. . . . . . . . . . . . . . . . . . . . . . . . . 276.5. Resultado de la ejecución del comando “npm run build” . . . . . . . . . . . . . . 29
1
Capítulo1Introducción
1.1. Contexto: Programación Web
La web y el internet no siempre han sido como actualmente los conocemos, estos dos conceptos
han pasado por diferentes etapas y definiciones en las que, con el paso del tiempo, se han ido
enriqueciendo con nuevas tecnologías y adaptándose a las diferentes necesidades e ingenio del
hombre moderno.
La historia de la web comienza en 1985, naciendo como una necesidad entre los investigadores
de la Organización Europea para la Investigación Nuclear (CERN, por sus siglas en inglés) de
tener un sistema que permitiera compartir información de manera fácil. Ese año se puso en
marcha el primer servidor Web en Ginebra, Suiza, de la mano de Tim Berners-Lee, a quien se
le atribuye la primera versión del lenguaje HTML aunque esto no haya sido publicado de forma
oficial.
Cientificos y universidades de todas partes del mundo continuaron desarrollando el sistema
de Tim Berners-Lee, ya que era de código abierto. Mientras que, en los siguientes cuatro años,
diferentes empresas sacarían al mercado sus diferentes ofertas en navegadores como Mosaic y
Netscape. También durante este tiempo la web dejó de ser exclusivamente para universidades y
centros de investigación y pasó a ser lugar también de empresas y particulares.
En 1994 Berners-Lee fundó el World Wide Web Consortium (W3C), una organización formada
entre empresas, universidades y organizaciones sin ánimo de lucro que comenzarían a desarrollar
las siguientes versiones de HTML y CSS organizados en grupos de trabajo.
Introducción
Desde el año 1995 ocurrió la famosa "Guerra de los navegadores"donde principalmente Nets-
cape e Internet Explorer lanzaban nuevas características cada año, hecho que puso en peligro la
estandarización de la web debido a la fragmentación entre las diferentes funcionalidades de cada
proveedor. Sin embargo, la W3C lanzó para esto diferentes recomendaciones y sugerencias de
estándares que sugerían, por ejemplo, una separación entre la lógica (HTML) y el estilo(CSS) en
las páginas web.
La llegada de Javascript también ocurrió en ese mismo año. Un nuevo lenguaje que podía
ejecutarse directamente en el navegador y que agregaba muchas más funcionalidades a las pá-
ginas web, haciendo que dejaran de ser completamente estáticas y que ahora pudieran ejecutar
funciones más avanzadas, como actualizar el contenido sin que el usuario tuviera que recargar la
página. Su mantenimiento, desarrollo y estandarización estuvo a cargo de la organización ECMA,
quienes publicaron las primeras normas oficiales en 1997. En 1998 se creó la organización Mo-
zilla, a quienes Netscape donó el código de su navegador para que fuese publicado como código
abierto.
En el año 2000 se dejó a un lado el desarrollo de HTML para enfocarse en un nuevo estándar
llamado XHTML, que incluía soporte para etiquetas XML y se ajustaba a las nuevas necesidades
del desarrollo web en el mundo. Sin embargo, para este año Internet Explorer ya era el rey de
los navegadores y, al desaparecer por completo Netscape, Microsoft decidió no desarrollar más
versiones de su navegador, el cual ya se encontraba en su versión número 6. Para ese entonces la
W3C había trabajado bastante en nuevos estándares y recomendaciones para XHTML y CSS2,
pero Internet Explorer no implementaba ninguno de ellos, ni siquiera admitía documentos XML.
Lo anterior hizo que no se publicaran recomendaciones ni estándares durante mucho tiempo,
salvo unas pequeñas sugerencias relacionadas con lenguajes de marcas como SVG y MathML.
A raíz de esta situación Mozilla comenzó a desarrollar su propio navegador siguiendo todos los
estándares de la W3C y convirtiéndose en el principal rival de Internet Explorer.
En el año 2004 se creó la Fundación Mozilla, quién continuaría fuertemente el desarrollo de su
navegador Firefox y obligaría a Microsoft a continuar el desarrollo de Internet Explorer. La W3C
y una nueva organización llamada WHATWG decidieron continuar el desarrollo olvidado de
HTML, bajo el nombre de HTML5. En el año 2009, Google saca al mercado su propio navegador
Google Chrome, bastante particular gracias al modelo de desarrollo frenético con actualizaciones
2
1.2 Objetivos
cada dos meses.
Hacia el año 2011 se renuncia al desarrollo de XHTML y todos los esfuerzos se concentran en
sacar las siguientes normas para HTML5. Firefox también cambia su modo de actualizaciones al
mismo de Google Chrome, sacando actualizaciones cada dos meses mientras Internet Explorer
seguía ligado a las actualizaciones de Windows. En el año 2013 Firefox anuncia “asm.js”, un
conjunto de herramientas de Javascript que permitía ejecutar código de otros lenguajes, princi-
palmente C y C++ directamente en el navegador. En este mismo año Microsoft decide crear un
nuevo navegador llamado Edge para cumplir los nuevos estándares de la Web, el cual seguiría
ligado a nuevas actualizaciones de Windows 10, mientras Google Chrome se posiciona como el
navegador más utilizado.
A pesar de que en el año 2016 el navegador más utilizado es Google Chrome, las nuevas normas
para HTML y Javascript se han mantenido más actualizadas que nunca. En este mismo año el
W3C cierra todos sus grupos de trabajo relacionados con XML. En los años siguientes se anuncia
que las nuevas versiones del navegador Edge de Microsoft estarían basadas en el motor de Google
Chrome, Chromium.
En el año 2017 es cuando se presenta por primera vez, de la mano de Firefox y Chrome, la
nueva tecnología WebAssembly, un nuevo estándar de código binario basado en Javascript que
prometía un rendimiento casi nativo para las aplicaciones web y permitiendo compilar código
desde casi cualquier lenguaje de programación. Las primeras recomendaciones de la W3C salieron
en diciembre del año 2019, después de que en junio de ese mismo año Google presentara una
versión de su aplicación Google Earth en esta tecnología.
1.2. Objetivos
Experimentar en el uso de nuevas tecnologías para el desarrollo web, específicamente con
WebAssembly.
Investigar el estado actual de WebAssembly y el lenguaje de programación RUST.
Hacer una comparativa entre RUST/WebAssembly y las tecnologías actuales para desarro-
llo web.
3
5
Capítulo2Preliminares
2.1. Rust
Rust es un lenguaje de programación multiparadigma creado por Mozilla en el año 2015. Puede
ser usado tanto para programación funcional como imperativa y orientada a objetos. Cabe resaltar
que Rust es un lenguaje compilado, lo que permite aprovechar todas sus ventajas como código
de máquina en cuanto a velocidad y rendimiento.
Cuando usamos Rust podemos ver que usa su propio gestor de paquetes llamado “Cargo”, con
él podemos compilar nuestros propios paquetes, encapsularlos para distribuirlos y hasta cargar
y descargar dependencias de terceros para nuestros proyectos. Todas estas dependencias son
almacenadas en crates.io, el registro de paquetes de la comunidad de Rust, algo así como npm
para Node.js y javascript.
Otra característica importante de Rust es que, a diferencia de lenguajes como java, no cuenta
con un recolector de basura, de modo que el mismo programador debe encargarse del manejo de
memoria de la aplicación. Sin embargo, lo anterior no es para preocuparse demasiado ya que Rust
literalmente nos obliga a escribir código correctamente y nos avisa de posibles irregularidades a
la hora de compilar.
Rust es considerado un lenguaje bastante seguro, no solamente con el manejo de tipos a la hora
de programar sino con el uso de la memoria, de allí el hecho de que no cuente con un recolector
de basura, ya que el compilador se encarga de revisar ubicaciones de memoria incorrectas o
referencias nulas. Según Balbaert [2], Rust soluciona todos los problemas de memoria que ocurrían
Preliminares
en lenguajes como C/C++.
Rust también es considerado como el lenguaje de programación más querido por los desarro-
lladores desde el año 2016 según la encuesta anual de Stackoverflow1, donde en el año 2019 fue
seguido por TypeScript y Python en esta categoría.
2.2. Web Assembly
Web Assembly es un lenguaje de bajo nivel para la web, muy similar a lo que se conoce hoy en
día como Assembler o Lenguaje Ensamblador ya que se compila para luego ser ejecutado como
código de máquina de manera casi nativa en el navegador.
Para trabajar con esta tecnología no es necesario escribir directamente los archivos con exten-
sión .wasm necesarios para ser ejecutados en el navegador, ya que la idea principal del desarrollo
en WebAssembly es poder trabajar con lenguajes de más alto nivel para luego compilar ese código
al formato deseado. Actualmente los lenguajes con los que normalmente se trabaja son C, C++
y, el más soportado, Rust.
El objetivo de desarrollar para la web con Web Assembly es reducir el tamaño del código que
se descarga cuando se accede a una página y minimizar el tiempo de ejecución de las tareas que
normalmente se llevarían a cabo únicamente con JavaScript, lo anterior es posible gracias a que
el tiempo de interpretado se hace practicamente nulo debido a que la ejecución del código se hace
de manera nativa. Cabe resaltar que WebAssembly no pretende reemplazar JavaScript, sino que
está diseñado para que ambos lenguajes trabajen a la par.
El ciclo de desarrollo con esta tecnología inicia escribiendo el código correspondiente en C,
C++, Rust o cualquiera de los lenguajes que actualmente ya se encuentran soportados2. Después
se debe compilar este código a archivos con extensión .wasm que luego serán montados con ayuda
de javascript para su ejecución en el navegador.
1https://insights.stackoverflow.com/survey/20202https://github.com/appcypher/awesome-wasm-langs
6
7
Capítulo3
Evaluación de Frameworks utilizados
Antes de empezar a construir una aplicación con Rust y WebAssembly es conveniente investigar
los diferentes Frameworks o bibliotecas que actualmente existen para estas tecnologías. Cabe
recordar que para usar la tecnología WebAssembly podemos escoger cualquiera de los lenguajes
de programación que ya tienen un compilador para archivos .wasm, sin embargo, para efectos
de este proyecto usaremos solamente el lenguaje de programación Rust debido a que es el que
mayor soporte tiene en el uso de esta tecnología.
Debido a que vamos a trabajar con Rust y necesitaremos construir una aplicación web más
adelante, es conveniente hacer un estudio de los diferentes frameworks que actualmente existen
para este lenguaje. los frameworks que se decidieron estudiar por su popularidad y madurez en
la actualidad fueron tres; Yew.rs, Nickel.rs y Rocket.rs, donde el primero se usa para front-end
y los dos restantes para back-end. A continuación se hará una pequeña exposición de cada uno
de ellos.
3.1. Nickel.rs
La filosofía de Nickel.rs es ser un framework simple y liviano con el que se pueda escribir
aplicaciones web y API’s completamente en Rust. Todas sus instrucciones de uso se encuentran
en su página web1 y su repositorio. Su principal particularidad es su gran parecido con Express.js,
el framework de javascript para aplicaciones web en el que se encuentra inspirado, hecho que1http://nickel-org.github.io/
Evaluación de Frameworks utilizados
podemos evidenciar en la Figura 3.1.
Dentro de su documentación se evidencia soporte para Flexible routing, que consiste en definir
de forma dinámica las diferentes rutas para acceder a los servicios REST de la aplicación. También
permite el manejo total de objetos de tipo JSON, Middleware para las rutas de acceso, manejo
de errores y hasta motores de plantillas para manejar de forma mucho más sencilla los archivos
HTML.
En su repositorio podemos encontrar varios ejemplos donde nos muestran cómo se hace el
manejo de las plantillas, puntos de acceso a los datos y hasta autenticación de usuarios. Ac-
tualmente, Nickel.rs cuenta con más de 2700 estrellas en Github y es considerado uno de los
frameworks de Rust más populares para la web. La Figura 3.1 nos muestra cómo sería un “Hola
Mundo” en Nickel.rs.
Figura 3.1: Hola Mundo en Nickel.rs
3.2. Rocket.rs
El framework Rocket.rs se destaca por su gran popularidad dentro de la comunidad de Rust.
Actualmente cuenta con más de 10900 estrellas en su repositorio de Github y es el más soportado
en cuanto a actualizaciones y desarrollo.
En su sitio web, Benitez [3], su creador y más activo contribuyente del proyecto, describe a
8
3.3 Yew.rs
Rocket como un framework web que simplifica la creación de aplicaciones web rápidas y seguras
sin sacrificar la flexibilidad, facilidad de uso o la seguridad de tipos. Además, también pone
a disposición de los desarrolladores toda la documentación necesaria para trabajar con esta
tecnología.
Entre las características más importantes de este framework tenemos: el manejo de diferentes
rutas a la hora de solicitar los recursos, manejo de diferentes tipos de errores, soporte con motores
de plantillas, manejo de autenticación y cookies, uso de objetos tipo JSON, integración con
diferentes tipos de bases de datos como MySQL, Postgres, MongoDB, entre otras, herramientas
para Testing y varias funciones más que hacen de Rocket una opción bastante atractiva para los
desarrolladores. La Figura 3.2 nos muestra ahora cómo sería un “Hola Mundo” en Rocket.rs.
Figura 3.2: Hola Mundo en Rocket.rs
3.3. Yew.rs
Según su página oficial [1], “Yew es un framework para crear aplicaciones web front-end multi-
proceso con WebAssembly”. Esta descripción es muy interesante debido a que este framework se
enfoca precisamente en el front-end, lo que permite explotar todas las características de Rust y
llevar este lenguaje al límite generando el código .wasm correspondiente que luego será ejecutado
directamente en el navegador.
Es posible afirmar que Yew.rs es para Rust lo que React.js es para Javascript ya que ámbos
tienen un funcionamiento basado en componentes y manejan un estado en la aplicación.
Su repositorio cuenta con más de 12600 estrellas, pero sus creadores han agregado otros repo-
9
Evaluación de Frameworks utilizados
sitorios con desarrollos hechos a partir de Yew, como yew-router, una biblioteca de enrutamiento
muy similar a react-router, o yewtify, otra biblioteca con componentes de css listos para ser
utilizados a la hora de crear una aplicación.
Una característica importante es la interoperabilidad con Javascript ya que, gracias a maneja-
dores de paquetes como NPM, es posible integrar bibliotecas ya existentes en nuestra aplicación
sin ningún problema.
Dentro de la misma documentación de Yew nos encontramos con algunos tutoriales2 para
comenzar a usar esta tecnología, sin embargo, nos recomiendan que para crear una aplicación
desde cero es conveniente usar alguna plantilla, como por ejemplo yew-parcel-template3. Sin
embargo, para obtener una experiencia de desarrollo más cómoda y aprovechar las ventajas de
npm, me parece más conveniente usar la herramienta create-yew-app4. La ventaja de usar este
tipo de plantillas es que se obtiene todo un entorno preconfigurado con toda la estructura de un
proyecto sólido, tanto para desarrollo como para producción, como por ejemplo el hecho de que
con simples comandos como “npm start” se inicie un servidor de desarrollo donde se recarga la
página del navegador cada vez que hay un cambio en el código o como “npm run buid”, que se
encarga de compilar todo el proyecto a WebAssembly y generar todos los archivos optimizados
para producción.
Este framework también permite hacer pruebas unitarias sobre los componentes, de modo que
si estamos usando la herramienta create-yew-app, podemos hacer uso del comando “npm test”
para ejecutar las diferentes pruebas que hayamos definido para nuestra aplicación. El template
ya posee por defecto algunas pruebas para mostrar la forma correcta de hacerlo.
2https://yew.rs/docs/getting-started/build-a-sample-app3https://github.com/spielrs/yew-parcel-template4https://github.com/jetli/create-yew-app
10
11
Capítulo4
Aplicación: Sistema
Para cumplir con los objetivos planteados al principio de este documento es necesario construir
una aplicación web que haga uso de las dos tecnologías de las que hemos venido hablando, es
decir, que esté hecha en Rust completamente y que el front-end de dicho aplicativo haga uso de
WebAssembly.
Después de hacer un análisis de los diferentes frameworks que existen actualmente para el
desarrollo de aplicaciones web con Rust y WebAssembly llegamos a las siguientes conclusiones:
Por un lado, para el back-end de la aplicación lo más conveniente sería usar Rocket.rs, ya que
está mucho más soportado que Nickel.rs y se encuentra mucho más avanzado en cuanto a carac-
terísticas y funcionalidades. Por otro lado, Yew.rs también se destaca por ser hasta el momento
el único framework para front-end lo suficiente maduro como para ser usado en un proyecto real.
La aplicación a construir se tratará de un sistema en el que se pueda hacer una gestión de
todo el proceso para publicar y escoger temas de tesis en una universidad, teniendo en cuenta
dos roles distintos, profesor y estudiante.
La Figura 4.1 nos muestra lo que sería la arquitectura de la aplicación. Para el front-end se
usará entonces Yew.rs, que serían precisamente los archivos optimizados para producción junto
con los archivos .wasm que se ejecutarán en el navegador del cliente. Para el back-end se hará uso
de Rocket.rs, quien se encargará de todo el manejo de los diferentes puntos de datos necesarios
para la aplicación. A su vez, el back-end contará con una base de datos de tipo relacional que
para efectos prácticos sería PostgreSQL por su popularidad y por ser de código abierto.
Aplicación: Sistema
Figura 4.1: Arquitectura del sistema a construir
12
13
Capítulo5
Aplicación: Crear una aplicación con Rust
Antes de crear cualquier programa con Rust, debemos hacer una instalación de este lenguaje
y las herramientas necesarias para trabajar con él. Según la página oficial de Rust1 basta solo
con ejecutar el siguiente comando en la terminal:
$ cu r l −−proto ’=https ’ −−t l s v 1 . 2 −sS f https : // sh . rustup . r s | sh
Una vez instalado tenemos dos formas de crear un programa con este lenguaje, la primera
forma es la menos habitual, ya que no se usa Cargo, el gestor de paquetes de Rust. Para crear
un programa de esta forma lo primero que debemos hacer es abrir un editor de código y crear
un archivo con extensión “.rs”, por ejemplo “hola_mundo.rs” y escribir el siguiente código en él:
fn main ( ) {
p r i n t l n ! ( " He l lo World ! " ) ;
}
Cabe resaltar que en un programa de Rust lo primero que se ejecuta es la función “main()”. Para
ejecutar el anterior programa lo primero que debemos hacer es abrir una terminal y ubicarnos
en el lugar o carpeta en donde esté guardado el archivo y compilar ese código haciendo uso del
siguiente comando:
$ ru s t c hola_mundo . r s
1https://www.rust-lang.org/
Aplicación: Crear una aplicación con Rust
Lo anterior hará que se cree un archivo binario con el mismo nombre pero sin extensión, es
decir, “hola_mundo”, con el que ya podríamos ejecutar el programa. Su ejecución y su resultado
serían los siguientes:
$ . / hola_mundo
>> Hel lo World !
La siguiente forma de crear un programa o aplicación con Rust es en la que hacemos uso de
Cargo, el gestor de paquetes de Rust. En esta forma nos ahorramos bastante los pasos anteriores,
ya que no necesitaremos estar compilando uno por uno los diferentes archivos .rs de una aplica-
ción más elaborada. Adicionalmente, cuando creamos una aplicación de Rust con Cargo, este se
encarga de crear una estructura o arquitectura apropiada para un proyecto real. Para crear un
proyecto con Cargo tenemos que escribir en la terminal lo siguiente:
$ cargo new name_of_my_project
>> Created binary ( app l i c a t i o n ) ‘ name_of_my_project ‘ package
La Figura 5.1 nos muestra la estructura resultante de un proyecto creado con Cargo, en el
vemos que se crea por defecto un archivo “.gitignore”, esto ocurre porque no es necesario cargar
a un repositorio lo que esté en la carpeta “target”, ya que allí quedan los archivos compilados
de Rust. Dentro de la carpeta “src” se encuentra el archivo “main.rs”, que contiene la función
principal que ejecutará el programa.
Figura 5.1: Estructura de un proyecto creado con Cargo
Para ejecutar este programa primero debemos situarnos dentro del proyecto en la terminal al
mismo nivel que las carpetas “src” y “target”, y luego ejecutar lo siguiente:
$ cargo bu i ld
14
El anterior comando compilará todos los archivos con extensión .rs que se encuentren dentro
de la carpeta “src” y agregará los archivos compilados a una carpeta llamada “debug” dentro de
la carpeta “target”. Por último, debemos ejecutar el siguiente comando:
$ cargo run
El anterior comando se encarga de ejecutar los archivos compilados que se generaron con el
comando anterior sin que nosotros tengamos que preocuparnos por su ubicación o su nombre.
En este punto es importante mencionar que cuando queremos ejecutar un programa de Rust
generado con Cargo podemos saltarnos el comando “cargo build” y pasar diréctamente al uso de
“cargo run”, lo anterior debido a que con este segundo comando también se realiza el proceso
de compilación si los archivos compilados de la carpeta “target” no se encuentran en su última
versión.
15
17
Capítulo6Aplicación: Implementación del sistema
La implementación del sistema se puede dividir en dos fases, el back-end y el front-end. Como
dijimos anteriormente, el back-end se realizará con Rocket.rs, mientras que el front-end con
Yew.rs. A pesar de que cualquier aplicación hecha con Rust se crea de la misma forma, existe
una serie de pasos adicionales que debemos realizar para usar algunos de los frameworks hechos
para este lenguaje. El código de la aplicación desarrollada se encuentra en su repositorio oficial1.
6.1. Back-end
Según la documentación de Benitez [3], para crear una aplicación usando Rocket.rs lo primero
que debemos hacer es instalar rustup, un instalador para diferentes herramientas de Rust que
nos permitiran obtener versiones de este lenguaje de programación diréctamente de los canales
oficiales de lanzamiento. Lo anterior es útil debido a que podemos escoger entre tres diferentes
compiladores: estable, beta y nightly, obteniendo las carácterísticas de cada uno completamente
actualizadas. La instalación de rustup la hacemos empleando este comando en la terminal:
$ cu r l −−proto ’=https ’ −−t l s v 1 . 2 −sS f https : // sh . rustup . r s | sh
Ahora que ya está rustup instalado, debemos configurar la cadena de herramientas de la versión
nightly como las predeterminadas para trabajar con Rust. Hacemos uso del siguiente comando:
$ rustup de f au l t n i gh t l y
1https://github.com/FLAGlab/real-web-programming
Aplicación: Implementación del sistema
Lo anterior es necesario debido a que Rocket.rs trabaja con la versión nightly de Rust. Si en
algún momento el proyecto dejase de funcionar bastaría con actualizar a la versión más reciente
de estas herramientas con el siguiente comando:
$ rustup update && cargo update
Ahora que ya tenemos el ambiente configurado procedemos a la creación del proyecto de la
misma forma que vimos en el capítulo anterior, pero agregando el atributo –bin con el que
indicamos que estamos creando un programa binario. Posteriormente, accedemos a la carpeta
donde fue creado. Todo esto desde la terminal:
$ cargo new he l l o−rocke t −−bin
$ cd he l l o−rocke t
Ahora debemos añadir Rocket.rs a nuestro proyecto, para ello tenemos que dirigirnos al archivo
“Cargo.toml” y agregar la siguiente linea en la sección de dependencias:
[ dependenc ies ]
rocke t = " 0 . 4 . 5 "
Ahora que configuramos las dependencias, procedemos al código principal del programa. Nos
dirigimos al archivo “src/main.rs” y lo editamos de la siguiente forma:
1 #![ f e a t u r e ( proc_macro_hygiene , decl_macro ) ]
2
3 #[macro_use ] extern c ra t e rocke t ;
4
5 #[ get ( " / " ) ]
6 fn index ( ) −> &’ s t a t i c s t r {
7 " Hel lo , world ! "
8 }
9
10 fn main ( ) {
11 rocke t : : i g n i t e ( ) . mount ( " / " , r oute s ! [ index ] ) . launch ( ) ;
12 }
18
6.1 Back-end
El código anterior se considera un “hola mundo” en Rocket.rs. Debido a que este framework
usa las funcionalidades de la versión nightly de Rust, la primera línea activa las funcionalidades
inestables para que funcione correctamente. La linea tres importa el código de Rocket. En la línea
5 se define la ruta inicial del servicio REST el cual, en este caso, retorna una simple cadena de
caracteres. Por último, en la línea diez se encuentra la función principal, en donde se montan
las rutas creadas anteriormente para luego lanzar la aplicación. Para ejecutar la aplicación basta
con usar el comando “cargo run” dentro del folder del proyeto.
Si queremos enviar una respuesta de tipo JSON podemos importar la utilidad content de
Rocket y usarla de la siguiente forma:
use rocke t : : r e sponse : : content ;
#[ get ( " / api / u s e r s " ) ]
fn get_thopics ( ) −> content : : Json<&’ s t a t i c s t r> {
content : : Json (
" [
{
’name ’ : \"Name number one \ " ,
’ id ’ : \"1234567890\"
} ,
{
’name ’ : \"Name number two \" ,
’ id ’ : \"1234567891\"
}
] " ,
)
}
También podemos acceder a los parámetros de la petición REST y usarlos en el cuerpo de la
respuesta de la siguiente forma:
#[ d e l e t e ( " / u s e r s/<id >") ]
fn de l e te_user ( id : S t r ing ) −> Str ing {
19
Aplicación: Implementación del sistema
format ! ( "DELETE user id = {}" , id )
}
En nuestra aplicación las principales rutas para la funcionalidad esperada, sin tener en cuenta
las rutas de autenticación, corresponden al CRUD de usuarios y temas de tesis disponibles. De
modo que en el back-end se debe manejar la lógica de negocio adecuada para que los temas
de tesis nuevos solo puedan ser publicados por profesores y los que los escojan pertenezcan al
grupo de estudiantes. Todo el manejo de las bases de datos debe implementarse siguiendo la
documentación oficial de los diferentes drivers construidos para Rust2.
6.2. Front-end
Según la página principal de Yew.rs, la forma sugerida de crear un proyecto usando esta
tecnología es ejecutando el siguiente comando en la terminal:
$ cargo new −− l i b yew−app && cd yew−app
Cabe resaltar que en el comando anterior, se hace uso de “–lib”, en lugar de “–bin” como se
hacía en Rocket.rs, lo anterior ocurre porque en este caso se busca crear una librería y no archivos
binarios. Ahora debemos agregar las dependencias necesarias en el archivo “Cargo.toml” de la
siguiente manera:
[ l i b ]
c rate−type = [ " cdy l i b " , " r l i b " ]
[ dependenc ies ]
yew = "0 . 1 7 "
wasm−bindgen = " 0 . 2 "
En el código anterior estamos agregando “Yew” y “wasm-bindgen” a nuestro proyecto, este
último es el que nos permitirá compilar todo el código de Rust a archivos con extensión “.wasm”
más adelante.
2https://rocket.rs/v0.4/guide/state/#databases
20
6.2 Front-end
Ahora debemos dirigirnos al archivo “src/lib.rs” donde se encuentra el código principal de
nuestra aplicación. En el tutorial oficial 3 podemos encontrar el código completo de la aplicación.
En él vemos que inicialmente se importan las librerías de Yew y wasm-bindgen. Posteriormente
se crea el modelo de la aplicación que, en tecnologías como React.js es lo que se conoce como
el estado de la aplicación. Y por último se definen los métodos principales del ciclo de vida de
un componente en “Yew”, que serían: create, update y view. El primero se ejecuta cuando recien
se crea el componente y antes de ser montado en la vista de la aplicación, el segundo se ejecuta
cuando ocurre algún cambio en el estado o modelo, y el tercero se usa para definir la parte
visual de la aplicación usando HTML, CSS, y Rust, de forma similar a como lo hace el método
“render()” en React.js con la sintaxis de JSX.
Para llamar las instrucciones anteriores es necesario agregar el método principal, así que colo-
camos el siguiente código al final del archivo:
#[wasm_bindgen ( s t a r t ) ]
pub fn run_app ( ) {
App:: <Model >: :new ( ) . mount_to_body ( ) ;
}
Como se dijo anteriormente, todo lo anterior es lo que recomienda la documentación oficial,
sin embargo, se hace bastante complejo y engorroso trabajar de esta forma para aplicaciones más
grandes y altamente desacopladas. Es en este punto cuando surge la necesidad de desarrollar
a partir de algún tipo de plantilla donde tanto la estructura del proyecto como la velocidad
de desarrollo sea mucho más acertada. Según la documentación oficial, se sugiere que se use
“yew-parcel-template” 4 como plantilla para crear una aplicación en Yew, sin embargo, existe
otra plantilla mucho más elaborada y cómoda de trabajar cuando se llega de tecnologías como
React.js, su nombre es “create-yew-app”5.
Para usar “create-yew-app” es necesario tener instalado npm, el sistema de gestión de paquetes
por defecto para Node.js, esto debido a que los archivos binarios de esta biblioteca se encuentran
en este gestor y será necesario utilizar npx, su ejecutador de paquetes binario. Usando npm será
3https://yew.rs/docs/getting-started/build-a-sample-app4https://github.com/spielrs/yew-parcel-template5https://github.com/jetli/create-yew-app
21
Aplicación: Implementación del sistema
mucho más cómodo el desarrollo de la aplicación, los despliegues de desarrollo y la compilación
de los archivos para producción haciendo uso de WebAssembly.
Para crear una aplicación y ejecutarla con este template, tenemos que ejecutar los siguientes
comandos:
$ npx create−yew−app my−app
$ cd my−app
$ npm s t a r t
El primer comando ejecutará una serie de procesos automáticos que crearán todos los archi-
vos necesarios para la aplicación mientras crea una estructura adecuadada para el proyecto, la
Figura 6.1 muestra dicha estructura.
Figura 6.1: Arquitectura de una aplicacion con create-yew-app
Como se mencionó anteriormente, para ejecutar la aplicación basta con ejecutar el comando
22
6.2 Front-end
“npm start”, o “yarn start” en caso de que se prefiera usar este instalador de paquetes. Cuando se
lanza la aplicación por primera vez la interfaz inicial es muy similar a la que se muestra cuando
se crea una aplicación de React.js usando su correspondiente template “create-react-app”, tal
como lo muestran la Figura 6.2 y la Figura 6.3.
Figura 6.2: Interfaz por defecto con create-react-app
Figura 6.3: Interfaz por defecto con create-yew-app
Claramente los creadores de esta herramienta se han inspirado principalmente en React.js
y en las formas actuales de trabajar con él, sin embargo, cabe recordar que en este framework
estaríamos usando el lenguaje Rust para compilar después a WebAssembly en lugar de Javascript.
Debemos recordar también que cuando ejecutamos la aplicación mediante el comando “npm
start” nos encontramos en un entorno de desarrollo donde los archivos aún no están optimizados
para producción.
Para entender la estructura del proyecto y de la implementación de nuestro sistema podemos
dirigirnos inicialmente al directorio raiz, en él podemos encontrar los archivos de la licencia,
el README, los archivos “package.json” que se encargan de ejecutar y compilar la aplicación
23
Aplicación: Implementación del sistema
definiendo los comando y librerías necesarias, los archivos “Cargo.toml” y “Cargo.lock” que
definen las librerías de Rust que se usarán y el “.gitignore”. Después tenemos los directorios:
“test” para las pruebas unitarias; “target” con los archivos compilados y ejecutables generados
por Cargo; “static” con el archivo “index.html” inicial de la aplicación, “favicon.ico”, “styles.scss”
para los estilos de la aplicación, entre otros; “node-modules” y “pkg” con las librerías necesarias
para ejecutar y compilar la aplicación; “dist” con los archivos optimizados para producción
cuando ya se compila el proyecto; y por último “src” con el código fuente de escrito en Rust.
En el directorio “src” encontraremos las carpetas “components” y “routes” junto a los archivos
“app.rs” y “lib.rs”. Es precisamente en este último donde colocamos el punto de entrada de
nuestra aplicación que, debido a la configuración automatica de la herramienta, quedaría de la
siguiente forma:
#[wasm_bindgen ]
pub fn run ( ) −> Result <() , JsValue> {
wasm_logger : : i n i t ( wasm_logger : : Conf ig : : d e f au l t ( ) ) ;
yew : : start_app :: <App>() ;
Ok( ( ) )
}
Sin embargo, no es necesario cambiar nada en este archivo, ya que este se encarga solamente
del arranque de la aplicación independientemente de sus funcionalidades. En el siguiente archivo,
“app.rs”, es donde se define el componente principal de la aplicación. Para ilustrar lo que es
la creación de un componente en Yew tomaremos como ejemplo el componente “Home” que se
encuentra en la carpeta “src/routes”, el cual se ve de la siguiente manera:
use yew : : pre lude : : ∗ ;
/// Home page
pub s t r u c t Home ;
impl Component f o r Home {
type Message = ( ) ;
type Prope r t i e s = ( ) ;
fn c r e a t e (_: S e l f : : Proper t i e s , _: ComponentLink<Se l f >) −> Se l f {
24
6.2 Front-end
Home {}
}
fn change(&mut s e l f , _: S e l f : : P rope r t i e s ) −> ShouldRender {
f a l s e
}
fn update(&mut s e l f , _: S e l f : : Message ) −> ShouldRender {
t rue
}
fn view(& s e l f ) −> Html {
html ! {
<div c l a s s ="app">
<header c l a s s ="app−header">
<h1>{ "Welcome to S i s I n f o " }</h1>
</header>
</div>
}
}
}
Como podemos ver, normalmente la creación de un componente comienza importando las
librerías que vamos a usar en él, empezando por Yew::prelude. Después es necesario definir el
componente como una estructura para poder agregar los métodos del ciclo de vida del componente
en sí. Procedemos a implementar o definir los métodos que contendrá dicha estructura que, como
se había mencionado antes, los más importantes son: “create”, “update” y “view”. En este caso se
define para la vista un simple “header” con un “h1” dentro. En el método “create” se retorna la
misma estructura para que sea montada y en el método “update” se indica que se debe actualizar
la interfaz si algún dato del estado de la aplicación cambia. Aclarado esto, ya podemos continuar
explicando la función del componente principal “app.rs”. Lo que hace especial a este componente
es que define inicialmente el contenido que se va a mostrar siempre en la aplicación a través de su
método “view” y del uso de “yew-router”, una librería escrita para este framework y muy similar
25
Aplicación: Implementación del sistema
a “react-router” que se encarga de manejar las diferentes rutas de acceso o url’s para administrar
el contenido que se mostrará en cada una.
Para hacer esto lo primero que hace este componente es importar tanto la librería “yew-router”
como los componentes y rutas definidas en la misma aplicación de la siguiente forma:
use yew : : pre lude : : ∗ ;
use yew_router : : switch : : Permiss ive ;
use yew_router : : { pre lude : : ∗ , route : : Route } ;
use c r a t e : : components : : nav : : Nav ;
use c r a t e : : r out e s : : { about : : About , home : : Home, t op i c s : : Topics , AppRoute } ;
Por último, utiliza el método “view” para definir qué componente se mostrará segun la ruta
accedida por el usuario:f n view(& s e l f ) −> Html {
html ! {
<>
<Nav />
<Router<AppRoute , ()>
r e n d e r = Router : : r e n d e r ( | s w i t c h : AppRoute | {
match s w i t c h {
AppRoute : : Home => html ! { <Home /> } ,
AppRoute : : About => html ! { <About /> } ,
AppRoute : : Topics => html ! { <Topics /> } ,
AppRoute : : PageNotFound ( P e r m i s s i v e ( None ) ) => html ! { " Page not found " } ,
AppRoute : : PageNotFound ( P e r m i s s i v e ( Some ( missed_route ) ) ) => html ! { format ! ( " Page ’ { } ’ not
found " , missed_route )}
}
} )
r e d i r e c t = Router : : r e d i r e c t ( | r o u t e : Route <()>| {
AppRoute : : PageNotFound ( P e r m i s s i v e ( Some ( r o u t e . r o u t e ) ) )
})
/>
</>
}
}
Ahora, en la carpeta “routes” encontraremos los componentes que se mostraran en cada ruta
de la aplicación, cada uno en un archivo de Rust distinto. El primero de ellos se llama “home.rs”
y su código ya fue mostrado algunas líneas más arriba. El siguiente es “about.rs” y es muy similar
al anterior, mostrando información acerca de la aplicación. Cabe resaltar que tanto el “home”
como el “about” son componentes y rutas que vienen configuradas por defecto cuando se crea la
aplicación. El siguiente componente se llama “topics.rs” y su función es listar los diferentes temas
26
6.2 Front-end
de tesis disponibles cuando un estudiante hace la consulta. Para este componente es necesario
importar algunas librerías de Yew como “FetchService” para hacer las solicitudes de datos al
back-end de la aplicación:
use yew : : s e r v i c e s : : {
f e t ch : : { FetchServ ice , FetchTask , Request , Response } ,
Conso leServ ice ,
}
La Figura 6.4 muestra cómo se ve el componente junto con la barra de navegación.
Figura 6.4: Componente “topics” de la aplicación.
El siguiente archivo es “mod.rs”, este no es un componente como tal pero su código cumple la
función de exportar los componentes anteriormente definidos para que puedan ser manipulados
desde los demás archivos de la aplicación. También se encarga de definir una enumeración en
donde se asocian las diferentes rutas url con su correspondiente componente. Su código es el
siguiente:
use yew_router : : pre lude : : ∗ ;
27
Aplicación: Implementación del sistema
use yew_router : : switch : : Permiss ive ;
pub mod about ;
pub mod home ;
pub mod t op i c s ;
/// App route s
#[ de r i v e ( Switch , Debug , Clone ) ]
pub enum AppRoute {
#[ to = "/ t op i c s " ]
Topics ,
#[ to = "/ about " ]
About ,
#[ to = "/ page−not−found " ]
PageNotFound ( Permiss ive<Str ing >) ,
#[ to = " / " ]
Home,
}
Por último, en la carpeta “components” encontraremos dos archivos, “mod.rs” cuya función
en este caso consiste solamente en exportar el componente del otro archivo, y “nav.rs” un com-
ponente configurado como barra de navegación que, junto a “yew-router”, redirige a una ruta
específica según el enlace que el usuario pulse. Lo más destacable aquí es su método “view” donde
ocurre la configuración:f n view(& s e l f ) −> Html {
html ! {
<nav>
<ul>
<l i ><RouterAnchor<AppRoute> r o u t e=AppRoute : : Home c l a s s e s ="app−l i n k " >{ "Home" }</RouterAnchor
<AppRoute>></l i >
<l i ><RouterAnchor<AppRoute> r o u t e=AppRoute : : About c l a s s e s ="app−l i n k ">{ " About " }</RouterAnchor
<AppRoute>></l i >
<l i ><RouterAnchor<AppRoute> r o u t e=AppRoute : : Topics c l a s s e s ="app−l i n k ">{ " Topics " }</RouterAnchor
<AppRoute>></l i >
</ul>
</nav>
28
6.2 Front-end
}
}
Por último, recordemos que se debe compilar la aplicación para que quede lista para produc-
ción, esto lo hacemos con el comando “npm run build”, tal como lo haríamos en una aplicación
de React. Esto generará todos los archivos necesarios para desplegar la aplicación final, incluyen-
do los de WebAssembly. Todo esto quedará en la carpeta “dist” como se dijo anteriormente. La
Figura 6.5 muestra la respuesta obtenida por la terminal, que nos brinda datos como el tamaño
final de cada archivo y el tiempo que duro su compilación.
Figura 6.5: Resultado de la ejecución del comando “npm run build”
En cuanto al despliegue podríamos colocar en un servidor http los archivos resultantes, sin
embargo, ya que esta aplicación también cuenta con un back-end, lo más recomendable sería
colocar estos archivos en el mismo servidor del back-end y configurar el código de Rocket.rs para
que sirva estos archivos en la carpeta pública del sistema.
29
31
Capítulo7
Conclusión y trabajo futuro
Esta tesis presenta un estudio para el desarrollo de aplicaciones web basadas en código Rust y
WebAssembly. En particular, se propone un modelo de desarrollo de manera práctica haciendo uso
de los frameworks más reconocidos actualmente para estas tecnologías, específicamente Rocket.rs
y Yew.rs. Primeramente se realizó un estudio del estado actual de estas tecnologías para luego
desarrollar de manera incremental un sistema separado por el back-end y el front-end.
Finalmente, después de todo el trabajo realizado, la información investigada y el proceso por
el cual se ha llevado a cabo el desarrollo de la aplicación se puede afirmar que las tecnologías
creadas con Rust y WebAssembly se encuentran en un estando bastante maduro, principalmente
por la comunidad de desarrolladores que mantienen frameworks como Yew o Rocket y también
gracias a todos los esfuerzos de la organización Mozilla por sacar adelante WebAssembly.
En cuanto a la seguridad de estas tecnologías podemos decir que llevan una gran ventaja
gracias a Rust, debido a que este lenguaje incorpora por si mismo características de seguridad
como, por ejemplo, un manejo estricto de la memoria.
Algo negativo que se debe mencionar es que la curva de aprendizaje de estas tecnologías es bas-
tante lenta, al mismo tiempo que no siempre resulta intuitivo el manejo de algunas características
del lenguaje. Todo esto empeora un poco debido a que la documentación es muy escasa o incom-
pleta, como por ejemplo la web oficial de Yew, en donde al día de hoy existen varias secciones
sin terminar o en blanco. También ocurre a menudo el hecho de encontrarse con documentación
que queda obsoleta gracias a las nuevas versiones del lenguaje o del framework.
Conclusión y trabajo futuro
Si bien estos frameworks aún no se encuentran totalmente a la altura de tecnologías usadas
en la actualidad como por ejemplo React, Angular o Node, lo cierto es que constantemente se
van actualizando y mejorando con características que cada vez los hacen mucho más rápidos y
seguros. En cuanto aWebAssembly, cada dia los navegadores incluyen soporte para esta tecnología
aprovechando al máximo el trabajo de organizaciones como Mozilla o la W3C.
Para el trabajo futuro de la aplicación, hace falta implementar el manejo de sesiones y auten-
ticación de usuarios haciendo uso de una base de datos relacional en el back-end y enviando las
peticiones y los datos desde el front-end. Sin embargo, el trabajo futuro puede extenderse tanto
como los requerimentos funcionales del sistema lo requieran.
32
33
Bibliografía
The references are sorted alphabetically by first author.
[1] Introduction - yew docs. Accedido en 28-06-2020 a https://yew.rs/, 2020.
[2] Ivo Balbaert. Rust Essentials: A quick guide to writing fast, safe, and concurrent systems
and applications. Packt Publishing Ltd, 2017.
[3] Sergio Benitez. Rocket - simple, fast, type-safe web framework for rust. Accedido en 28-06-
2020 a https://rocket.rs/, 2020.
[4] Lyn Dupré. BUGS in Writing: A Guide to Debugging Your Prose. pub-addison, revised
edition, 1998. ISBN 0-201-37921-X.
[5] William Strunk and E.B. White. The Elements of Style. Longman, fourth edition, 2000.
ISBN 0-205-30902-X.