lexa_framework/extract/
form.rs1use hyper::http;
12
13pub struct Form<F>(pub F);
18
19#[derive(Debug)]
24#[derive(thiserror::Error)]
25#[error("\n\t{}: {0}", std::any::type_name::<Self>())]
26pub enum MissingFormError {
27 FormRejection(#[from] axum::extract::rejection::FormRejection),
28 JsonRejection(#[from] axum::extract::rejection::JsonRejection),
29}
30
31#[axum::async_trait]
36impl<F, S, B> axum::extract::FromRequest<S, B> for Form<F>
37where
38 F: serde::de::DeserializeOwned,
39 S: Send + Sync,
40 B: hyper::body::HttpBody + Send + 'static,
41 B::Data: Send,
42 B::Error: Into<axum::BoxError>,
43{
44 type Rejection = MissingFormError;
45
46 async fn from_request(
47 req: axum::http::request::Request<B>,
48 state: &S,
49 ) -> Result<Self, Self::Rejection> {
50 let f = if json_content_type(req.headers()) {
51 let axum::extract::Json(form) =
52 axum::extract::Json::<F>::from_request(req, state).await?;
53 form
54 } else {
55 let axum::extract::Form(form) =
56 axum::extract::Form::<F>::from_request(req, state).await?;
57 form
58 };
59 Ok(Self(f))
60 }
61}
62
63impl axum::response::IntoResponse for MissingFormError {
64 fn into_response(self) -> axum::response::Response {
65 let err_status = http::StatusCode::INTERNAL_SERVER_ERROR;
66 let err_body = self.to_string();
67 (err_status, err_body).into_response()
68 }
69}
70
71fn json_content_type(headers: &hyper::HeaderMap) -> bool {
72 let content_type =
73 if let Some(content_type) = headers.get(hyper::header::CONTENT_TYPE) {
74 content_type
75 } else {
76 return false;
77 };
78
79 let content_type = if let Ok(content_type) = content_type.to_str() {
80 content_type
81 } else {
82 return false;
83 };
84
85 let mime = if let Ok(mime) = content_type.parse::<mime::Mime>() {
86 mime
87 } else {
88 return false;
89 };
90
91 let is_json_content_type = mime.type_() == "application"
92 && (mime.subtype() == "json"
93 || mime.suffix().map_or(false, |name| name == "json"));
94
95 is_json_content_type
96}