lunes, 22 de junio de 2020

Creando aplicaciones web usando Rust y Rocket (Parte 1)

Los resultados de la encuesta de Rust de 2019 reflejan que la mayoría de los que trabajan con Rust en tiempo completo son programadores / ingenieros en software que trabajan en "backend web applications" que son simplemente aplicaciones web para servicios de fondo. Estos servicios de fondo se encargan de procesar entradas de datos y a partir de esto regresar un resultado o realizar una actualización en una base de datos. Usualmente el usuario no interactúa con estos servicios directamente.

Rust cuenta ya con algunos "crates" o librerías que ayudan crear estos servicios de fondo. Información de estos se puede encontrar en la página "Are we web yet?". He decidido seguir la guía  de uno de estos frameworks web para servicios web y clientes web para probar las capacidades de Rust en esta área.

Viendo la sección de frameworks https://www.arewewebyet.org/topics/frameworks/ resaltan algunos por su número de descargas:
  • 1,200,000 descargas para actix-web. Actualmente parece ser el framework más completo, complejo y paralelo. El problema es que puede ser muy complicado para un principiante de Rust. Puede usarse en la actual versión estable de Rust y usa funcionalidades async de Rust. 
  • 734,000 descargas para iron. Es un framework que actualmente no ha sido mantenido considerablemente pero dadas las descargas parece ser que era importante.
  • 515,000 descargas para rocket. En la versión actual de rocket la versión actual estable de Rust no es suficiente para que compile. Rocket requiere algunas funcionalidades "experimentales" que se están estabilizando y/o se planean remover de Rocket para que Rocket pueda compilar en la versión estable de Rust. Pero por ahora para usar rocket necesitamos la versión "nightly" de Rust. Eventualmente esta planeado que pueda usarse con la versión estable de Rust. A pesar de esto hay compañías que ya están usando Rocket en producción según lo mencionado en la plática "Rocket: Securing the Web at Compile-time" que puede encontrarse en Youtube. Rocket también actualmente no parece usar las funcionalidades de async de Rust así que parece ser una buena opción para aplicaciones pequeñas que no se enfrentan a una gran demanda. Para aplicaciones más demandantes actix-web podría ser una mejor opción.
  • 402,000 descargas para wrap. Este framework parece ser un poco más nuevo que Rocket. A diferencia de Rocket este puede usarse en la versión estable actual de Rust y usa funcionalidades async de Rust. 
Para esta prueba quiero un framework simple que me permita hacer un API REST que reciba y regrese JSON. Por lo que me decidí por Rocket ya que parece más amigable para principiantes de Rust. A continuación seguiré el proceso de ejemplo descrito en la página oficial de Rocket: https://rocket.rs/v0.4/guide/getting-started/

El primer paso es crear un proyecto usando "cargo new" y instalando Rust Nightly usando "rustup default nightly":

Creando el proyecto y instalando rust nightly usando "rustup default nightly"
Para agregar Rocket a nuestro proyecto solo es cuestión de agregar rocket al archivo "cargo.toml". 

[package]
name = "rocket-test"
version = "0.1.0"
authors = ["MiUsuario <micorreo@email.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rocket = "0.4.5"

Como se puede ver la versión de rocket al momento de esta publicación es 0.4.5. El siguiente paso es copiar y pegar el código de ejemplo en el archivo "main.rs", en este caso cambié el mensaje a "Hola, mundo! Estoy usando Rocket":


#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use] extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "Hola, mundo! Estoy usando Rocket"
}

fn main() {
    rocket::ignite().mount("/", routes![index]).launch();
}

Como podemos ver Rocket hace uso de atributos de Rust. Los atributos son las líneas que empiezan con "#" y afectan lo que sigue inmediatamente después de estos. Cuando un atributo afecta todo un ejecutable o toda una librería o todo un módulo se usa "#!" en lugar de sólo "#".

Como podemos ver por el uso de "#![feature(...)]" Rocket usa ciertas características/features de Rust que se activan con la línea "#![feature(proc_macro_hygiene, decl_macro)]". Luego tenemos que activar el uso de macros de Rocket (macros externos) usando la línea "#[macro_use] extern crate rocket;".

Usando el atributo "#[get("/")]" parece ser la forma en la que etiquetamos una función para que Rocket la maneje. Supongo que estos serán análogos a las funciones GET, PUT, DELETE y POST que se usan en HTTP/REST. En este caso la función "index" regresa un "str" que vive durante toda la vida del ejecutable, es decir que tiene un tiempo de vida (lifetime) del tipo "'static". Como este "str" vive durante toda la ejecución del programa entonces podemos regresar una referencia "&'static" sin problema de que deje de vivir, ya que vivirá durante todo el tiempo de ejecución del programa.

Finalmente tenemos la línea en el main que es "rocket::ignite().mount("/", routes![index]).launch();" donde estamos llamando varios métodos de la librería de Rocket. Por el uso del signo de exclamación "!" puedo ver que "routes!" se trata de una macro. Y le estamos pasando nuestra función "index".

Siguiendo la guía todavía no se nos explica a detalle que es todo esto, pero podemos correrlo ya usando el comando "cargo run".

Como esta es la primera vez que se ejecuta se tienen que descargar y compilar Rocket y sus dependencias de la página web cartes.io:

El resultado de ejecutar "cargo run" por primera vez. Se descargan las dependencias y después de descargar se compilan.
Una vez que esperamos a que se descarguen y se compilen las dependencias podremos ejecutar "cargo run" y ver Rocket corriendo:
El resultado de correr nuestro programa usando "cargo run" después de que ya tenemos las dependencias descargadas y compiladas
Mientras esta esto corriendo en la consola podemos abrir un navegador de internet como Google Chrome y ir a la página "http://localhost:8000" para ver el resultado de este pequeño ejemplo:

Google Chrome con la página http://localhost:8000
Como podemos ver la página nos muestra el texto que escribimos en la función "index". Con esto tenemos una pequeña aplicación web en Rust usando Rocket con lo que fueron pasos muy simples:

  1. "rustup default nightly"
  2. "cargo new rocket-test" y "cd rocket-test" 
  3. Agregar "rocket = "0.4.5"" como dependencia en Cargo.toml
  4. Las 12 líneas de código en main.rs que vienen en el ejemplo inicial de Rocket
  5. "cargo run"
  6. Esperar que se descarguen y compilen las dependencias
No olvidemos que podemos usar "cargo run --release" en lugar de "cargo run" para compilar con optimizaciones y menos información de debug.


Fuentes:

No hay comentarios.:

Publicar un comentario