- Rwf es un framework integral para crear aplicaciones web con Rust, basado en el patrón clásico MVC, y ofrece por defecto las funciones necesarias para construir apps web rápidas y seguras
- Entre sus funciones básicas se incluyen un servidor HTTP, un ORM para consultas PostgreSQL, plantillas dinámicas, autenticación y sesiones de usuario, middleware, trabajos en segundo plano y programados, y migraciones de base de datos
- También ofrece un framework REST integrado con soporte para serialización JSON, WebSockets, hosting de archivos estáticos, configuración por entorno, logging, métricas y CLI
- Está estrechamente integrado con Hotwired Turbo, lo que permite crear SPA impulsadas desde el backend, y ofrece un servidor WSGI para migraciones desde Django/Flask y un servidor Rack para migraciones desde Rails
- Actualmente está en estado beta y busca adopters tempranos; indica que la mayoría de las funciones están en buen estado y la documentación ya es utilizable
Framework web MVC para Rust
- Rwf es un framework integral para construir aplicaciones web con Rust
- Está escrito siguiendo el patrón clásico MVC (model-view-controller)
- Su objetivo es incluir por defecto las funciones necesarias para crear fácilmente apps web rápidas y seguras
- La documentación está disponible en la documentación oficial
Funcionalidades disponibles
- Servidor y manejo de solicitudes
- Datos y estructura de la aplicación
- Ofrece un ORM fácil de usar para crear consultas PostgreSQL
- Soporta migraciones de base de datos
- Ofrece Dynamic templates
- Incluye Authentication y sesiones de usuario integradas
- API y procesamiento de tareas
- Operación y herramientas de desarrollo
- Soporta configuración por entorno
- Ofrece logging y métricas
- Incluye CLI
Soporte para Hotwired Turbo y migración
Inicio rápido
- Crea una aplicación binaria de Rust y úsalo agregando
rwf a las dependencias
cargo add rwf
- La app básica usa
rwf::prelude::* y rwf::http::Server para definir controladores y rutas
use rwf::prelude::*;
use rwf::http::Server;
#[controller]
async fn index() -> Response {
Response::new().html("Welcome to Rwf!
")
}
#[tokio::main]
async fn main() {
Server::new(vec![
route!("/" => index),
])
.launch()
.await
.unwrap();
}
Ejemplos y estado del proyecto
- Los casos de uso comunes pueden verse en examples
- Rwf está actualmente en estado beta y busca adopters tempranos
- Indica que la mayoría de las funciones están en buen estado y la documentación ya es utilizable
- Las contribuciones son bienvenidas; la guía está en CONTRIBUTING, la explicación de la estructura del código en ARCHITECTURE y la lista de funciones deseadas en ROADMAP
1 comentarios
Opiniones de Hacker News
El lanzamiento parece algo bastante irreal; felicitaciones. Lo más importante que aprendí tras mucho tiempo haciendo MVC web con Rails es que el framework debe contener con firmeza la lógica de negocio de la capa de modelo.
Creo que conviene no poner en los modelos de datos callbacks como los que menciona Active Record, por ejemplo hooks como
afterCreate. Si todavía no están en el ORM pero están en el roadmap, creo que sería mejor que no estuvieran.Eso sí, esto solo funciona bien cuando se recomienda con fuerza una capa de servicios, es decir, de lógica de negocio. La mayoría de mis apps Rails estructuran objetos de comando/servicio con gems como Interactor.
Creo que solo con MVC y, por lo tanto, solo con la configuración básica de Rails, no es ideal escribir una app operable debido a la ausencia de una capa de servicios. También me da curiosidad por qué no se aprovechó algún ORM o query builder existente de la comunidad. Todavía no he escrito ni una línea de Rust, pero cada vez me da más curiosidad.
Creo que los servicios deberían ser casi siempre fragmentos de código más complejos y específicos, disparados desde el modelo. Controladores delgados y modelos gruesos ha sido lo mejor para depurar, organizar y descubrir código; por experiencia, usar muchos servicios genera mucho código espagueti.
Incluso desde una perspectiva puramente orientada a objetos, el modelo es el objeto básico que define la entidad.
Userdebería saber todo lo que necesita saber sobre sí mismo y comunicarse con otras entidades mediante mensajes.Eso sí, estoy de acuerdo con lo de los callbacks. Los callbacks generan muchos efectos secundarios extraños y hacen que depurar sea realmente difícil.
Se puede hacer así, pero se vuelve bastante difícil razonar sobre de qué maneras puede actualizarse una entidad. Porque cualquier cantidad de procedimientos podría actualizarla, y cada uno podría tener sus propias reglas de negocio. En ese caso, también podrían hacer que los procedimientos escriban directamente en la base de datos y eliminar el modelo.
Pero después de más de 20 años desarrollando, llegué a la conclusión de que la encapsulación no es una funcionalidad sino una carga, y que los datos deben separarse de las operaciones que se realizan sobre ellos. A esto se le llama diseño orientado a datos o programación orientada a datos, y no soy la única persona que llegó a esa misma conclusión.
Hay otras formas de modelar que escalan bien, y también hay algunos artículos al respecto. Uno escrito por alguien de Basecamp es https://dev.37signals.com/vanilla-rails-is-plenty/.
Claro que esto es muy orientado a objetos, así que tampoco me entusiasma demasiado. Por ejemplo, el framework Phoenix de Elixir usa contextos para agrupar funcionalidad relacionada, que en pocas palabras pueden verse como fachadas.
Si te gustan los servicios, puedes usarlos, pero decir que MVC no es suficiente para producción me parece un poco errado. Manejar procesos de negocio pesados con callbacks del modelo no es bueno, pero para pequeñas tareas de moldear los datos en la forma correcta, funcionan bastante bien.
Puede que esté sesgado, sobre todo porque mi experiencia de programación empezó con PHP para Wordpress, donde los hooks se usan extensamente.
Lo que hice tiene una especificación de tablas que puede convertirse en definiciones SQL o generar formularios HTML con buen formato. Un controlador separado maneja todas las conexiones a la DB y las operaciones CRUD, y hay hooks antes y después que permiten, cuando hace falta, hacer referencias cruzadas fácilmente con otras tablas y restricciones.
Funciona bastante bien, pero si pudiera me cambiaría de inmediato a Laravel.
Si es un framework REST, esperaría que por defecto pudiera generar definiciones Swagger/OpenAPI. Creo que esa es una de las funciones estrella de FastAPI.
Tampoco termino de entender por qué hicieron su propio ORM en lugar de integrarse con un ORM existente como diesel.rs, ni por qué crearon su propio lenguaje de plantillas en vez de elegir un motor de plantillas popular ya existente.
Fuera de eso, el proyecto se ve realmente interesante y pienso seguirlo de cerca.
[0] https://diesel.rs/
[1] https://crates.io/categories/template-engine
En general fue un buen primer intento de adaptar los tipos de la base de datos a los tipos de Rust, pero un ORM debería ser más flexible y fácil de usar. La idea es que escribir queries sea más fácil, no más difícil :)
En cuanto a las plantillas, hacer tu propio lenguaje es casi un rito de iniciación al club de nerds mayores de 30. No leí el Dragon Book, pero en la universidad siempre quise tomar esa clase. Siempre hay múltiples implementaciones de lo mismo, y se sintió correcto usar esta implementación que imita muy de cerca lo que hace ERB de Rails.
Desde la perspectiva de SRE, me interesó https://levkk.github.io/rwf/migrating-from-python/. Por un lado, es realmente genial que hayan logrado esto, pero desde el punto de vista de un SRE que mira la estabilidad, me hace gritar por dentro.
Cuando la escala crece, esto debería manejarlo un proxy inverso como Caddy, Nginx o Traefik
Es posible escribir un servidor WSGI estable, y no es tan difícil si se presta un poco de atención a detalles como la cantidad de hilos, vacuum, o reiniciar cada n solicitudes como el antiguo php-fpm. Básicamente, si implementas la mayoría de las opciones que tiene uwsgi, vas por el camino correcto. Está en el roadmap hacer que Rwf sea comparable a ejecutar Gunicorn
La elección del nombre es realmente increíble. Es una forma de quedar arriba en los resultados de búsqueda :P
En serio, está bien hecho. Crear un buen framework es un trabajo sorprendentemente grande, y siempre es bueno ver a la gente explorar el espacio de diseño y probar ideas nuevas
rwf.RustOnWeb.com también se puede comprar por USD 10 :) Solo lo digo
Me gusta la expresión “piensa en Rails, no en Flask”. En los lenguajes con tipado estático hacen falta más, o mejores, frameworks con opiniones fuertes al estilo Rails/Django
Está bien hecho. Valdría la pena intentar que aparezca en https://www.arewewebyet.org/
¡Bien! Django/Rails hecho con un lenguaje de primer nivel.
Como sugerencia,
async-traitya debería estar estabilizado, así que quizá la macro ya no sea necesaria, y sería bueno agregar una integración con OpenTelemetry para obtener métricas y trazas por defecto. Para targets Linux también estaría bien usar jemallocPlaneo agregar etiquetas de OpenTelemetry a las funciones del crate
tracing. jemalloc se puede agregar a las apps binarias que usan Rwf, y no hace falta incluirlo como dependencia de la biblioteca.[1] https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-trait...
Intenté aprender Rust, pero abandoné al principio. Viniendo de C#, C/C++, Java y Python, Rust se me hizo raro.
Lo que me venció no fue lo raro en sí, sino que, comparado con lenguajes como C#, Java y Python, la velocidad para terminar una tarea era menor.
Hoy hago principalmente desarrollo web, así que la facilidad de uso y la productividad son lo más importante. Rust puede ser un poco mejor en throughput y velocidad, pero si miras benchmarks modernos de frameworks web, C# y Java también lo hacen bastante bien en ese aspecto.
Espero que esto no se lea como una crítica a Rust ni como una forma de restarle mérito al gran logro de crear un framework MVC desde cero. Va más por el lado de “la herramienta adecuada para el trabajo”
Para superar la curva de aprendizaje hace falta una motivación fuerte. Puede ser que tengas que usar el lenguaje, que te atraigan los beneficios del sistema de tipos y la seguridad, o que tengas alguna razón concreta propia.
Si no tienes esa motivación, está totalmente bien. Yo tampoco la tenía al principio, y por eso mis primeros intentos de aprender no llegaron muy lejos. Como siente mucha gente, Rust toma más tiempo que Java o Python para terminar cosas, y exige pensar más por adelantado. En ciertas situaciones vale la pena, pero si no tienes claro por qué aceptar ese trade-off, no hay una razón fuerte para seguir
Hace poco dejé el loader JS de webpack y empecé a usar un loader en Rust 50 veces más rápido, y yo también me enganché con Rust. Rust tiene un gran impacto en la mejora de rendimiento, y ahora C++ y Rust son mis lenguajes favoritos
Para trabajo de backend en Rust evalué todos los candidatos que suelen mencionarse e hice pequeños prototipos. Hasta ahora, aunque es más de bajo nivel de lo que me gustaría, terminé aceptando a regañadientes la conclusión colectiva de que Axum es la mejor opción en general.
Los otros candidatos eran Loco y Rocket. Loco se parecía demasiado a Rails, y Rocket empezó a molestarme con sus macros recién después de usar más Rust.
Este framework parece encajar perfectamente con mi criterio de “baterías incluidas, pero no demasiado prescriptivo”. Es una buena incorporación al ecosistema