1 use crate::{
2     body::{Bytes, HttpBody},
3     extract::{rejection::*, FromRequest},
4     BoxError,
5 };
6 use async_trait::async_trait;
7 use axum_core::response::{IntoResponse, Response};
8 use bytes::{BufMut, BytesMut};
9 use http::{
10     header::{self, HeaderMap, HeaderValue},
11     Request, StatusCode,
12 };
13 use serde::{de::DeserializeOwned, Serialize};
14 
15 /// JSON Extractor / Response.
16 ///
17 /// When used as an extractor, it can deserialize request bodies into some type that
18 /// implements [`serde::Deserialize`]. The request will be rejected (and a [`JsonRejection`] will
19 /// be returned) if:
20 ///
21 /// - The request doesn't have a `Content-Type: application/json` (or similar) header.
22 /// - The body doesn't contain syntactically valid JSON.
23 /// - The body contains syntactically valid JSON but it couldn't be deserialized into the target
24 /// type.
25 /// - Buffering the request body fails.
26 ///
27 /// ⚠️ Since parsing JSON requires consuming the request body, the `Json` extractor must be
28 /// *last* if there are multiple extractors in a handler.
29 /// See ["the order of extractors"][order-of-extractors]
30 ///
31 /// [order-of-extractors]: crate::extract#the-order-of-extractors
32 ///
33 /// See [`JsonRejection`] for more details.
34 ///
35 /// # Extractor example
36 ///
37 /// ```rust,no_run
38 /// use axum::{
39 ///     extract,
40 ///     routing::post,
41 ///     Router,
42 /// };
43 /// use serde::Deserialize;
44 ///
45 /// #[derive(Deserialize)]
46 /// struct CreateUser {
47 ///     email: String,
48 ///     password: String,
49 /// }
50 ///
51 /// async fn create_user(extract::Json(payload): extract::Json<CreateUser>) {
52 ///     // payload is a `CreateUser`
53 /// }
54 ///
55 /// let app = Router::new().route("/users", post(create_user));
56 /// # async {
57 /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
58 /// # };
59 /// ```
60 ///
61 /// When used as a response, it can serialize any type that implements [`serde::Serialize`] to
62 /// `JSON`, and will automatically set `Content-Type: application/json` header.
63 ///
64 /// # Response example
65 ///
66 /// ```
67 /// use axum::{
68 ///     extract::Path,
69 ///     routing::get,
70 ///     Router,
71 ///     Json,
72 /// };
73 /// use serde::Serialize;
74 /// use uuid::Uuid;
75 ///
76 /// #[derive(Serialize)]
77 /// struct User {
78 ///     id: Uuid,
79 ///     username: String,
80 /// }
81 ///
82 /// async fn get_user(Path(user_id) : Path<Uuid>) -> Json<User> {
83 ///     let user = find_user(user_id).await;
84 ///     Json(user)
85 /// }
86 ///
87 /// async fn find_user(user_id: Uuid) -> User {
88 ///     // ...
89 ///     # unimplemented!()
90 /// }
91 ///
92 /// let app = Router::new().route("/users/:id", get(get_user));
93 /// # async {
94 /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
95 /// # };
96 /// ```
97 #[derive(Debug, Clone, Copy, Default)]
98 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
99 #[must_use]
100 pub struct Json<T>(pub T);
101 
102 #[async_trait]
103 impl<T, S, B> FromRequest<S, B> for Json<T>
104 where
105     T: DeserializeOwned,
106     B: HttpBody + Send + 'static,
107     B::Data: Send,
108     B::Error: Into<BoxError>,
109     S: Send + Sync,
110 {
111     type Rejection = JsonRejection;
112 
from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection>113     async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
114         if json_content_type(req.headers()) {
115             let bytes = Bytes::from_request(req, state).await?;
116             let deserializer = &mut serde_json::Deserializer::from_slice(&bytes);
117 
118             let value = match serde_path_to_error::deserialize(deserializer) {
119                 Ok(value) => value,
120                 Err(err) => {
121                     let rejection = match err.inner().classify() {
122                         serde_json::error::Category::Data => JsonDataError::from_err(err).into(),
123                         serde_json::error::Category::Syntax | serde_json::error::Category::Eof => {
124                             JsonSyntaxError::from_err(err).into()
125                         }
126                         serde_json::error::Category::Io => {
127                             if cfg!(debug_assertions) {
128                                 // we don't use `serde_json::from_reader` and instead always buffer
129                                 // bodies first, so we shouldn't encounter any IO errors
130                                 unreachable!()
131                             } else {
132                                 JsonSyntaxError::from_err(err).into()
133                             }
134                         }
135                     };
136                     return Err(rejection);
137                 }
138             };
139 
140             Ok(Json(value))
141         } else {
142             Err(MissingJsonContentType.into())
143         }
144     }
145 }
146 
json_content_type(headers: &HeaderMap) -> bool147 fn json_content_type(headers: &HeaderMap) -> bool {
148     let content_type = if let Some(content_type) = headers.get(header::CONTENT_TYPE) {
149         content_type
150     } else {
151         return false;
152     };
153 
154     let content_type = if let Ok(content_type) = content_type.to_str() {
155         content_type
156     } else {
157         return false;
158     };
159 
160     let mime = if let Ok(mime) = content_type.parse::<mime::Mime>() {
161         mime
162     } else {
163         return false;
164     };
165 
166     let is_json_content_type = mime.type_() == "application"
167         && (mime.subtype() == "json" || mime.suffix().map_or(false, |name| name == "json"));
168 
169     is_json_content_type
170 }
171 
172 axum_core::__impl_deref!(Json);
173 
174 impl<T> From<T> for Json<T> {
from(inner: T) -> Self175     fn from(inner: T) -> Self {
176         Self(inner)
177     }
178 }
179 
180 impl<T> IntoResponse for Json<T>
181 where
182     T: Serialize,
183 {
into_response(self) -> Response184     fn into_response(self) -> Response {
185         // Use a small initial capacity of 128 bytes like serde_json::to_vec
186         // https://docs.rs/serde_json/1.0.82/src/serde_json/ser.rs.html#2189
187         let mut buf = BytesMut::with_capacity(128).writer();
188         match serde_json::to_writer(&mut buf, &self.0) {
189             Ok(()) => (
190                 [(
191                     header::CONTENT_TYPE,
192                     HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
193                 )],
194                 buf.into_inner().freeze(),
195             )
196                 .into_response(),
197             Err(err) => (
198                 StatusCode::INTERNAL_SERVER_ERROR,
199                 [(
200                     header::CONTENT_TYPE,
201                     HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
202                 )],
203                 err.to_string(),
204             )
205                 .into_response(),
206         }
207     }
208 }
209 
210 #[cfg(test)]
211 mod tests {
212     use super::*;
213     use crate::{routing::post, test_helpers::*, Router};
214     use serde::Deserialize;
215     use serde_json::{json, Value};
216 
217     #[crate::test]
deserialize_body()218     async fn deserialize_body() {
219         #[derive(Debug, Deserialize)]
220         struct Input {
221             foo: String,
222         }
223 
224         let app = Router::new().route("/", post(|input: Json<Input>| async { input.0.foo }));
225 
226         let client = TestClient::new(app);
227         let res = client.post("/").json(&json!({ "foo": "bar" })).send().await;
228         let body = res.text().await;
229 
230         assert_eq!(body, "bar");
231     }
232 
233     #[crate::test]
consume_body_to_json_requires_json_content_type()234     async fn consume_body_to_json_requires_json_content_type() {
235         #[derive(Debug, Deserialize)]
236         struct Input {
237             foo: String,
238         }
239 
240         let app = Router::new().route("/", post(|input: Json<Input>| async { input.0.foo }));
241 
242         let client = TestClient::new(app);
243         let res = client.post("/").body(r#"{ "foo": "bar" }"#).send().await;
244 
245         let status = res.status();
246 
247         assert_eq!(status, StatusCode::UNSUPPORTED_MEDIA_TYPE);
248     }
249 
250     #[crate::test]
json_content_types()251     async fn json_content_types() {
252         async fn valid_json_content_type(content_type: &str) -> bool {
253             println!("testing {content_type:?}");
254 
255             let app = Router::new().route("/", post(|Json(_): Json<Value>| async {}));
256 
257             let res = TestClient::new(app)
258                 .post("/")
259                 .header("content-type", content_type)
260                 .body("{}")
261                 .send()
262                 .await;
263 
264             res.status() == StatusCode::OK
265         }
266 
267         assert!(valid_json_content_type("application/json").await);
268         assert!(valid_json_content_type("application/json; charset=utf-8").await);
269         assert!(valid_json_content_type("application/json;charset=utf-8").await);
270         assert!(valid_json_content_type("application/cloudevents+json").await);
271         assert!(!valid_json_content_type("text/json").await);
272     }
273 
274     #[crate::test]
invalid_json_syntax()275     async fn invalid_json_syntax() {
276         let app = Router::new().route("/", post(|_: Json<serde_json::Value>| async {}));
277 
278         let client = TestClient::new(app);
279         let res = client
280             .post("/")
281             .body("{")
282             .header("content-type", "application/json")
283             .send()
284             .await;
285 
286         assert_eq!(res.status(), StatusCode::BAD_REQUEST);
287     }
288 
289     #[derive(Deserialize)]
290     struct Foo {
291         #[allow(dead_code)]
292         a: i32,
293         #[allow(dead_code)]
294         b: Vec<Bar>,
295     }
296 
297     #[derive(Deserialize)]
298     struct Bar {
299         #[allow(dead_code)]
300         x: i32,
301         #[allow(dead_code)]
302         y: i32,
303     }
304 
305     #[crate::test]
invalid_json_data()306     async fn invalid_json_data() {
307         let app = Router::new().route("/", post(|_: Json<Foo>| async {}));
308 
309         let client = TestClient::new(app);
310         let res = client
311             .post("/")
312             .body("{\"a\": 1, \"b\": [{\"x\": 2}]}")
313             .header("content-type", "application/json")
314             .send()
315             .await;
316 
317         assert_eq!(res.status(), StatusCode::UNPROCESSABLE_ENTITY);
318         let body_text = res.text().await;
319         assert_eq!(
320             body_text,
321             "Failed to deserialize the JSON body into the target type: b[0]: missing field `y` at line 1 column 23"
322         );
323     }
324 }
325