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 redirect from the JSON response and navigates via SPA fetch (same-origin paths).
  • Without JavaScript — server responds with 303 See Other and Location header.
  • 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\").