DEV Community

Mario García
Mario García

Posted on

Web Apps con Rust + Rocket

De acuerdo a su sitio, Rocket es un framework web para Rust que hace que sea sencillo escribir aplicaciones web rápidas y seguras, sin sacrificar flexibilidad, usabilidad y el tipado fuerte.

La última versión disponible es la 0.4 publicada el 6 de Diciembre, el día que se lanzó Rust 2018, lo que garantiza su compatibilidad con la última edición del lenguaje. Rocket funciona con Rust Nightly.

Configuración

  • Instalar Rust Nightly con rustup si no se tiene instalado.
$ rustup install nightly
Enter fullscreen mode Exit fullscreen mode
  • Crear un nuevo proyecto con Cargo.
$ cargo new hello_rocket
Enter fullscreen mode Exit fullscreen mode
  • Asignar Nightly al proyecto creado.
$ cd hello_rocket
$ rustup override set nightly
Enter fullscreen mode Exit fullscreen mode

Estructura de directorios

La estructura del directorio de un proyecto desarrollo con Rocket es la siguiente:

  • src
  • static
  • templates
  • Cargo.toml

static es el directorio en el que se guardan las imágenes, archivos de JavaScript y hojas de estilo (CSS).

En el directorio templates se guardan las plantillas HTML.

Estos directorios deben crearse.

Templates

Rocket soporta dos sistemas de plantillas, Tera que está inspirado en Jinja2 y el lenguaje de plantillas de Django, y Handlebars.

¡Hola, mundo!

¡Es momento de crear el primer ejemplo con Rocket!

Cargo.toml

Agregar Rocket como dependencia al archivo Cargo.toml.

[package]
name = "hello_rocket"
version = "0.1.0"
authors = ["mattdark"]
edition = '2018'

[dependencies]
rocket = "0.4"
Enter fullscreen mode Exit fullscreen mode

src/main.rs

Editar el archivo main.rs en src y colocar el código que mostrará el texto "¡Hola, mundo!" en el navegador.

#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate rocket;

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

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

Con la línea #![feature] se le indica a Rust que se usarán funcionalidades del compilador disponibles en Nightly.

Se importa el crate de Rocket y todas sus macros al espacio de nombres mediante #[macro_use] extern crate rocket;.

Se declara la función index que mostrará el texto en el navegador y en la función principal main se inicia el servidor de la aplicación.

Iniciando la aplicación

Se ejecuta el siguiente comando para iniciar el servidor de la aplicación.

$ cargo run
Enter fullscreen mode Exit fullscreen mode

El comando anterior se encarga de descargar las dependencias del proyecto, de acuerdo a la información del archivo Cargo.toml, realiza la compilación, genera el binario correspondiente e inicia el servidor.

En caso de no haber error alguno, en la terminal aparece lo siguiente.

🔧 Configured for development.
    => address: localhost
    => port: 8000
    => log: normal
    => workers: 4
    => secret key: generated
    => limits: forms = 32KiB
    => keep-alive: 5s
    => tls: disabled
🛰  Mounting /:
    => GET / (index)
🚀 Rocket has launched from http://localhost:8000
Enter fullscreen mode Exit fullscreen mode

Desde la barra de direcciones del navegador se accede a http://localhost:8000 y debe mostrar lo siguiente.
Hola mundo

Routing

#[get("/world")] {            // <- route attribute
fn world() -> &'static str {  // <- request handler
    "¡Hola, mundo!"
}
Enter fullscreen mode Exit fullscreen mode

La función world, declarada en el código anterior, corresponde al manejador de peticiones y está asociada a la ruta /world, la cual recibirá peticiones de tipo GET.

Mounting

Después de declarar una ruta, indicar el tipo de peticiones que recibirá y declarar la función que se encargará de manejar las peticiones, esta deberá montarse como se muestra a continuación.

fn main() {
    rocket::ignite.mount("/hello", routes![world]).launch();
}
Enter fullscreen mode Exit fullscreen mode

