PRG pattern
Post/Redirect/Get — avoid duplicate form submissions after #[submit].
Why
After a successful POST, redirect to a GET URL so refresh does not re-submit the form.
Return a redirect
#[submit]
async fn create_item(form: ItemForm, _req: &FlowRequest) -> Result<Redirect, SubmitError> {
db::insert(&form).await.map_err(|_| SubmitError::new("Failed"))?;
Ok(redirect("/items"))
}
// Or any serializable struct with a `redirect` field:
#[derive(Serialize)]
struct CreateResult { redirect: String }
#[submit]
async fn create_alt(form: ItemForm, _req: &FlowRequest) -> Result<CreateResult, SubmitError> {
Ok(CreateResult { redirect: "/items".into() })
}Behavior
- With JavaScript — runtime reads
redirectfrom the JSON response and navigates via SPA fetch (same-origin paths). - Without JavaScript — server responds with 303 See Other and
Locationheader. - Security — only root-relative paths (
/items) are allowed; open redirects are rejected.
Flash messages
Redirect with a query flag — see Query params — e.g. redirect(\"/items?created=1\").