> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/tokio-rs/axum/llms.txt
> Use this file to discover all available pages before exploring further.

# Form

> URL encoded form data extractor and response

Extractor and response type for URL encoded form data.

## Type signature

```rust theme={null}
pub struct Form<T>(pub T);
```

## As an extractor

The `Form` extractor deserializes form data from the request. The behavior depends on the request method:

* **GET or HEAD requests**: Form data is read from the query string (same as `Query`)
* **Other methods**: Form data is read from the request body with `Content-Type: application/x-www-form-urlencoded`

This matches how HTML forms are sent by browsers by default.

<Warning>
  Since parsing form data might require consuming the request body, the `Form` extractor must be **last** if there are multiple extractors in a handler. See [the order of extractors](/core-concepts/extractors#order-of-extractors).
</Warning>

### Basic usage

```rust theme={null}
use axum::{
    Form,
    routing::post,
    Router,
};
use serde::Deserialize;

#[derive(Deserialize)]
struct SignUp {
    username: String,
    password: String,
}

async fn accept_form(Form(sign_up): Form<SignUp>) {
    let username = sign_up.username;
    let password = sign_up.password;
    // ...
}

let app = Router::new().route("/signup", post(accept_form));
```

### Optional fields

Use `Option` for optional form fields:

```rust theme={null}
use serde::Deserialize;

#[derive(Deserialize)]
struct FormData {
    username: String,
    email: Option<String>,
    age: Option<u32>,
}
```

### Multiple values

Form fields with the same name can be collected into a `Vec`:

```rust theme={null}
use serde::Deserialize;

#[derive(Deserialize)]
struct Preferences {
    interests: Vec<String>,
}

// Form data: interests=reading&interests=coding&interests=travel
```

## As a response

`Form` can encode any type that implements `serde::Serialize` as `application/x-www-form-urlencoded`:

```rust theme={null}
use axum::Form;
use serde::Serialize;

#[derive(Serialize)]
struct Payload {
    value: String,
}

async fn handler() -> Form<Payload> {
    Form(Payload { value: "foo".to_owned() })
}
```

## Error handling

### Extractor rejections

<ResponseField name="InvalidFormContentType" type="415">
  The request method is not GET/HEAD and the content-type is not `application/x-www-form-urlencoded`.
</ResponseField>

<ResponseField name="FailedToDeserializeForm" type="400">
  Failed to deserialize form data from query string (GET/HEAD requests).
</ResponseField>

<ResponseField name="FailedToDeserializeFormBody" type="422">
  Failed to deserialize form data from request body (other methods).
</ResponseField>

### Example errors

```rust theme={null}
// GET request with invalid query string:
// Status: 400 Bad Request
// Body: "Failed to deserialize form: age: invalid digit found in string"

// POST request with invalid form body:
// Status: 422 Unprocessable Entity
// Body: "Failed to deserialize form body: age: invalid digit found in string"

// POST request without correct content-type:
// Status: 415 Unsupported Media Type
```

## GET vs POST behavior

The `Form` extractor automatically handles both query strings and request bodies:

```rust theme={null}
use axum::{
    Form,
    routing::{get, post},
    Router,
};
use serde::Deserialize;

#[derive(Deserialize)]
struct SearchForm {
    query: String,
}

async fn search(Form(form): Form<SearchForm>) {
    // Works with both:
    // - GET /search?query=rust
    // - POST /search with body: query=rust
}

let app = Router::new()
    .route("/search", get(search).post(search));
```

## Multipart forms

For `multipart/form-data` (file uploads), use the `Multipart` extractor instead:

```rust theme={null}
use axum::extract::Multipart;

async fn upload(mut multipart: Multipart) {
    // Handle multipart form data
}
```

## URL encoding

Form data uses URL encoding where special characters are percent-encoded:

```rust theme={null}
// Form data: message=hello%20world&emoji=%F0%9F%8E%89
#[derive(Deserialize)]
struct Message {
    message: String,  // "hello world"
    emoji: String,    // "🎉"
}
```
