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