1use core::{
4 convert::Infallible,
5 fmt,
6 marker::PhantomData,
7 ops::{Deref, DerefMut},
8};
9
10use serde::{de::Deserialize, ser::Serialize};
11use xitca_http::util::service::router::{PathGen, RouteGen, RouterMapErr};
12
13use crate::{
14 body::BodyStream,
15 bytes::{BufMutWriter, Bytes, BytesMut},
16 context::WebContext,
17 error::{Error, error_from_service, forward_blank_bad_request},
18 handler::{FromRequest, Responder},
19 http::{WebResponse, const_header_value::JSON, header::CONTENT_TYPE},
20 service::Service,
21};
22
23use super::{
24 body::Limit,
25 header::{self, HeaderRef},
26};
27
28pub const DEFAULT_LIMIT: usize = 1024 * 1024;
29
30#[derive(Clone)]
35pub struct Json<T, const LIMIT: usize = DEFAULT_LIMIT>(pub T);
36
37impl<T, const LIMIT: usize> fmt::Debug for Json<T, LIMIT>
38where
39 T: fmt::Debug,
40{
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 f.debug_struct("Json")
43 .field("value", &self.0)
44 .field("limit", &LIMIT)
45 .finish()
46 }
47}
48
49impl<T, const LIMIT: usize> Deref for Json<T, LIMIT> {
50 type Target = T;
51
52 fn deref(&self) -> &Self::Target {
53 &self.0
54 }
55}
56
57impl<T, const LIMIT: usize> DerefMut for Json<T, LIMIT> {
58 fn deref_mut(&mut self) -> &mut Self::Target {
59 &mut self.0
60 }
61}
62
63impl<'a, 'r, C, B, T, const LIMIT: usize> FromRequest<'a, WebContext<'r, C, B>> for Json<T, LIMIT>
64where
65 B: BodyStream + Default,
66 T: for<'de> Deserialize<'de>,
67{
68 type Type<'b> = Json<T, LIMIT>;
69 type Error = Error;
70
71 async fn from_request(ctx: &'a WebContext<'r, C, B>) -> Result<Self, Self::Error> {
72 HeaderRef::<'a, { header::CONTENT_TYPE }>::from_request(ctx).await?;
73 let (bytes, _) = <(BytesMut, Limit<LIMIT>)>::from_request(ctx).await?;
74 serde_json::from_slice(&bytes).map(Json).map_err(Into::into)
75 }
76}
77
78pub struct LazyJson<T, const LIMIT: usize = DEFAULT_LIMIT> {
111 bytes: Vec<u8>,
112 _json: PhantomData<T>,
113}
114
115impl<T, const LIMIT: usize> LazyJson<T, LIMIT> {
116 pub fn deserialize<'de>(&'de self) -> Result<T, Error>
117 where
118 T: Deserialize<'de>,
119 {
120 serde_json::from_slice(&self.bytes).map_err(Into::into)
121 }
122}
123
124impl<'a, 'r, C, B, T, const LIMIT: usize> FromRequest<'a, WebContext<'r, C, B>> for LazyJson<T, LIMIT>
125where
126 B: BodyStream + Default,
127 T: Deserialize<'static>,
128{
129 type Type<'b> = LazyJson<T, LIMIT>;
130 type Error = Error;
131
132 async fn from_request(ctx: &'a WebContext<'r, C, B>) -> Result<Self, Self::Error> {
133 HeaderRef::<'a, { header::CONTENT_TYPE }>::from_request(ctx).await?;
134 let (bytes, _) = <(Vec<u8>, Limit<LIMIT>)>::from_request(ctx).await?;
135 Ok(LazyJson {
136 bytes,
137 _json: PhantomData,
138 })
139 }
140}
141
142impl<'r, C, B, T> Responder<WebContext<'r, C, B>> for Json<T>
143where
144 T: Serialize,
145{
146 type Response = WebResponse;
147 type Error = Error;
148
149 #[inline]
150 async fn respond(self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
151 self._respond(|bytes| ctx.into_response(bytes))
152 }
153
154 #[inline]
155 fn map(self, res: Self::Response) -> Result<Self::Response, Self::Error> {
156 self._respond(|bytes| res.map(|_| bytes.into()))
157 }
158}
159
160impl<T> Json<T> {
161 fn _respond<F>(self, func: F) -> Result<WebResponse, Error>
162 where
163 T: Serialize,
164 F: FnOnce(Bytes) -> WebResponse,
165 {
166 let mut bytes = BytesMut::new();
167 serde_json::to_writer(BufMutWriter(&mut bytes), &self.0)?;
168 let mut res = func(bytes.freeze());
169 res.headers_mut().insert(CONTENT_TYPE, JSON);
170 Ok(res)
171 }
172}
173
174impl<'r, C, B> Responder<WebContext<'r, C, B>> for serde_json::Value {
175 type Response = WebResponse;
176 type Error = Error;
177
178 #[inline]
179 async fn respond(self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
180 Json(self).respond(ctx).await
181 }
182
183 #[inline]
184 fn map(self, res: Self::Response) -> Result<Self::Response, Self::Error> {
185 Responder::<WebContext<'r, C, B>>::map(Json(self), res)
186 }
187}
188
189error_from_service!(serde_json::Error);
190forward_blank_bad_request!(serde_json::Error);
191
192impl<T> PathGen for Json<T> {}
193
194impl<T> RouteGen for Json<T> {
195 type Route<R> = RouterMapErr<R>;
196
197 fn route_gen<R>(route: R) -> Self::Route<R> {
198 RouterMapErr(route)
199 }
200}
201
202impl<T> Service for Json<T>
203where
204 T: Clone,
205{
206 type Response = Self;
207 type Error = Infallible;
208
209 async fn call(&self, _: ()) -> Result<Self::Response, Self::Error> {
210 Ok(self.clone())
211 }
212}
213
214impl<'r, C, B, T> Service<WebContext<'r, C, B>> for Json<T>
215where
216 T: Serialize + Clone,
217{
218 type Response = WebResponse;
219 type Error = Error;
220
221 #[inline]
222 async fn call(&self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
223 self.clone().respond(ctx).await
224 }
225}
226
227#[cfg(test)]
228mod test {
229 use xitca_unsafe_collection::futures::NowOrPanic;
230
231 use crate::{
232 App,
233 handler::handler_service,
234 http::{WebRequest, header::CONTENT_LENGTH},
235 test::collect_string_body,
236 };
237
238 use super::*;
239
240 #[derive(serde::Deserialize, serde::Serialize, Clone)]
241 struct Gacha<'a> {
242 credit_card: &'a str,
243 }
244
245 #[test]
246 fn extract_lazy() {
247 let mut ctx = WebContext::new_test(&());
248 let mut ctx = ctx.as_web_ctx();
249
250 let body = serde_json::to_string(&Gacha {
251 credit_card: "declined",
252 })
253 .unwrap();
254
255 ctx.req_mut().headers_mut().insert(CONTENT_TYPE, JSON);
256 ctx.req_mut().headers_mut().insert(CONTENT_LENGTH, body.len().into());
257
258 *ctx.body_borrow_mut() = body.into();
259
260 async fn handler(lazy: LazyJson<Gacha<'_>>) -> &'static str {
261 let ga = lazy.deserialize().unwrap();
262 assert_eq!(ga.credit_card, "declined");
263 "bankruptcy"
264 }
265
266 let service = handler_service(handler).call(()).now_or_panic().unwrap();
267
268 let body = service.call(ctx).now_or_panic().unwrap().into_body();
269 let res = collect_string_body(body).now_or_panic().unwrap();
270
271 assert_eq!(res, "bankruptcy");
272 }
273
274 #[test]
275 fn service() {
276 let res = App::new()
277 .at("/", Json(Gacha { credit_card: "mom" }))
278 .finish()
279 .call(())
280 .now_or_panic()
281 .unwrap()
282 .call(WebRequest::default())
283 .now_or_panic()
284 .unwrap();
285 assert_eq!(res.status().as_u16(), 200);
286 }
287}