Yew, crea webapps al estilo Angular/React en Rust

Hoy os traigo una librería muy potente y muy útil, ahora que Rust compila a WebAssembly de forma nativa. Se trata de Yew, una librería para diseñar frontends, single-page-applications y en general, una librería que es una alternativa a Angular, React, Vue y Elm.

En particular, Yew se basa en The Elm Architecture, por lo que los usuarios de Elm serán los que encuentren más familiar a Yew.

Yew significa tejo. He aquí uno de los tejos más famosos de Valladolid, en la plaza del Viejo Coso

Instalar cargo-web y el soporte a WebAssembly

Antes de empezar a programar necesitaremos instalar un plugin para Cargo, llamado cargo-web, que nos ayudará en el desarrollo web con Rust. Por otro lado, hace falta instalar el soporte de Rust a WebAssembly. Existen tres opciones actualmente: asmjs-unknown-emscripten, wasm32-unknown-emscripten y wasm32-unknown-unknown. Para los primeras opciones hace falta tener instalado Emscripten. Para la última, no hace falta nada, por lo que es mi opción recomendada. Por otro lado, wasm32 significa WebAssembly y asmjs es asm.js, que es simplemente JavaScript y será compatible con más navegadores.

The Elm Architecture

Los principios de The Elm Architecture se basan en: modelo, mensajes, actualización y vista.

Para este tutorial vamos a hacer la típica aplicación de una lista donde guardamos notas. Nuestro modelo se va a componer de una lista de tareas, para simplificar, pongamos que una tarea es simplemente un String y un ID. Entonces también nos hará falta almacenar un contador para ir poniendo IDs. También, al tener un campo de texto, nos hará falta una variable para ir almacenando temporalmente lo que escribe el usuario.

Lo siguiente es diseñar los mensajes. Los mensajes interactúan con el modelo y desencadenan una actualización de la vista. En esta aplicación solo nos hacen falta dos mensajes: añadir mensaje y borrar mensaje. Pero como tenemos un campo de texto, tenemos que introducir un mensaje Change y siempre viene bien un mensaje que no haga nada.

Una vez hecho esto pasamos a crear la función update, en la que hacemos distintas cosas según el mensaje que recibamos.

Así pues, si se lanza un mensaje Msg::Add lo que hacemos es copiar el valor de la variable temporal input, crear una nueva tarea con su ID y añadirla a la lista de tareas. Ya está. Yew mágicamente actualizará la página para reflejar que la lista de tareas ha sido modificada. Lo mismo pasa con Remove.

Ahora vamos a las vistas. Una vista es una función que devuelve Html<Msg> y se pueden componer varias funciones así. En nuestro caso, tenemos una vista principal donde se ve un campo de texto y un sitio donde se ejecuta un bucle for con las tareas del modelo. Y a cada tarea se le aplica la vista view_task.

La macro html! nos permite escribir HTML directamente en Rust, con algunas diferencias (¡prestad atención a las comas!). También nos permite introducir código Rust (entre llaves) y closures (observad onclick, oninput y onkeypress).

Finalmente en el método main, inicializamos el modelo y llamamos a program, que empieza a ejecutar Yew.

El código final queda así.

Ejecutando la aplicación web

Usando cargo web, es muy sencillo generar la aplicación web. Simplemente ejecuta:

El resultado, se montará en un mini servidor web. Si accedes a la URL que indica Cargo con tu navegador web, verás algo similar a esto:

Añade items y bórralos. Observa como la aplicación funciona perfectamente.

Distribuyendo la aplicación

Realmente cargo web ha hecho muchas cosas por nosotros. Si nosotros queremos usar Yew en la vida real, no usaremos cargo web. Para ello, compilamos la aplicación web:

Y accedemos a la carpeta target/wasm32-unknown-unknown/release. Allí encontraremos dos archivos que vamos a necesitar. Uno acabado en .js y otro acabado en .wasm. Ambos ficheros deberemos copiarlos donde queramos usarlos. Por último, será necesario un fichero HTML. En el fichero HTML solo hace falta cargar el fichero JS. Yew hará el resto.

Si quieres saber más, puedes descargarte el código de ejemplo que se encuentra en GitHub.

¿Qué pasa con Elixir?

