From 6c3381ce52c9f8e6c8f9999477965e34743b7129 Mon Sep 17 00:00:00 2001 From: Ben Wishovich Date: Mon, 24 Apr 2023 17:08:28 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20add=20From=20for=20RequestParts=20into?= =?UTF-8?q?=20Parts=20for=20Axum=20and=20add=20an=20option=20to=20ge?= =?UTF-8?q?=E2=80=A6=20(#931)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/ssr_modes_axum/src/main.rs | 17 ++++++++---- integrations/actix/src/lib.rs | 20 +++++++++++++- integrations/axum/src/lib.rs | 41 +++++++++++++++++++++++++++-- integrations/viz/src/lib.rs | 18 ++++++++++++- 4 files changed, 87 insertions(+), 9 deletions(-) diff --git a/examples/ssr_modes_axum/src/main.rs b/examples/ssr_modes_axum/src/main.rs index 9f9f1e936..ffd60510f 100644 --- a/examples/ssr_modes_axum/src/main.rs +++ b/examples/ssr_modes_axum/src/main.rs @@ -1,12 +1,15 @@ #[cfg(feature = "ssr")] #[tokio::main] -async fn main(){ +async fn main() { + use axum::{ + extract::{Extension, Path}, + routing::{get, post}, + Router, + }; use leptos::*; use leptos_axum::{generate_route_list, LeptosRoutes}; - use axum::{extract::{Extension, Path}, Router, routing::{get, post}}; + use ssr_modes_axum::{app::*, fallback::file_and_error_handler}; use std::sync::Arc; - use ssr_modes_axum::fallback::file_and_error_handler; - use ssr_modes_axum::app::*; let conf = get_configuration(None).await.unwrap(); let addr = conf.leptos_options.site_addr; @@ -19,7 +22,11 @@ async fn main(){ let app = Router::new() .route("/api/*fn_name", post(leptos_axum::handle_server_fns)) - .leptos_routes(leptos_options.clone(), routes, |cx| view! { cx, }) + .leptos_routes( + leptos_options.clone(), + routes, + |cx| view! { cx, }, + ) .fallback(file_and_error_handler) .layer(Extension(Arc::new(leptos_options))); diff --git a/integrations/actix/src/lib.rs b/integrations/actix/src/lib.rs index 6271ad9e6..600263528 100644 --- a/integrations/actix/src/lib.rs +++ b/integrations/actix/src/lib.rs @@ -905,6 +905,20 @@ async fn render_app_async_helper( pub fn generate_route_list( app_fn: impl FnOnce(leptos::Scope) -> IV + 'static, ) -> Vec +where + IV: IntoView + 'static, +{ + generate_route_list_with_exclusions(app_fn, None) +} + +/// Generates a list of all routes defined in Leptos's Router in your app. We can then use this to automatically +/// create routes in Actix's App without having to use wildcard matching or fallbacks. Takes in your root app Element +/// as an argument so it can walk you app tree. This version is tailored to generated Actix compatible paths. Adding excluded_routes +/// to this function will stop `.leptos_routes()` from generating a route for it, allowing a custom handler. These need to be in Actix path format +pub fn generate_route_list_with_exclusions( + app_fn: impl FnOnce(leptos::Scope) -> IV + 'static, + excluded_routes: Option>, +) -> Vec where IV: IntoView + 'static, { @@ -932,7 +946,7 @@ where // Match `:some_word` but only capture `some_word` in the groups to replace with `{some_word}` let capture_re = Regex::new(r":((?:[^.,/]+)+)[^/]?").unwrap(); - let routes = routes + let mut routes = routes .into_iter() .map(|listing| { let path = wildcard_re @@ -946,6 +960,10 @@ where if routes.is_empty() { vec![RouteListing::new("/", Default::default(), [Method::Get])] } else { + // Routes to exclude from auto generation + if let Some(excluded_routes) = excluded_routes { + routes.retain(|p| !excluded_routes.iter().any(|e| e == p.path())) + } routes } } diff --git a/integrations/axum/src/lib.rs b/integrations/axum/src/lib.rs index 2caaae6d5..945045a45 100644 --- a/integrations/axum/src/lib.rs +++ b/integrations/axum/src/lib.rs @@ -19,7 +19,10 @@ use futures::{ channel::mpsc::{Receiver, Sender}, Future, SinkExt, Stream, StreamExt, }; -use http::{header, method::Method, uri::Uri, version::Version, Response}; +use http::{ + header, method::Method, request::Parts, uri::Uri, version::Version, + Response, +}; use hyper::body; use leptos::{ leptos_server::{server_fn_by_path, Payload}, @@ -46,6 +49,21 @@ pub struct RequestParts { pub headers: HeaderMap, pub body: Bytes, } + +/// Convert http::Parts to RequestParts(and vice versa). Body and Extensions will +/// be lost in the conversion +impl From for RequestParts { + fn from(parts: Parts) -> Self { + Self { + version: parts.version, + method: parts.method, + uri: parts.uri, + headers: parts.headers, + body: Bytes::default(), + } + } +} + /// This struct lets you define headers and override the status of the Response from an Element or a Server Function /// Typically contained inside of a ResponseOptions. Setting this is useful for cookies and custom responses. #[derive(Debug, Clone, Default)] @@ -1003,6 +1021,21 @@ where pub async fn generate_route_list( app_fn: impl FnOnce(Scope) -> IV + 'static, ) -> Vec +where + IV: IntoView + 'static, +{ + generate_route_list_with_exclusions(app_fn, None).await +} + +/// Generates a list of all routes defined in Leptos's Router in your app. We can then use this to automatically +/// create routes in Axum's Router without having to use wildcard matching or fallbacks. Takes in your root app Element +/// as an argument so it can walk you app tree. This version is tailored to generate Axum compatible paths. Adding excluded_routes +/// to this function will stop `.leptos_routes()` from generating a route for it, allowing a custom handler. These need to be in Axum path format +#[tracing::instrument(level = "trace", fields(error), skip_all)] +pub async fn generate_route_list_with_exclusions( + app_fn: impl FnOnce(Scope) -> IV + 'static, + excluded_routes: Option>, +) -> Vec where IV: IntoView + 'static, { @@ -1029,7 +1062,7 @@ where let routes = routes.0.read().to_owned(); // Axum's Router defines Root routes as "/" not "" - let routes = routes + let mut routes = routes .into_iter() .map(|listing| { let path = listing.path(); @@ -1052,6 +1085,10 @@ where [leptos_router::Method::Get], )] } else { + // Routes to exclude from auto generation + if let Some(excluded_routes) = excluded_routes { + routes.retain(|p| !excluded_routes.iter().any(|e| e == p.path())) + } routes } } diff --git a/integrations/viz/src/lib.rs b/integrations/viz/src/lib.rs index 75f5ddd4b..3b1324fa5 100644 --- a/integrations/viz/src/lib.rs +++ b/integrations/viz/src/lib.rs @@ -947,6 +947,19 @@ where pub async fn generate_route_list( app_fn: impl FnOnce(Scope) -> IV + 'static, ) -> Vec +where + IV: IntoView + 'static, +{ + generate_route_list_with_exclusions(app_fn, None).await +} + +/// Generates a list of all routes defined in Leptos's Router in your app. We can then use this to automatically +/// create routes in Viz's Router without having to use wildcard matching or fallbacks. Takes in your root app Element +/// as an argument so it can walk you app tree. This version is tailored to generate Viz compatible paths. +pub async fn generate_route_list_with_exclusions( + app_fn: impl FnOnce(Scope) -> IV + 'static, + excluded_routes: Option>, +) -> Vec where IV: IntoView + 'static, { @@ -973,7 +986,7 @@ where let routes = routes.0.read().to_owned(); // Viz's Router defines Root routes as "/" not "" - let routes = routes + let mut routes = routes .into_iter() .map(|listing| { let path = listing.path(); @@ -996,6 +1009,9 @@ where [leptos_router::Method::Get], )] } else { + if let Some(excluded_routes) = excluded_routes { + routes.retain(|p| !excluded_routes.iter().any(|e| e == p.path())) + } routes } }