use axum::{ extract::{FromRequest, Form, Json, Query}, http::{self, Request, StatusCode}, response::{IntoResponse, Response}, RequestExt, }; use axum_typed_multipart::{TryFromMultipart, TypedMultipart}; #[derive(Debug, TryFromMultipart, Deserialize)] pub struct LoginForm { username: String, #[allow(dead_code)] password: String, } #[async_trait] impl FromRequest for LoginForm where Json: FromRequest<(), B>, Form: FromRequest<(), B>, TypedMultipart: FromRequest, B::Data: Into, B::Error: Into + Send + std::error::Error, B: Send + 'static + axum::body::HttpBody, S: Send { type Rejection = Response; async fn from_request(req: Request, _state: &S) -> Result { let headers = req.headers(); if let Some(mime) = headers.get(http::header::CONTENT_TYPE).and_then(|v| v.to_str().ok()) { if mime.starts_with("application/json") { let Json(login_form): Json = req.extract().await.map_err(IntoResponse::into_response)?; return Ok(login_form); } if mime.starts_with("application/x-www-form-urlencoded") { let Form(login_form) = req.extract().await.map_err(IntoResponse::into_response)?; return Ok(login_form); } if mime.starts_with("multipart/form-data") { let TypedMultipart(login_form): TypedMultipart = req.extract().await.map_err(IntoResponse::into_response)?; return Ok(login_form); } Err(StatusCode::UNSUPPORTED_MEDIA_TYPE.into_response()) } else { Err("No POST Content-Type".into_response()) } } } #[debug_handler] pub async fn route(form: LoginForm) -> String { format!("Welcome {}", form.username) }