rama_http/service/web/endpoint/response/
json.rs

1use super::IntoResponse;
2use crate::headers::ContentType;
3use crate::{Body, Response, dep::http::StatusCode};
4use bytes::{BufMut, BytesMut};
5use rama_core::error::OpaqueError;
6use rama_utils::macros::impl_deref;
7use serde::Serialize;
8use std::fmt;
9
10use super::Headers;
11
12/// Wrapper used to create Json Http [`Response`]s,
13/// as well as to extract Json from Http [`Request`] bodies.
14///
15/// [`Request`]: crate::Request
16/// [`Response`]: crate::Response
17///
18/// # Examples
19///
20/// ## Creating a Json Response
21///
22/// ```
23/// use serde_json::json;
24/// use rama_http::service::web::response::{IntoResponse, Json};
25///
26/// async fn handler() -> impl IntoResponse {
27///     Json(json!({
28///         "name": "john",
29///         "age": 30,
30///         "is_student": false
31///     }))
32/// }
33/// ```
34///
35/// ## Extracting Json from a Request
36///
37/// ```
38/// use serde_json::json;
39/// use rama_http::service::web::response::Json;
40///
41/// #[derive(Debug, serde::Deserialize)]
42/// struct Input {
43///     name: String,
44///     age: u8,
45///     alive: Option<bool>,
46/// }
47///
48/// # fn bury(name: impl AsRef<str>) {}
49///
50/// async fn handler(Json(input): Json<Input>) {
51///     if !input.alive.unwrap_or_default() {
52///         bury(&input.name);
53///     }
54/// }
55/// ```
56pub struct Json<T>(pub T);
57
58impl<T: fmt::Debug> fmt::Debug for Json<T> {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        f.debug_tuple("Json").field(&self.0).finish()
61    }
62}
63
64impl<T: Clone> Clone for Json<T> {
65    fn clone(&self) -> Self {
66        Self(self.0.clone())
67    }
68}
69
70impl_deref!(Json);
71
72impl<T> From<T> for Json<T> {
73    fn from(inner: T) -> Self {
74        Self(inner)
75    }
76}
77
78impl<T> IntoResponse for Json<T>
79where
80    T: Serialize,
81{
82    fn into_response(self) -> Response {
83        // Extracted into separate fn so it's only compiled once for all T.
84        fn make_respone(buf: BytesMut, ser_result: serde_json::Result<()>) -> Response {
85            match ser_result {
86                Ok(()) => (Headers::single(ContentType::json()), buf.freeze()).into_response(),
87                Err(err) => (
88                    StatusCode::INTERNAL_SERVER_ERROR,
89                    Headers::single(ContentType::text_utf8()),
90                    err.to_string(),
91                )
92                    .into_response(),
93            }
94        }
95        // Use a small initial capacity of 128 bytes like serde_json::to_vec
96        // https://docs.rs/serde_json/1.0.82/src/serde_json/ser.rs.html#2189
97        let mut buf = BytesMut::with_capacity(128).writer();
98        let res = serde_json::to_writer(&mut buf, &self.0);
99        make_respone(buf.into_inner(), res)
100    }
101}
102
103impl<T> TryInto<Body> for Json<T>
104where
105    T: Serialize,
106{
107    type Error = OpaqueError;
108
109    fn try_into(self) -> Result<Body, Self::Error> {
110        // Use a small initial capacity of 128 bytes like serde_json::to_vec
111        // https://docs.rs/serde_json/1.0.82/src/serde_json/ser.rs.html#2189
112        let mut buf = BytesMut::with_capacity(128).writer();
113        match serde_json::to_writer(&mut buf, &self.0) {
114            Ok(()) => Ok(buf.into_inner().freeze().into()),
115            Err(err) => Err(OpaqueError::from_std(err)),
116        }
117    }
118}