Return a 404 when paring the route fails (#3860)

* return a 404 when paring the route fails

* add a playwright test for fullstack routing status codes

* Fix new playwright test

* document SSRError

* Make SSRError public and fix clippy

* Move the error display bound to the routable trait

* fix clippy

* return a more generic 404 message

* fix router tests
This commit is contained in:
Evan Almloff authored and GitHub committed 2025-03-14 00:51:44 -07:00
1 parent 7b7357037f
commit 09a4b5eb4e
18 files changed
+253 -46

No files matched your search

+1 -6
View File
@@ -1,7 +1,5 @@
use dioxus_lib::prelude::*;
use std::str::FromStr;
use crate::{
prelude::{provide_router_context, Outlet},
routable::Routable,
@@ -39,10 +37,7 @@ impl<R: Clone> PartialEq for RouterProps<R> {
}
/// A component that renders the current route.
pub fn Router<R: Routable + Clone>(props: RouterProps<R>) -> Element
where
<R as FromStr>::Err: std::fmt::Display,
{
pub fn Router<R: Routable + Clone>(props: RouterProps<R>) -> Element {
use crate::prelude::{outlet::OutletContext, RouterContext};
use_hook(|| {
+29 -11
View File
@@ -1,5 +1,7 @@
use std::{
collections::HashSet,
error::Error,
fmt::Display,
sync::{Arc, Mutex},
};
@@ -11,6 +13,19 @@ use crate::{
prelude::SiteMapSegment, routable::Routable, router_cfg::RouterConfig,
};
/// An error that is thrown when the router fails to parse a route
#[derive(Debug, Clone)]
pub struct ParseRouteError {
message: String,
}
impl Error for ParseRouteError {}
impl Display for ParseRouteError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.message.fmt(f)
}
}
/// This context is set in the root of the virtual dom if there is a router present.
#[derive(Clone, Copy)]
struct RootRouterContext(Signal<Option<RouterContext>>);
@@ -94,10 +109,7 @@ pub struct RouterContext {
}
impl RouterContext {
pub(crate) fn new<R: Routable + 'static>(cfg: RouterConfig<R>) -> Self
where
<R as std::str::FromStr>::Err: std::fmt::Display,
{
pub(crate) fn new<R: Routable + 'static>(cfg: RouterConfig<R>) -> Self {
let subscribers = Arc::new(Mutex::new(HashSet::new()));
let mapping = consume_child_route_mapping();
@@ -233,15 +245,21 @@ impl RouterContext {
let absolute_route = self.full_route_string();
// If this is a child route, map the absolute route to the child route before parsing
let mapping = consume_child_route_mapping::<R>();
match mapping.as_ref() {
let route = match mapping.as_ref() {
Some(mapping) => mapping
.parse_route_from_root_route(&absolute_route)
.unwrap_or_else(|| {
panic!("route's display implementation must be parsable by FromStr")
}),
None => R::from_str(&absolute_route).unwrap_or_else(|_| {
panic!("route's display implementation must be parsable by FromStr")
}),
.ok_or_else(|| "Failed to parse route".to_string()),
None => {
R::from_str(&absolute_route).map_err(|err| format!("Failed to parse route {err}"))
}
};
match route {
Ok(route) => route,
Err(err) => {
throw_error(ParseRouteError { message: err });
"/".parse().unwrap_or_else(|err| panic!("{err}"))
}
}
}
+1 -1
View File
@@ -39,7 +39,7 @@ mod contexts {
pub(crate) mod router;
pub use navigator::*;
pub(crate) use router::*;
pub use router::{root_router, GenericRouterContext, RouterContext};
pub use router::{root_router, GenericRouterContext, ParseRouteError, RouterContext};
}
mod router_cfg;
+1 -1
View File
@@ -592,7 +592,7 @@ type SiteMapFlattened<'a> = FlatMap<
note = "Routable should generally be derived using the `#[derive(Routable)]` macro."
)
)]
pub trait Routable: FromStr + Display + Clone + 'static {
pub trait Routable: FromStr<Err: Display> + Display + Clone + 'static {
/// The error that can occur when parsing a route.
const SITE_MAP: &'static [SiteMapSegment];
-1
View File
@@ -43,7 +43,6 @@ impl<R> Default for RouterConfig<R> {
impl<R> RouterConfig<R>
where
R: Routable,
<R as std::str::FromStr>::Err: std::fmt::Display,
{
/// A function to be called whenever the routing is updated.
///