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

+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}"))
}
}
}