|  | use crate::{ | 
|  | body::{Bytes, HttpBody}, | 
|  | extract::{rejection::*, FromRequest}, | 
|  | BoxError, | 
|  | }; | 
|  | use async_trait::async_trait; | 
|  | use axum_core::response::{IntoResponse, Response}; | 
|  | use bytes::{BufMut, BytesMut}; | 
|  | use http::{ | 
|  | header::{self, HeaderMap, HeaderValue}, | 
|  | Request, StatusCode, | 
|  | }; | 
|  | use serde::{de::DeserializeOwned, Serialize}; | 
|  |  | 
|  | /// JSON Extractor / Response. | 
|  | /// | 
|  | /// When used as an extractor, it can deserialize request bodies into some type that | 
|  | /// implements [`serde::Deserialize`]. The request will be rejected (and a [`JsonRejection`] will | 
|  | /// be returned) if: | 
|  | /// | 
|  | /// - The request doesn't have a `Content-Type: application/json` (or similar) header. | 
|  | /// - The body doesn't contain syntactically valid JSON. | 
|  | /// - The body contains syntactically valid JSON but it couldn't be deserialized into the target | 
|  | /// type. | 
|  | /// - Buffering the request body fails. | 
|  | /// | 
|  | /// ⚠️ 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"][order-of-extractors] | 
|  | /// | 
|  | /// [order-of-extractors]: crate::extract#the-order-of-extractors | 
|  | /// | 
|  | /// See [`JsonRejection`] for more details. | 
|  | /// | 
|  | /// # Extractor example | 
|  | /// | 
|  | /// ```rust,no_run | 
|  | /// use axum::{ | 
|  | ///     extract, | 
|  | ///     routing::post, | 
|  | ///     Router, | 
|  | /// }; | 
|  | /// use serde::Deserialize; | 
|  | /// | 
|  | /// #[derive(Deserialize)] | 
|  | /// struct CreateUser { | 
|  | ///     email: String, | 
|  | ///     password: String, | 
|  | /// } | 
|  | /// | 
|  | /// async fn create_user(extract::Json(payload): extract::Json<CreateUser>) { | 
|  | ///     // payload is a `CreateUser` | 
|  | /// } | 
|  | /// | 
|  | /// let app = Router::new().route("/users", post(create_user)); | 
|  | /// # async { | 
|  | /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); | 
|  | /// # }; | 
|  | /// ``` | 
|  | /// | 
|  | /// When used as a response, it can serialize any type that implements [`serde::Serialize`] to | 
|  | /// `JSON`, and will automatically set `Content-Type: application/json` header. | 
|  | /// | 
|  | /// # Response example | 
|  | /// | 
|  | /// ``` | 
|  | /// 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 { | 
|  | ///     // ... | 
|  | ///     # unimplemented!() | 
|  | /// } | 
|  | /// | 
|  | /// let app = Router::new().route("/users/:id", get(get_user)); | 
|  | /// # async { | 
|  | /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); | 
|  | /// # }; | 
|  | /// ``` | 
|  | #[derive(Debug, Clone, Copy, Default)] | 
|  | #[cfg_attr(docsrs, doc(cfg(feature = "json")))] | 
|  | #[must_use] | 
|  | pub struct Json<T>(pub T); | 
|  |  | 
|  | #[async_trait] | 
|  | impl<T, S, B> FromRequest<S, B> for Json<T> | 
|  | where | 
|  | T: DeserializeOwned, | 
|  | B: HttpBody + Send + 'static, | 
|  | B::Data: Send, | 
|  | B::Error: Into<BoxError>, | 
|  | S: Send + Sync, | 
|  | { | 
|  | type Rejection = JsonRejection; | 
|  |  | 
|  | async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> { | 
|  | if json_content_type(req.headers()) { | 
|  | let bytes = Bytes::from_request(req, state).await?; | 
|  | let deserializer = &mut serde_json::Deserializer::from_slice(&bytes); | 
|  |  | 
|  | let value = match serde_path_to_error::deserialize(deserializer) { | 
|  | Ok(value) => value, | 
|  | Err(err) => { | 
|  | let rejection = match err.inner().classify() { | 
|  | serde_json::error::Category::Data => JsonDataError::from_err(err).into(), | 
|  | serde_json::error::Category::Syntax | serde_json::error::Category::Eof => { | 
|  | JsonSyntaxError::from_err(err).into() | 
|  | } | 
|  | serde_json::error::Category::Io => { | 
|  | if cfg!(debug_assertions) { | 
|  | // we don't use `serde_json::from_reader` and instead always buffer | 
|  | // bodies first, so we shouldn't encounter any IO errors | 
|  | unreachable!() | 
|  | } else { | 
|  | JsonSyntaxError::from_err(err).into() | 
|  | } | 
|  | } | 
|  | }; | 
|  | return Err(rejection); | 
|  | } | 
|  | }; | 
|  |  | 
|  | Ok(Json(value)) | 
|  | } else { | 
|  | Err(MissingJsonContentType.into()) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn json_content_type(headers: &HeaderMap) -> bool { | 
|  | let content_type = if let Some(content_type) = headers.get(header::CONTENT_TYPE) { | 
|  | content_type | 
|  | } else { | 
|  | return false; | 
|  | }; | 
|  |  | 
|  | let content_type = if let Ok(content_type) = content_type.to_str() { | 
|  | content_type | 
|  | } else { | 
|  | return false; | 
|  | }; | 
|  |  | 
|  | let mime = if let Ok(mime) = content_type.parse::<mime::Mime>() { | 
|  | mime | 
|  | } else { | 
|  | return false; | 
|  | }; | 
|  |  | 
|  | let is_json_content_type = mime.type_() == "application" | 
|  | && (mime.subtype() == "json" || mime.suffix().map_or(false, |name| name == "json")); | 
|  |  | 
|  | is_json_content_type | 
|  | } | 
|  |  | 
|  | axum_core::__impl_deref!(Json); | 
|  |  | 
|  | impl<T> From<T> for Json<T> { | 
|  | fn from(inner: T) -> Self { | 
|  | Self(inner) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<T> IntoResponse for Json<T> | 
|  | where | 
|  | T: Serialize, | 
|  | { | 
|  | fn into_response(self) -> Response { | 
|  | // Use a small initial capacity of 128 bytes like serde_json::to_vec | 
|  | // https://docs.rs/serde_json/1.0.82/src/serde_json/ser.rs.html#2189 | 
|  | let mut buf = BytesMut::with_capacity(128).writer(); | 
|  | match serde_json::to_writer(&mut buf, &self.0) { | 
|  | Ok(()) => ( | 
|  | [( | 
|  | header::CONTENT_TYPE, | 
|  | HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), | 
|  | )], | 
|  | buf.into_inner().freeze(), | 
|  | ) | 
|  | .into_response(), | 
|  | Err(err) => ( | 
|  | StatusCode::INTERNAL_SERVER_ERROR, | 
|  | [( | 
|  | header::CONTENT_TYPE, | 
|  | HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()), | 
|  | )], | 
|  | err.to_string(), | 
|  | ) | 
|  | .into_response(), | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #[cfg(test)] | 
|  | mod tests { | 
|  | use super::*; | 
|  | use crate::{routing::post, test_helpers::*, Router}; | 
|  | use serde::Deserialize; | 
|  | use serde_json::{json, Value}; | 
|  |  | 
|  | #[crate::test] | 
|  | async fn deserialize_body() { | 
|  | #[derive(Debug, Deserialize)] | 
|  | struct Input { | 
|  | foo: String, | 
|  | } | 
|  |  | 
|  | let app = Router::new().route("/", post(|input: Json<Input>| async { input.0.foo })); | 
|  |  | 
|  | let client = TestClient::new(app); | 
|  | let res = client.post("/").json(&json!({ "foo": "bar" })).send().await; | 
|  | let body = res.text().await; | 
|  |  | 
|  | assert_eq!(body, "bar"); | 
|  | } | 
|  |  | 
|  | #[crate::test] | 
|  | async fn consume_body_to_json_requires_json_content_type() { | 
|  | #[derive(Debug, Deserialize)] | 
|  | struct Input { | 
|  | foo: String, | 
|  | } | 
|  |  | 
|  | let app = Router::new().route("/", post(|input: Json<Input>| async { input.0.foo })); | 
|  |  | 
|  | let client = TestClient::new(app); | 
|  | let res = client.post("/").body(r#"{ "foo": "bar" }"#).send().await; | 
|  |  | 
|  | let status = res.status(); | 
|  |  | 
|  | assert_eq!(status, StatusCode::UNSUPPORTED_MEDIA_TYPE); | 
|  | } | 
|  |  | 
|  | #[crate::test] | 
|  | async fn json_content_types() { | 
|  | async fn valid_json_content_type(content_type: &str) -> bool { | 
|  | println!("testing {content_type:?}"); | 
|  |  | 
|  | let app = Router::new().route("/", post(|Json(_): Json<Value>| async {})); | 
|  |  | 
|  | let res = TestClient::new(app) | 
|  | .post("/") | 
|  | .header("content-type", content_type) | 
|  | .body("{}") | 
|  | .send() | 
|  | .await; | 
|  |  | 
|  | res.status() == StatusCode::OK | 
|  | } | 
|  |  | 
|  | assert!(valid_json_content_type("application/json").await); | 
|  | assert!(valid_json_content_type("application/json; charset=utf-8").await); | 
|  | assert!(valid_json_content_type("application/json;charset=utf-8").await); | 
|  | assert!(valid_json_content_type("application/cloudevents+json").await); | 
|  | assert!(!valid_json_content_type("text/json").await); | 
|  | } | 
|  |  | 
|  | #[crate::test] | 
|  | async fn invalid_json_syntax() { | 
|  | let app = Router::new().route("/", post(|_: Json<serde_json::Value>| async {})); | 
|  |  | 
|  | let client = TestClient::new(app); | 
|  | let res = client | 
|  | .post("/") | 
|  | .body("{") | 
|  | .header("content-type", "application/json") | 
|  | .send() | 
|  | .await; | 
|  |  | 
|  | assert_eq!(res.status(), StatusCode::BAD_REQUEST); | 
|  | } | 
|  |  | 
|  | #[derive(Deserialize)] | 
|  | struct Foo { | 
|  | #[allow(dead_code)] | 
|  | a: i32, | 
|  | #[allow(dead_code)] | 
|  | b: Vec<Bar>, | 
|  | } | 
|  |  | 
|  | #[derive(Deserialize)] | 
|  | struct Bar { | 
|  | #[allow(dead_code)] | 
|  | x: i32, | 
|  | #[allow(dead_code)] | 
|  | y: i32, | 
|  | } | 
|  |  | 
|  | #[crate::test] | 
|  | async fn invalid_json_data() { | 
|  | let app = Router::new().route("/", post(|_: Json<Foo>| async {})); | 
|  |  | 
|  | let client = TestClient::new(app); | 
|  | let res = client | 
|  | .post("/") | 
|  | .body("{\"a\": 1, \"b\": [{\"x\": 2}]}") | 
|  | .header("content-type", "application/json") | 
|  | .send() | 
|  | .await; | 
|  |  | 
|  | assert_eq!(res.status(), StatusCode::UNPROCESSABLE_ENTITY); | 
|  | let body_text = res.text().await; | 
|  | assert_eq!( | 
|  | body_text, | 
|  | "Failed to deserialize the JSON body into the target type: b[0]: missing field `y` at line 1 column 23" | 
|  | ); | 
|  | } | 
|  | } |