> ## 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.

# Json

> JSON extractor and response type

JSON extractor and response type.

When used as an extractor, it deserializes request bodies into types that implement `serde::DeserializeOwned`. When used as a response, it serializes types that implement `serde::Serialize` to JSON.

## Type signature

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

## As an extractor

The `Json` extractor consumes the request body and deserializes it as JSON.

<Warning>
  Since parsing JSON requires consuming the request body, the `Json` 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::{
    extract::Json,
    routing::post,
    Router,
};
use serde::Deserialize;

#[derive(Deserialize)]
struct CreateUser {
    email: String,
    password: String,
}

async fn create_user(Json(payload): Json<CreateUser>) {
    // payload is a CreateUser
    let email = payload.email;
    let password = payload.password;
    // ...
}

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

### Content-Type validation

The request must have a `Content-Type: application/json` header (or similar like `application/problem+json`). Requests without this header will be rejected with `415 Unsupported Media Type`.

```rust theme={null}
// Valid content types:
// - application/json
// - application/json; charset=utf-8
// - application/cloudevents+json
// - application/*+json (any JSON-based media type)
```

## As a response

When returned from a handler, `Json` serializes the value to JSON and sets the `Content-Type: application/json` header automatically.

```rust theme={null}
use axum::{
    extract::Path,
    routing::get,
    Router,
    Json,
};
use serde::Serialize;
use uuid::Uuid;

#[derive(Serialize)]
struct User {
    id: Uuid,
    username: String,
}

async fn get_user(Path(user_id): Path<Uuid>) -> Json<User> {
    let user = find_user(user_id).await;
    Json(user)
}

async fn find_user(user_id: Uuid) -> User {
    // ...
    # todo!()
}

let app = Router::new().route("/users/{id}", get(get_user));
```

## Error handling

### Extractor rejections

<ResponseField name="MissingJsonContentType" type="415">
  The request doesn't have a `Content-Type: application/json` header.
</ResponseField>

<ResponseField name="JsonSyntaxError" type="400">
  The body doesn't contain syntactically valid JSON.
</ResponseField>

<ResponseField name="JsonDataError" type="422">
  The body contains syntactically valid JSON, but it couldn't be deserialized into the target type.
</ResponseField>

<ResponseField name="FailedToBufferBody" type="varies">
  Buffering the request body failed.
</ResponseField>

### Example error responses

```rust theme={null}
// Missing content-type header:
// Status: 415 Unsupported Media Type

// Invalid JSON syntax:
// Status: 400 Bad Request
// Body: "Failed to parse the request body as JSON: EOF while parsing an object at line 1 column 1"

// Invalid data:
// Status: 422 Unprocessable Entity  
// Body: "Failed to deserialize the JSON body into the target type: missing field `email` at line 1 column 25"
```

### Response serialization errors

If serialization fails when using `Json` as a response, a `500 Internal Server Error` will be returned with the error message as the body.

## Parsing from bytes

You can construct a `Json<T>` from bytes directly:

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

#[derive(Deserialize)]
struct Data {
    value: String,
}

let bytes = br#"{"value": "hello"}"#;
let Json(data): Json<Data> = Json::from_bytes(bytes).unwrap();
assert_eq!(data.value, "hello");
```

## Optional JSON

Use `Option<Json<T>>` to make JSON extraction optional based on the presence of a `Content-Type` header:

```rust theme={null}
async fn handler(json: Option<Json<Data>>) {
    match json {
        Some(Json(data)) => {
            // Request had JSON content
        }
        None => {
            // No Content-Type header present
        }
    }
}
```
