fusion_web/
extract.rs

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}