Documentation / Forms / Form extraction — `request.form("name")`
Form extraction — `request.form("name")`
request.form("name") is a method built into Request that orchestrates a full pipeline behind the scenes:
request.form("name") is a method built into Request that orchestrates a full pipeline behind the scenes:
- Aegis — Single body extraction (multipart, urlencoded, json) normalized into a
HashMap, within the request size limit. For a multipart body, no file is written before a valid CSRF token (X-CSRF-Tokenheader, or acsrf_tokenfield placed before the files). - CSRF — The pipeline records whether the
csrf_tokenfield's token is valid. It does not reject the request for that:request.form("name")marks the form invalid (csrf.invalid_or_missing) andtry_formwill not validate it. Upstream, the CSRF middleware has already refused with a 403 a wrongX-CSRF-Tokenheader, a body that is not a form (JSON…) without the header, and a form posted from another site. - Construction — Builds the form
Tand fills its fields. Validation runs afterwards, inValidationForm::try_form, and only when the request sends back the name given to the form.
use runique::prelude::*;
pub async fn register(mut request: Request) -> AppResult<Response> {
let form: SignupForm = request.form("signup");
if let Ok(validated) = ValidationForm::try_form(form, &request).await {
// Valid form → processing
}
// ...
}
💡 The developer simply calls
request.form("name")— the entire security pipeline is transparent.
Full example — display, validate, save
A single handler serves both display (GET) and submission (POST). request.form("name") builds the form in both cases: empty on GET, filled from the body on POST.
use runique::prelude::*;
pub async fn register(mut request: Request) -> AppResult<Response> {
let form: SignupForm = request.form("signup");
let template = "register_form.html";
// GET (nothing submitted) or invalid POST — re-render with errors
let validated = match ValidationForm::try_form(form, &request).await {
Ok(validated) => validated,
Err(form) => {
context_update!(request => { "register_form" => &form });
return request.render(template);
}
};
// Valid POST — save. `save` consumes the form and gives it back:
// `Ok(form)` once written, `Err(form)` with the DB error already attached.
match validated.save(&request.engine.db).await {
Ok(_form) => {
success!(request.notices => "Welcome!");
Ok(Redirect::to("/").into_response())
}
Err(form) => {
context_update!(request => { "register_form" => &form });
request.render(template)
}
}
}
Key points:
request.form("name")returns a ready-to-use form — no manual construction.ValidationForm::try_form(form, &request).awaitchecks the request sends that name back, dispatches on the HTTP method (allow_get/allow_post) then validates;Okproves at the type level the form was validated,Errreturns the form with its field errors to re-render (rendered automatically by{% form.register_form %}).validated.save(&request.engine.db).awaitpersists the entity and returns the form:Ok(form)once written,Err(form)if the database refuses (unique constraint, missing row). The error is already on that form.
← Forms | RuniqueForm trait →