1use axum::{
2 Form,
3 body::Body,
4 extract::{
5 FromRequest,
6 rejection::{FormRejection, JsonRejection},
7 },
8 http::{Request, header},
9};
10use headers::ContentType;
11use mime::Mime;
12use serde::de::DeserializeOwned;
13
14use crate::WebError;
15
16pub struct JsonOrForm<T>(pub T);
17
18impl<S, T> FromRequest<S> for JsonOrForm<T>
19where
20 S: Send + Sync,
21 T: DeserializeOwned,
22{
23 type Rejection = WebError;
24
25 async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
26 let header_value = req
27 .headers()
28 .get(header::CONTENT_TYPE)
29 .ok_or(WebError::new_with_code(400, "'Content-Type' not found"))?;
30
31 let content_type: ContentType = header_value
32 .to_str()
33 .map_err(|ex| WebError::new_with_msg(ex.to_string()))?
34 .parse()
35 .map_err(|_ex| WebError::new_with_code(400, "'Content-Type' invalid"))?;
36
37 let m: Mime = content_type.into();
38
39 let res = if mime::APPLICATION_JSON == m {
40 let axum::Json(res) = axum::Json::<T>::from_request(req, state)
41 .await
42 .map_err(|ex: JsonRejection| WebError::new_with_code(400, ex.body_text()))?;
43 res
44 } else if mime::APPLICATION_WWW_FORM_URLENCODED == m {
45 let Form(res) = Form::<T>::from_request(req, state)
46 .await
47 .map_err(|ex: FormRejection| WebError::new_with_code(400, ex.body_text()))?;
48 res
49 } else {
50 return Err(WebError::new_with_code(400, "Extract incoming data from HttpRequest error."));
51 };
52 Ok(JsonOrForm(res))
53 }
54}