rust 46 lines · 8 steps

Validating a signup form in Axum

An Axum handler parses a submitted form, collects per-field validation errors, and returns either 422 or 201.

Explained by highlit
1use axum::{extract::Form, http::StatusCode, response::{IntoResponse, Response}, Json};
2use serde::Deserialize;
3use serde_json::json;
4use std::collections::HashMap;
5 
6#[derive(Deserialize)]
7pub struct SignupForm {
8 username: String,
9 email: String,
10 password: String,
11 age: Option<u32>,
12}
13 
14pub async fn signup(Form(form): Form<SignupForm>) -> Response {
15 let mut errors: HashMap<&'static str, Vec<String>> = HashMap::new();
16 
17 if form.username.trim().len() < 3 {
18 errors.entry("username").or_default().push("must be at least 3 characters".into());
19 }
20 if !form.username.chars().all(|c| c.is_alphanumeric() || c == '_') {
21 errors.entry("username").or_default().push("may only contain letters, digits and underscores".into());
22 }
23 
24 if !form.email.contains('@') || !form.email.contains('.') {
25 errors.entry("email").or_default().push("is not a valid email address".into());
26 }
27 
28 if form.password.len() < 8 {
29 errors.entry("password").or_default().push("must be at least 8 characters".into());
30 }
31 if !form.password.chars().any(|c| c.is_ascii_digit()) {
32 errors.entry("password").or_default().push("must contain a digit".into());
33 }
34 
35 if let Some(age) = form.age {
36 if age < 13 {
37 errors.entry("age").or_default().push("must be at least 13".into());
38 }
39 }
40 
41 if !errors.is_empty() {
42 return (StatusCode::UNPROCESSABLE_ENTITY, Json(json!({ "errors": errors }))).into_response();
43 }
44 
45 (StatusCode::CREATED, Json(json!({ "username": form.username }))).into_response()
46}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Accumulating errors in a map lets you report every problem at once instead of failing on the first.
  2. 2Deriving Deserialize on a struct turns raw form bytes into typed, validated fields for free.
  3. 3Returning a (StatusCode, Json) tuple is the idiomatic way to pair a status with a body in Axum.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Validating a signup form in Axum — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code