Key Concepts
1. RuniqueEngine
The application's main shared state:
pub struct RuniqueEngine {
pub db: Arc<DatabaseConnection>,
pub tera: Arc<Tera>,
pub config: RuniqueConfig,
}
Injected as an Axum Extension, accessible in every handler via request.engine.
2. Request — The Main Extractor
Request is Runique's central extractor. It replaces the former TemplateContext and contains everything required:
pub struct Request {
pub engine: AEngine, // Arc<RuniqueEngine>
pub session: Session, // tower-sessions session
pub notices: Message, // Flash messages
pub csrf_token: CsrfToken, // CSRF token
pub context: Context, // Tera context
pub method: Method, // HTTP method
}
Usage inside a handler:
pub async fn index(mut request: Request) -> AppResult<Response> {
context_update!(request => {
"title" => "Home",
});
request.render("index.html")
}
Methods:
request.render("template.html")— Render with the current contextrequest.method.is_safe()— Check the HTTP method (GET/HEAD)
3. `request.form()` — Integrated Form Extraction
pub async fn handler(mut request: Request) -> AppResult<Response> {
let form: RegisterForm = request.form();
let form = match ValidationForm::try_new(form, &request).await {
Ok(validated) => {
let user = validated.save(&request.engine.db).await?;
success!(request.notices => "User created!");
return Ok(Redirect::to("/").into_response());
}
Err(form) => form,
};
context_update!(request => {
"form" => &form,
});
request.render("form.html")
}
request.form() automatically:
- Parses the request body
- Creates a form instance
- Verifies the CSRF token
- Fills in submitted data