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}