Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Router::nest to flatten the routes #1711

Merged
merged 13 commits into from Apr 11, 2023
5 changes: 5 additions & 0 deletions axum/CHANGELOG.md
Expand Up @@ -7,8 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

# Unreleased

- **fixed:** Fixed performance regression with `Router::nest` introduced in
0.6.0. `nest` now flattens the routes which performs better ([#1711])
- **fixed:** Extracting `MatchedPath` in nested handlers now gives the full
matched path, including the nested path ([#1711])
- **added:** Implement `Deref` and `DerefMut` for built-in extractors ([#1922])

[#1711]: https://github.com/tokio-rs/axum/pull/1711
[#1922]: https://github.com/tokio-rs/axum/pull/1922

# 0.6.12 (22. March, 2023)
Expand Down
19 changes: 0 additions & 19 deletions axum/src/boxed.rs
Expand Up @@ -28,25 +28,6 @@ where
into_route: |handler, state| Route::new(Handler::with_state(handler, state)),
}))
}

pub(crate) fn from_router(router: Router<S, B>) -> Self
where
B: HttpBody + Send + 'static,
S: Clone + Send + Sync + 'static,
{
Self(Box::new(MakeErasedRouter {
router,
into_route: |router, state| Route::new(router.with_state(state)),
}))
}

pub(crate) fn call_with_state(
self,
request: Request<B>,
state: S,
) -> RouteFuture<B, Infallible> {
self.0.call_with_state(request, state)
}
}

impl<S, B, E> BoxedIntoRoute<S, B, E> {
Expand Down
39 changes: 38 additions & 1 deletion axum/src/extract/matched_path.rs
Expand Up @@ -235,6 +235,26 @@ mod tests {
req
}

let app = Router::new()
.nest_service("/:a", Router::new().route("/:b", get(|| async move {})))
.layer(map_request(extract_matched_path));

let client = TestClient::new(app);

let res = client.get("/foo/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
}

#[crate::test]
async fn can_extract_nested_matched_path_in_middleware_using_nest() {
async fn extract_matched_path<B>(
matched_path: Option<MatchedPath>,
req: Request<B>,
) -> Request<B> {
assert_eq!(matched_path.unwrap().as_str(), "/:a/:b");
req
}

let app = Router::new()
.nest("/:a", Router::new().route("/:b", get(|| async move {})))
.layer(map_request(extract_matched_path));
Expand All @@ -253,7 +273,7 @@ mod tests {
}

let app = Router::new()
.nest("/:a", Router::new().route("/:b", get(|| async move {})))
.nest_service("/:a", Router::new().route("/:b", get(|| async move {})))
.layer(map_request(assert_no_matched_path));

let client = TestClient::new(app);
Expand All @@ -262,6 +282,23 @@ mod tests {
assert_eq!(res.status(), StatusCode::OK);
}

#[tokio::test]
async fn can_extract_nested_matched_path_in_middleware_via_extension_using_nest() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙌🏼

async fn assert_matched_path<B>(req: Request<B>) -> Request<B> {
assert!(req.extensions().get::<MatchedPath>().is_some());
req
}

let app = Router::new()
.nest("/:a", Router::new().route("/:b", get(|| async move {})))
.layer(map_request(assert_matched_path));

let client = TestClient::new(app);

let res = client.get("/foo/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
}

#[crate::test]
async fn can_extract_nested_matched_path_in_middleware_on_nested_router() {
async fn extract_matched_path<B>(matched_path: MatchedPath, req: Request<B>) -> Request<B> {
Expand Down