Desde hace un tiempo oigo a bastante gente hablar de Elixir. Elixir es un lenguaje de programación de propósito general que vio la luz en 2011. Con bastantes aspectos de un lenguaje de programación funcional y dinámico, está especificamente diseñado para manejar la concurrencia. Se ejecuta sobre la máquina virtual BEAM, originalmente diseñada para Erlang y es capaz de ejecutar código métodos escritos en Erlang sin ninguna complicación extra. Además dispone de un sistema de compilación llamado mix, un gestor de paquetes llamado hex y la forma de escribir documentación es similar a Python (existe help(método), ¡aleluya!). Elixir además dispone de hot swapping, es decir, permite cambiar el código en ejecución sin necesidad de parar el programa. También le caracteriza tener un buen soporte a operaciones asíncronas.

¿Es Elixir el nuevo Ruby?

Mucha gente ha querido llamar a Elixir el Erlang escrito bonito. Muchos lo comparan con Ruby pues sí que comparten alguna característica común en su sintaxis y una filosofía en general de simplicidad. Además Elixir es mucho más rápido y está mucho mejor diseñado para concurrencia y aplicaciones tolerantes a fallos (como su hermano mayor Erlang).

Sin embargo, ¿es justo comparar Ruby con Elixir?

Entra Phoenix en acción

Mucha de la popularidad de Ruby se la debe a su framework Rails. Usado por una gran cantidad de sitios en la web, supuso para muchos su primer contacto con Ruby y la razón de que se quedasen aprendiendo el lenguaje.

Curiosamente, Elixir también tiene un framework web que atrae a desarrolladores. Se trata de Phoenix.

Phoenix se presenta como un framework para la nueva web. Aplicaciones realtime, tolerantes a fallos y de alto rendimiento sin perder las facilidades y comodidades de frameworks anteriores. La gente que lo ha usado cuenta maravillas. ¿Has usado Phoenix? Cuéntanos tu experiencia en los comentarios.

Probando Elixir con su REPL

Elixir viene con un REPL, es decir, una terminal donde línea a línea podemos ir introduciendo código Elixir. Se ejecuta con el comando iex.

Podemos hacer un hola mundo con IO.puts.

Podemos probar a definir un módulo de suma:

Lo que se ve en amarillo es el bytecode compilado para BEAM del módulo Adder

Aunque llegado el momento quizá nos interese crear alguna función anónima.

Es fácil encontrar documentación en español sobre Elixir si deseas investigar más sobre el tema.

Sin duda Elixir parece interesante. ¿Será un mero hype o dentro de unos años Elixir será uno de los lenguajes más populares? Ciertas webs han empezado a recomendar echar un vistazo a Elixir y Phoenix si queremos crear una nueva aplicación web.

Tutorial de Rocket, echa a volar tus webapps con Rust

Previamente ya hemos hablado de Iron como un web framework para Rust. Sin embargo desde que escribí ese post ha surgido otra librería que ha ganado mucha popularidad en poco tiempo. Se trata de Rocket. Un web framework que propone usar el rendimiento que ofrece Rust sin sacrificar la facilidad de uso de otros lenguajes.

Rocket lleva las pilas cargadas

A diferencia de Iron, Rocket incluye bastantes prestaciones por defecto con soporte para:

  • Plantillas
  • Cookies
  • Formularios
  • JSON
  • Soporte para rutas dinámicas

Un “Hola Mundo”

Rocket necesita una versión nightly del compilador de Rust. Una vez lo tengas creamos una aplicación con Cargo.

Ahora modificamos el fichero Cargo.toml generado en la carpeta rocket_app para añadir las siguientes dependencias:

Editamos el archivo src/main.rs para que se parezca algo a esto:

Con esto iniciamos Rocket y dejamos a la función index que gestione las peticiones GET encaminadas a /. El servidor devolverá El cohete ha despegado.

Ahora si ejecutamos cargo run veremos algo similar a esto:

Vemos que el servidor ya está escuchando en el puerto 8000 y está usando todos los cores (en mi caso 4) del ordenador.

Configurar Rocket

Rocket dispone de varias configuraciones predeterminadas que afectan a su funcionamiento. Para alternar entre las configuraciones debemos usar variables de entorno y para modificar las configuraciones en sí debemos usar un fichero llamado Rocket.toml.

Las configuraciones por defecto son: dev (development), stage (staging) y prod (production). Si no indicamos nada, Rocket se inicia con la configuración dev. Para arrancar con la configuración de producción modificamos el valor de ROCKET_ENV.

