mirror of
https://github.com/tokio-rs/axum.git
synced 2025-01-05 18:27:07 +01:00
Improve error message for nest("/", _)
(#500)
This commit is contained in:
parent
fb8156f17c
commit
34942f3d70
2 changed files with 62 additions and 2 deletions
|
@ -66,6 +66,7 @@ pub struct Router<B = Body> {
|
||||||
routes: HashMap<RouteId, Route<B>>,
|
routes: HashMap<RouteId, Route<B>>,
|
||||||
node: Node,
|
node: Node,
|
||||||
fallback: Fallback<B>,
|
fallback: Fallback<B>,
|
||||||
|
nested_at_root: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Clone for Router<B> {
|
impl<B> Clone for Router<B> {
|
||||||
|
@ -74,6 +75,7 @@ impl<B> Clone for Router<B> {
|
||||||
routes: self.routes.clone(),
|
routes: self.routes.clone(),
|
||||||
node: self.node.clone(),
|
node: self.node.clone(),
|
||||||
fallback: self.fallback.clone(),
|
fallback: self.fallback.clone(),
|
||||||
|
nested_at_root: self.nested_at_root,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,6 +105,7 @@ where
|
||||||
routes: Default::default(),
|
routes: Default::default(),
|
||||||
node: Default::default(),
|
node: Default::default(),
|
||||||
fallback: Fallback::Default(Route::new(NotFound)),
|
fallback: Fallback::Default(Route::new(NotFound)),
|
||||||
|
nested_at_root: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +132,7 @@ where
|
||||||
let id = RouteId::next();
|
let id = RouteId::next();
|
||||||
|
|
||||||
if let Err(err) = self.node.insert(path, id) {
|
if let Err(err) = self.node.insert(path, id) {
|
||||||
panic!("Invalid route: {}", err);
|
self.panic_on_matchit_error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.routes.insert(id, Route::new(service));
|
self.routes.insert(id, Route::new(service));
|
||||||
|
@ -156,6 +159,10 @@ where
|
||||||
|
|
||||||
let prefix = path;
|
let prefix = path;
|
||||||
|
|
||||||
|
if path == "/" {
|
||||||
|
self.nested_at_root = true;
|
||||||
|
}
|
||||||
|
|
||||||
match try_downcast::<Router<B>, _>(svc) {
|
match try_downcast::<Router<B>, _>(svc) {
|
||||||
// if the user is nesting a `Router` we can implement nesting
|
// if the user is nesting a `Router` we can implement nesting
|
||||||
// by simplying copying all the routes and adding the prefix in
|
// by simplying copying all the routes and adding the prefix in
|
||||||
|
@ -166,6 +173,10 @@ where
|
||||||
node,
|
node,
|
||||||
// discard the fallback of the nested router
|
// discard the fallback of the nested router
|
||||||
fallback: _,
|
fallback: _,
|
||||||
|
// nesting a router that has something nested at root
|
||||||
|
// doesn't mean something is nested at root in _this_ router
|
||||||
|
// thus we don't need to propagate that
|
||||||
|
nested_at_root: _,
|
||||||
} = router;
|
} = router;
|
||||||
|
|
||||||
for (id, nested_path) in node.paths {
|
for (id, nested_path) in node.paths {
|
||||||
|
@ -201,10 +212,11 @@ where
|
||||||
routes,
|
routes,
|
||||||
node,
|
node,
|
||||||
fallback,
|
fallback,
|
||||||
|
nested_at_root,
|
||||||
} = other;
|
} = other;
|
||||||
|
|
||||||
if let Err(err) = self.node.merge(node) {
|
if let Err(err) = self.node.merge(node) {
|
||||||
panic!("Invalid route: {}", err);
|
self.panic_on_matchit_error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (id, route) in routes {
|
for (id, route) in routes {
|
||||||
|
@ -218,6 +230,8 @@ where
|
||||||
(Fallback::Custom(_), pick @ Fallback::Custom(_)) => pick,
|
(Fallback::Custom(_), pick @ Fallback::Custom(_)) => pick,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.nested_at_root = self.nested_at_root || nested_at_root;
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +267,7 @@ where
|
||||||
routes,
|
routes,
|
||||||
node: self.node,
|
node: self.node,
|
||||||
fallback,
|
fallback,
|
||||||
|
nested_at_root: self.nested_at_root,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,6 +301,7 @@ where
|
||||||
routes,
|
routes,
|
||||||
node: self.node,
|
node: self.node,
|
||||||
fallback: self.fallback,
|
fallback: self.fallback,
|
||||||
|
nested_at_root: self.nested_at_root,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,6 +396,17 @@ where
|
||||||
|
|
||||||
RouterFuture::from_oneshot(route.oneshot(req))
|
RouterFuture::from_oneshot(route.oneshot(req))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn panic_on_matchit_error(&self, err: matchit::InsertError) {
|
||||||
|
if self.nested_at_root {
|
||||||
|
panic!(
|
||||||
|
"Invalid route: {}. Note that `nest(\"/\", _)` conflicts with all routes. Use `Router::fallback` instead",
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("Invalid route: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Service<Request<B>> for Router<B>
|
impl<B> Service<Request<B>> for Router<B>
|
||||||
|
|
|
@ -504,3 +504,36 @@ async fn route_layer() {
|
||||||
let res = client.post("/foo").send().await;
|
let res = client.post("/foo").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
|
assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[should_panic(
|
||||||
|
expected = "Invalid route: insertion failed due to conflict with previously registered route: /foo"
|
||||||
|
)]
|
||||||
|
async fn conflicting_route() {
|
||||||
|
let app = Router::new()
|
||||||
|
.route("/foo", get(|| async {}))
|
||||||
|
.route("/foo", get(|| async {}));
|
||||||
|
TestClient::new(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[should_panic(
|
||||||
|
expected = "Invalid route: insertion failed due to conflict with previously registered route: /*axum_nest. Note that `nest(\"/\", _)` conflicts with all routes. Use `Router::fallback` instead"
|
||||||
|
)]
|
||||||
|
async fn good_error_message_if_using_nest_root() {
|
||||||
|
let app = Router::new()
|
||||||
|
.nest("/", get(|| async {}))
|
||||||
|
.route("/", get(|| async {}));
|
||||||
|
TestClient::new(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[should_panic(
|
||||||
|
expected = "Invalid route: insertion failed due to conflict with previously registered route: /*axum_nest. Note that `nest(\"/\", _)` conflicts with all routes. Use `Router::fallback` instead"
|
||||||
|
)]
|
||||||
|
async fn good_error_message_if_using_nest_root_when_merging() {
|
||||||
|
let one = Router::new().nest("/", get(|| async {}));
|
||||||
|
let two = Router::new().route("/", get(|| async {}));
|
||||||
|
let app = one.merge(two);
|
||||||
|
TestClient::new(app);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue