Repository: leptos-rs/leptos
File: server_fn/src/middleware/mod.rs (Rust)

Code before:
#[cfg(feature = "axum-no-default")]
mod axum {
    use super::{BoxedService, ServerFnErrorSerializer, Service};
    use crate::{error::ServerFnErrorErr, response::Res, ServerFnError};
    use axum::body::Body;
    use http::{Request, Response};
    use std::{future::Future, pin::Pin};

    impl<S> super::Service<Request<Body>, Response<Body>> for S
    where
        S: tower::Service<Request<Body>, Response = Response<Body>>,
        S::Future: Send + 'static,
        S::Error: std::fmt::Display + Send + 'static,
    {
        fn run(
            &mut self,
            req: Request<Body>,
            err_ser: ServerFnErrorSerializer,
        ) -> Pin<Box<dyn Future<Output = Response<Body>> + Send>> {
            let path = req.uri().path().to_string();
            let inner = self.call(req);
            Box::pin(async move {
                inner.await.unwrap_or_else(|e| {
                    let err = err_ser(ServerFnErrorErr::MiddlewareError(
                        e.to_string(),
                    ));
                    Response::<Body>::error_response(&path, err)
                })
            })
        }
    }

    impl tower::Service<Request<Body>>
        for BoxedService<Request<Body>, Response<Body>>
    {
        type Response = Response<Body>;
        type Error = ServerFnError;
        type Future = Pin<
            Box<
                dyn std::future::Future<
                        Output = Result<Self::Response, Self::Error>,
                    > + Send,
            >,
        >;

        fn poll_ready(
            &mut self,
            _cx: &mut std::task::Context<'_>,
        ) -> std::task::Poll<Result<(), Self::Error>> {
            Ok(()).into()
        }

Review comment (bug):
This isn't really wrong or anything, the previous version also tries to handle errors as strings, I find myself wondering if this is right. Never mind me, just thinking in comments

Code after:
    use axum::body::Body;
    use bytes::Bytes;
    use http::{Request, Response};
    use std::{future::Future, pin::Pin};

    impl<S> super::Service<Request<Body>, Response<Body>> for S
    where
        S: tower::Service<Request<Body>, Response = Response<Body>>,
        S::Future: Send + 'static,
        S::Error: std::fmt::Display + Send + 'static,
    {
        fn run(
            &mut self,
            req: Request<Body>,
            ser: fn(ServerFnErrorErr) -> Bytes,
        ) -> Pin<Box<dyn Future<Output = Response<Body>> + Send>> {
            let path = req.uri().path().to_string();
            let inner = self.call(req);
            Box::pin(async move {
                inner.await.unwrap_or_else(|e| {
                    // TODO: This does not set the Content-Type on the response. Doing so will
                    //  require a breaking change in order to get the correct encoding from the
                    //  error's `FromServerFnError::Encoder::CONTENT_TYPE` impl.
                    //  Note: This only applies to middleware errors.
                    let err =
                        ser(ServerFnErrorErr::MiddlewareError(e.to_string()));
                    Response::<Body>::error_response(&path, err)
                })
            })
        }
    }

    impl tower::Service<Request<Body>>
        for BoxedService<Request<Body>, Response<Body>>
    {
        type Response = Response<Body>;
        type Error = ServerFnError;
        type Future = Pin<
            Box<
                dyn std::future::Future<
                        Output = Result<Self::Response, Self::Error>,
                    > + Send,
            >,
        >;

        fn poll_ready(
            &mut self,
            _cx: &mut std::task::Context<'_>,
        ) -> std::task::Poll<Result<(), Self::Error>> {
            Ok(()).into()
        }