Sería el comando para arrancar Rocket en modo producción. En el archivo Rocket.toml se puede modificar cada configuración, estableciendo el puerto, el número de workers y parámetros extra pero no vamos a entrar en ello.

Rutas dinámicas

Rocket soporta rutas dinámicas. Por ejemplo, si hacemos GET  /pelicula/Intocable podemos definir que la parte del nombre de la película sea un parámetro. Esto hará que la función encargada de /pelicula/Intocable y de /pelicula/Ratatouille sea la misma.

Los argumentos de la función son los parámetros de la petición GET. ¿Qué pasa si no concuerda el tipo de la función con lo que se pasa por HTTP? Nada. Sencillamente Rocket ignora esa petición, busca otra ruta (puede haber sobrecarga de rutas) y si encuentra otra que si satisfaga los parámetros será esa la escogida. Para especificar el orden en el que se hace la sobrecarga de rutas puede usarse rank. En caso de no encontrarse nada, se devuelve un error 404.

POST, subir JSON y formularios

Rocket se integra con Serde para lograr una serialización/deserialización con JSON inocua. Si añadimos las dependencias serde, serde_json y serde_derive al fichero Cargo.toml podemos tener un método que acepete una petición POST solo para mensajes del tipo application/json con deserialización incorporada.

Si el JSON no se ajusta a la estructura User simplemente se descarta devolviendo un error 400.

Lo mismo que es posible hacer con JSON puede hacerse con formularios usando el trait FromForm.

Errores

En Rocket, como es lógico, es posible crear páginas personalizadas para cada error.

La lista de métodos que manejan errores hay que pasarla en el método catch de rocket::ignite

Respuestas

Rocket nos permite devolver cualquier cosa que implemente el trait Responder. Algunos tipos ya lo llevan como String, File, JSON, Option y Result. Pero nada nos impide que nuestros propios tipos implementen Responder. Con Responder tenemos el contenido y el código de error (que en la mayoría de casos será 200). En el caso de Result es muy interesante, pues si Err contiene algo que implementa Responder, se devolverá la salida que implemente también, pudiendo así hacer mejores respuestas de error, mientras que si no lo hacen se llamará al método que implemente el error 500 de forma genérica. Con Option, si el valor es Some se devolverá el contenido, si es None se generará un error 404.

Este ejemplo para /pelicula/Intocable devolverá: La película Intocable se hizo en Francia mientras que para /pelicula/Ratatouille dirá No existe esa película en nuestra base de datos.

También es posible devolver plantillas. Rocket se integra por defecto con Handlebars y Tera, aunque no es muy costoso añadir cualquier otra como Maud.

Conclusión

Rocket es un prometedor web framework para Rust, bastante idiomático, que se integra muy bien con el lenguaje. Espero con ansia las nuevas veriones. Es posible que la API cambie bastante hasta que salga la versión 1.0, no obstante así es como ahora mismo funciona.

Tutorial de Maud, motor de plantillas HTML para Rust

Seguimos aprendiendo en el blog sobre interesantes proyectos hechos para Rust. Ya hemos visto Iron, Piston y Neon. Hoy veremos Maud, un potente motor de plantillas que se centra en la eficiencia. Maud se compara a otras soluciones como Razor, ERB, Liquid,  Handlebars o Jade pero esta vez escribiremos nuestro HTML en Rust. ¿Locura? No, y de hecho funciona de forma bastante transparente. Vamos a verlo en acción

Comparativa de velocidad de diferentes motores. Maud es el más rápido (menos es mejor)

Instalando Maud

Maud usa plugins del compilador, una característica que a día de hoy no está activado ni en el canal estable ni el canal beta, solamente en el canal nightly. Para obtener una copia de Rust nightly lo ideal es usar Rustup.

Una vez hecho eso, creamos un nuevo proyecto y añadimos las dependencias de Maud al fichero Cargo.toml.

Una simple plantilla

Ahora abrimos el archivo src/main.rs y vamos a empezar a usar Maud.

La potencia de Maud se ve en la mega-macro html!. En esta macro escribiremos la plantilla que será compilada de forma nativa a Rust, lo que nos asegura una velocidad de ejecución excepcional. En este caso la salida será una etiqueta P de párrafo con la variable interpolada.

Simple, ¿no?

PreEscaped y otros elementos básicos

Por defecto en Maud todos el texto se convierte a HTML seguro. Es decir, no se pueden introducir etiquetas nuevas en el texto. Si por alguna razón necesitásemos añadir etiquetas nuevas podemos usar PreEscaped, que no realiza esta transformación de seguridad. Veamos el siguiente código:

