axum_body_split/
lib.rs

1use axum::{
2    body::Bytes,
3    extract::FromRequest,
4    response::{IntoResponse, Response},
5};
6use std::{fmt::Debug, marker::PhantomData};
7
8pub struct SplitBody<T1, T2, State>(pub T1, pub T2, pub PhantomData<State>)
9where
10    T1: FromRequest<State> + Send + Sync + Send + Sync,
11    T2: FromRequest<State> + Send + Sync + Send + Sync,
12    State: Send + Sync;
13
14impl<T1, T2, S> FromRequest<S> for SplitBody<T1, T2, S>
15where
16    T1: FromRequest<S> + Send + Sync,
17    T2: FromRequest<S> + Send + Sync,
18    T1::Rejection: Debug + Send + Sync,
19    T2::Rejection: Debug + Send + Sync,
20    S: Send + Sync,
21{
22    type Rejection = Response;
23    async fn from_request(req: axum::extract::Request, state: &S) -> Result<Self, Self::Rejection> {
24        // async move {
25
26        fn make_builder(req: &axum::extract::Request) -> axum::http::request::Builder {
27            let mut builder = axum::extract::Request::builder();
28            if let Some(headers) = builder.headers_mut() {
29                *headers = req.headers().clone();
30            }
31            builder.uri(req.uri().clone()).version(req.version())
32        }
33
34        let builders = (make_builder(&req), make_builder(&req));
35
36        let body = Bytes::from_request(req, state)
37            .await
38            .map_err(|err| err.into_response())?;
39
40        let builders = (
41            builders
42                .0
43                .body(axum::body::Body::new(http_body_util::Full::new(
44                    body.clone(),
45                )))
46                // can unwrap, because this req is a clone of the one before
47                .unwrap(),
48            builders
49                .1
50                .body(axum::body::Body::new(http_body_util::Full::new(body)))
51                // can unwrap, because this req is a clone of the one before
52                .unwrap(),
53        );
54        // axum::extract::Json;
55        Ok(SplitBody(
56            T1::from_request(builders.0, state)
57                .await
58                .map_err(|err| err.into_response())?,
59            T2::from_request(builders.1, state)
60                .await
61                .map_err(|err| err.into_response())?,
62            PhantomData,
63        ))
64    }
65}