Lo anterior crea un nueva instancia de Rocket con la función ignite y monta la ruta world en la dirección /hello. Las peticiones GET a /hello/world se redigirán a la función world. El servidor de la aplicación se inicia con la función launch.

Una vez iniciado el servidor, desde la barra de direcciones acceder a http://localhost:8000/hello/world y mostrará el siguiente texto.
Hola mundo

Las rutas hello e index no están declaradas por lo que si se intenta acceder a http://localhost:8000 y http://localhost:8000/hello mostrará lo siguiente.
404

Estas rutas y su manejador correspondiente deberán declararse en el código en caso de que se necesite, y montarlas usando la macro routes.

Métodos

Los métodos soportados por Rocket son los siguientes:

  • get
  • put
  • post
  • delete
  • head
  • patch
  • options

Direcciones dinámicas

...
use rocket::http::RawStr;

#[get("/hello/<name>")]
fn hello(name: &RawStr) -> String {
    format("¡Hola, {}!", name.as_str())
}
Enter fullscreen mode Exit fullscreen mode

Una ruta puede recibir parámetros, como se observa en el código anterior, en el que la ruta hello recibe el parámetro <name>, que en el manejador de peticiones correspondiente, hello, guarda en la variable name, para luego imprimir como parte del texto que mostrará en el navegador.

&RawStr es un tipo de dato de Rocket, por lo que hay que decirle a Rust que se usará con la línea use rocket::http::RawStr.

Al visitar /hello/Mario en el navegador aparecerá lo siguiente.
Hola Mario

Archivos estáticos

En la estructura de directorios de Rocket, el directorio src es donde se guardan las imágenes, archivos de JavaScript y hojas de estilo (CSS).

...
use std::path::{Path, PathBuf};
use rocket::response::NamedFile;
...
#[get("/<file..>")]
fn files(file: PathBuf) -> Option<NamedFile> {
     NamedFile::open(Path::new("static/").join(file)).ok()
}

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

Toda petición GET para abrir un archivo enviada a / será recibida en el parámetro <file..> y manejada por la función files.

La línea NamedFile::open(Path::new("static/").join(file)).ok() se usa para decirle a Rust cual es el directorio donde se encuentran los archivos estáticos.

Con una nueva ruta declarada, esta debe agregarse a la macro routes para que pueda montarse correctamente.

Plantillas

Rocket soporta Tera y Handlebars como sistemas de plantillas.

Cargo.toml

En el archivo Cargo.toml se agrega lo siguiente para decirle que se usará Handlebars. Si se usa Tera solo se reemplaza handlebars por tera.

...
handlebars = "1.1.0"

[dependencies.rocket_contrib]
version = "0.4"
features = ["handlebars_templates"]
Enter fullscreen mode Exit fullscreen mode

src/main.rs

Una vez que se indica cuales son las dependencias necesarias para usar cualquiera de los sistemas de plantillas, se modifica el archivo main.rs en src.

...
extern crate rocket_contrib;
use rocket_contrib::templates::{template, handlebars};

#[get("/")]
fn index() -> Template {
    Template::render("index")
}
...
fn main() {
    rocket::ignite().mount("/", routes![index, files])
    .attach(Template::fairing())
    .launch();
}
Enter fullscreen mode Exit fullscreen mode

En primer lugar se importa el crate rocket_contrib y todas sus macros con la línea extern crate rocket_contrib. En seguida se indica el sistema de plantillas que se usará con la línea use rocket_contrib::templates::{template, handlebars};.

Para importar una plantilla se usa la función render y se especifica el tipo de dato que la función debe retornar, en este caso es Template.

Para asegurar que el middleware (fairing, como se conoce en Rocket) de Template se adjunte a la aplicación, en la función principal se agrega la línea .attach(Template::fairing()).

Las plantillas deberán colocarse en el directorio templates y el nombre debe corresponder con el indicado en Template::render("index"). Del código anterior se infiere que el nombre de la plantilla es index.html.hbs.

En este artículo he descrito de manera general como se crea una aplicación web con Rocket. Espero que la información sea útil. En un próximo artículo mostraré un ejemplo de aplicación desarrollada con este framework.

Latest comments (0)