The Json response type serializes data to JSON and automatically sets the Content-Type: application/json header.
Basic usage
Return any type that implements serde::Serialize:
use axum::{Json, routing::get, Router};
use serde::Serialize;
use uuid::Uuid;
#[derive(Serialize)]
struct User {
id: Uuid,
username: String,
}
async fn get_user() -> Json<User> {
let user = User {
id: Uuid::new_v4(),
username: "alice".to_string(),
};
Json(user)
}
let app = Router::new().route("/user", get(get_user));
How it works
IntoResponse implementation
The Json type implements IntoResponse by serializing the inner value using serde_json:
impl<T> IntoResponse for Json<T>
where
T: Serialize,
{
fn into_response(self) -> Response {
// Serializes to JSON with initial 128-byte buffer capacity
// Sets Content-Type: application/json on success
// Returns 500 Internal Server Error if serialization fails
}
}
See implementation in axum/src/json.rs:197-232.
Serialization behavior
The serialization process:
- Creates a
BytesMut buffer with 128-byte initial capacity
- Serializes the value using
serde_json::to_writer
- On success: Returns response with
Content-Type: application/json header
- On failure: Returns
500 Internal Server Error with error message as plain text
Error handling
If serialization fails (e.g., map with non-string keys), a 500 status code is returned with the error message:
async fn handler() -> Json<HashMap<Vec<u8>, i32>> {
// This will fail to serialize and return 500
let map = HashMap::from([(vec![1, 2, 3], 123)]);
Json(map)
}
To prevent status code override on serialization errors, use ForceStatusCode:
use axum_core::response::ForceStatusCode;
use axum::http::StatusCode;
// Force 418 status even if serialization fails
let response = (
ForceStatusCode(StatusCode::IM_A_TEAPOT),
Json(potentially_failing_data),
);
Response fields
Automatically set to application/json
The serialized JSON bytes
Common patterns
Returning JSON with custom status
use axum::http::StatusCode;
async fn create_user(/* ... */) -> (StatusCode, Json<User>) {
let user = create_user_in_db().await;
(StatusCode::CREATED, Json(user))
}
Returning JSON arrays
async fn list_users() -> Json<Vec<String>> {
Json(vec!["alice".to_string(), "bob".to_string()])
}
See also