El primer H5 se convertirá a código HTML seguro, es decir, no añadirá la etiqueta, en cambio se verá h5 en la web. Por contra con PreEscaped se añadirá la etiqueta h5 tal cual.

Los elementos son muy fáciles de añadir en Maud y por lo general no deberías usar PreEscaped salvo contadas ocasiones. Veamos como añadir más etiquetas.

En este ejemplo vemos como las etiquetas que no llevan texto como BR o INPUT debemos cerrarlas con una barra. Por otro lado es posible aglutinar varios niveles de etiquetas en una sola línea ( SMALL->EM->Texto).

Atributos, clases e IDs

En Maud es posible asignar atributos también, usando literales o variables. Para los atributos de texto la sintaxis es muy parecida a HTML.

Además existen en HTML atributos vacíos. Es decir, atributos que con su sola presencia basta y normalmente no llevan valor asignado.

En este caso el atributo contenteditable se añade si la variable allow_editing es true. Si queremos añadir atributos vacíos en cualquier circunstancia podemos simplemente quitar [allow_editing] y dejar p contenteditable? {}.

Los IDs y las clases se añaden usando la sintaxis esperable, puntos y almohadillas.

Estructuras de control

Maud soporta las estructuras de control básicas de Rust, if/else, if/let, for in y match.

Como vemos, Maud posee suficientes características para ser interesante. Maud además permite extender el motor para representar cualquier tipo de dato. Por defecto Maud mirá si está implementado std::fmt::Display pero si queremos añadir etiquetas extra este método no funcionará. En cambio si se implementa la trait maud::Render tendrás control total sobre como va a mostrar Maud las variables de ese tipo. En la crate maud_extras se encuentran implementaciones por ejemplo de Markdown para Maud.

Maud se integra además con web frameworks de Rust, en especial con Iron y con Rocket. Sin duda, una de mis crates favoritas.

Usando Iron, un web framework para Rust


Quizá te interese echar un ojo al tutorial de Rocket, otro web framework para Rust

Rust cada día atrae a más desarrolladores. Es eficiente y es robusto. Mozilla ha sido la principal impulsora de este lenguaje para ser usado en entornos tan complejos como el propio Firefox.

Hoy vamos a introducirnos en el mundo del desarrollo web con Rust. Cuando la gente oye desarrollo web normalmente se piensa en lenguajes como PHP, Python, Ruby o JavaScript. Estos son lenguajes con los que es rápido desarrollar algo, aunque son mucho menos eficientes y es más fácil cometer errores debido a que son interpretados directamente. Un paso por encima tenemos a Java y C#, que cubren en parte las carencias de los otros lenguajes mencionados. Ha llegado la hora de hablar de Rust. Si bien es cierto que hay web frameworks en C++, nunca han sido muy populares. ¿Será Rust la opción que finalmente nos permita tener aplicaciones web con una eficiencia nativa?

Existen varios web frameworks en Rust, para este tutorial vamos a usar Iron, el más popular según Crates.io. Quizá te interese echar un vistazo también a Rocket, mi preferido.

ironframework

Crear proyecto e instalar Iron

Lo primero que hay que hacer es crear un nuevo proyecto en Rust, lo hacemos gracias a Cargo.

Ahora editamos el fichero Cargo.toml para añadir las dependencias que vamos a usar.

Ahora obtenemos las dependencias especificadas con Cargo.

Hola Mundo con Iron

Vamos a empezar a programar en Rust. Vamos a hacer una simple aplicación que devuelva “Hola Rustáceos” por HTTP.

Editamos el archivo src/main.rs

holarustaceos

Usando router para el enrutamiento

Hemos hecho un pequeño servidor HTTP con Iron. Pero nos falta algo, que sea capaz de manejar rutas. Que miweb.com/hola no sea lo mismo que miweb.com/adios. Iron por defecto no trae enrutador, pero es muy habitual usar Router, que ya hemos instalado antes por conveniencia.

getiron

Archivos estáticos

Para gestionar los ficheros estáticos vamos a usar staticfile y mount, otras dos librerías para Iron.

ironstaticfile

 

Hemos dado nuestros primeros pasos en Iron, un web framework para Rust. Iron es completamente modular y soporta muchas más cosas que aquí no hemos visto. Gran parte de su funcionalidad se implementa a través de middleware, como en otros web frameworks populares.