Build server-first, highly-interactive, and beautiful web applications in Rust.
...because the current web-based application development trends are worth objecting to.
Due to an ongoing refactor, breaking changes are expected in the near future. See #320 for current status.
Unfortunately, Deno is a required runtime dependency. We aim to remove this dependency in the near future.
# MacOS
brew install radical-ui/tap/objection
# Linux / Windows
cargo install --git https://github.com/radical-ui/objection.git --bin objection
Objection works by generating a network bridge, allowing a series of typescript components (referred to as the runtime) to be managed by your backend (referred to as the engine). In practice, it feels like a merge between Phenix Liveview and HTMX.
The default runtime is located in the runtime
folder, but you can create and use your own.
The runtime can be started, and Rust bindings generated, by using the following command:
objection --engine rust --bindings-path src/bindings.rs --engine-url http://localhost:8000/ui run
The corresponding Rust engine can be written like so:
// src/main.rs
use axum::{extract::State, routing::post, Json, Router};
use bindings::Label;
use objection::{handle_request, RootUi, UiResponse};
use tokio::net::TcpListener;
use tower_http::cors::CorsLayer;
mod bindings;
#[tokio::main]
async fn main() {
let app = Router::new()
.route(
"/ui",
post(move |Json(body): Json<Value>| async move {
Json(handle_request(body, |_, ui| async {
ui.set_root_ui(Label::new("Hello, world!"));
Ok(ui.into_reponse())
}).await)
}),
)
.layer(CorsLayer::very_permissive());
let listener = TcpListener::bind(("localhost", 8000)).await.unwrap();
println!("listening at http://localhost:8000");
axum::serve(listener, app).await.unwrap();
}
That should do it. After starting the engine, navigate to the app server that objection will have started at http://localhost:3000
.
Behind the scenes, the app will connect to the engine at http://localhost:8000
over the generated network bridge.
You'll want to make sure that you have development dependencies installed:
Then, start up the example project:
runner dev