axum-handler-extract 0.1.0

axum handler extract
Documentation
use core::{future::Future, pin::Pin};
use std::net::SocketAddr;

use async_trait::async_trait;
use axum::{
    handler::Handler, http::Request as HttpRequest, response::Response as AxumResponse,
    routing::get, Router, Server,
};
use hyper::Body as HyperBody;

use axum_handler_extract::{matched_path::matched_path_from_request, path::path_from_request};

#[tokio::test]
async fn simple() -> Result<(), Box<dyn std::error::Error>> {
    //
    let listen_addr = SocketAddr::from(([127, 0, 0, 1], portpicker::pick_unused_port().unwrap()));
    println!("listen_addr {listen_addr:?}");

    //
    let server_task = tokio::task::spawn(async move {
        let app = Router::new().route("/path_params/:key", get(MyHandler));

        let server = Server::bind(&listen_addr).serve(app.into_make_service());

        server.await.expect("server error");
    });

    //
    tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;

    //
    let res = isahc::get_async(format!("http://{}{}", listen_addr, "/path_params/foo")).await?;
    assert!(res.status().is_success());
    assert_eq!(res.headers().get("x").unwrap(), "1");

    //
    server_task.abort();
    assert!(server_task.await.unwrap_err().is_cancelled());

    Ok(())
}

//
#[derive(Clone)]
struct MyHandler;

#[async_trait]
impl<S, B> Handler<(), S, B> for MyHandler
where
    S: Clone + 'static,
    B: Send + 'static,
{
    type Future = Pin<Box<dyn Future<Output = AxumResponse> + Send + 'static>>;

    fn call(self, req: HttpRequest<B>, _state: S) -> Self::Future {
        Box::pin(async move {
            assert_eq!(req.uri(), "/path_params/foo");

            let req = match path_from_request::<Vec<String>, B>(req).await {
                Ok((path, req)) => {
                    assert_eq!(path.unwrap().0, vec!["foo"]);

                    req
                }
                Err((err, _)) => {
                    panic!("{err}");
                }
            };

            match matched_path_from_request(req).await {
                Ok((matched_path, _req)) => {
                    assert_eq!(matched_path.unwrap().as_str(), "/path_params/:key");
                }
                Err((err, _)) => {
                    panic!("{err}");
                }
            }

            let body = HyperBody::empty();
            let mut res = AxumResponse::new(axum::body::boxed(body));
            res.headers_mut().insert("x", 1.into());

            res
        })
    }
}