Construyendo
APIs Web de alto rendimiento con Rust y Rocket
@sebasmagri - Enero de 2017
Agenda
- ¿APIs?
- ¿Qué necesitas saber de Rust para trabajar con Rocket?
- Breve introducción a Rocket
- Manos a la obra
- Referencias adicionales
¿Qué es un API Web?
Conceptos Básicos
API
Application Programmer Interface
+
Web
Tecnologías y Protocolos usables en un ámbito específico
Algunos Patrones o Estilos
- SOA
- RPC
- Como Salga.
- REST
REST
-
Recursos
- URIs o Identificadores
- Representaciones
- Verbos HTTP
Herramientas para el desarrollo Web con Rust
- Frameworks
- Iron, Nickel, Pencil, Rocket
- Soporte de bases de datos
- Formatos y Tipos de Contenido
¿Qué tanto Rust debo saber para hacer APIs Web con Rocket?
Principios Fundamentales de Rust
Seguridad
Concurrencia
Velocidad
Structs
Enums
Manejo de datos
struct LoadAvg {
last1: f64,
last5: f64,
last15: f64
}
...
let load_avg = LoadAvg {
last1: 0.36,
last5: 0.71,
last15: 1.1
}
...
println!("{}", load_avg.last1)
enum Gender {
Male,
Female,
Other
}
...
struct Person {
name: String,
age: i32,
gender: Gender
}
...
let p = Person {
name: "Sebastián".to_string(),
age: 15,
gender: Gender::Male
}
Descripción de un tipo
Un tipo con opciones
Seguridad
Ownership | Borrowing | Lifetimes |
---|
Herramientas para el manejo seguro de memoria, aún en ambientes altamente concurrentes.
Ownership y Lifetimes
Manejo de propiedad de memoria
- Cualquier valor se puede usar solo una vez. En su primer uso es movido a su nueva ubicación y ya no se puede usar desde la anterior.
- Todo valor es destruido al terminar su scope.
- Un bloque de código puede producir un valor usable por un bloque superior, como valor de retorno.
- Todo valor tiene un tiempo de vida (lifetime) asociado, el cual define el alcance del mismo (scope).
Borrowing
AKA: peleando con el borrow checker
- Puede existir una y solo una referencia mutable a una variable al mismo tiempo.
- Pueden existir tantas referencias inmutables a una variable como sean necesarias.
- No se pueden mezclar referencias mutables e inmutables a una misma variable.
Rocket
Un framework de desarrollo Web para Rust, enfocado en la simplicidad, el rendimiento, la flexibilidad, y el manejo seguro de tipos de datos.
https://rocket.rs/
Routes
Rocket hace uso de atributos de ruta para definir qué funciones atienden una solicitud específica.
Estos atributos permiten definir el método, la ruta y los tipos de datos de solicitud y de respuesta.
#[get("/")]
fn home() -> String { ... }
#[post("/noticias", data = "<entry>")]
fn new(entry: Entry) -> String { ... }
#[head("/noticias")]
fn head() -> String { ... }
#[get("/noticias")]
fn entries() -> String { ... }
#[get("/noticias/<id>")]
fn entries(id: i32) -> String { ... }
#[put("/noticias/<id>", data = "<entry>")]
fn update(entry: Entry) -> String { ... }
#[patch("/noticias/<id>", data = "<entry>")]
fn update_partial(id: i32, entry: Entry) -> ...
#[route(OPTIONS, "/noticias")]
fn options() -> String { ... }
Manejo de URLs
Handlers
Un handler se encarga de manejar una solicitud para la que el router tiene una coincidencia en las rutas declaradas y de emitir una respuesta después de procesar los datos de entrada.
#[get("/")]
fn hello() -> String {
"Hello World".to_string()
}
// Parámetros dinámicos por URL
#[get("/<name>")]
fn home(name: &str) -> String {
format!("Hello {}!", name)
}
// Parámetros en el cuerpo de la solicitud
#[post("/login", data = "<user_form>")]
fn login(user_form: Form<UserLogin>) -> String {
// Use `user_form`, return a String.
}
// ## Request Guards
// Permiten establecer requerimientos
// que debe cubrir una solicitud
#[get("/sensitive")]
fn sensitive(key: APIKey) -> &'static str { ... }
Manejo de solicitudes
Responders
Responder es un trait provisto por Rocket que se encarga de convertir un tipo de datos en una respuesta.
Cualquier tipo de datos devuelto por un handler debe implementar el trait Responder.
struct SystemLoad {
last1: f32,
last5: f32,
last15: f32
}
impl<'r, R: Responder<'r>> Responder<'r> for SystemLoad { ... }
#[get("/")]
fn hello() -> T {
"Hello World".to_string()
}
Procesamiento de respuestas
Iniciando la aplicación
El proceso de arranque permite hacer el montaje de los manejadores de solicitudes (o de errores) en sus rutas raíz e iniciar un servidor Web para la aplicación.
rocket::ignite()
.mount("/base", routes![index, another])
.launch()
...
🚀 Rocket has launched from http://localhost:8000...
A lo práctico...
Algunas referencias finales
- Repositorio de este taller: https://github.com/sebasmagri/rocket-loadavg-api
- El libro de Rust: https://doc.rust-lang.org/stable/book/
- Documentación de crates: https://docs.rs/
- La guía oficial de Rocket: https://rocket.rs/guide
- Los ejemplos oficiales: https://github.com/SergioBenitez/Rocket
- El canal de IRC de Rocket: #rocket@irc.mozilla.org
¡Gracias!
Construyendo servicios web de alto rendimiento con Rust y Rocket
By sebasmagri
Construyendo servicios web de alto rendimiento con Rust y Rocket
- 1,715