1 use super::*;
2 use crate::{body::boxed, extract::Extension};
3 use std::collections::HashMap;
4 use tower_http::services::ServeDir;
5
6 #[crate::test]
nesting_apps()7 async fn nesting_apps() {
8 let api_routes = Router::new()
9 .route(
10 "/users",
11 get(|| async { "users#index" }).post(|| async { "users#create" }),
12 )
13 .route(
14 "/users/:id",
15 get(
16 |params: extract::Path<HashMap<String, String>>| async move {
17 format!(
18 "{}: users#show ({})",
19 params.get("version").unwrap(),
20 params.get("id").unwrap()
21 )
22 },
23 ),
24 )
25 .route(
26 "/games/:id",
27 get(
28 |params: extract::Path<HashMap<String, String>>| async move {
29 format!(
30 "{}: games#show ({})",
31 params.get("version").unwrap(),
32 params.get("id").unwrap()
33 )
34 },
35 ),
36 );
37
38 let app = Router::new()
39 .route("/", get(|| async { "hi" }))
40 .nest("/:version/api", api_routes);
41
42 let client = TestClient::new(app);
43
44 let res = client.get("/").send().await;
45 assert_eq!(res.status(), StatusCode::OK);
46 assert_eq!(res.text().await, "hi");
47
48 let res = client.get("/v0/api/users").send().await;
49 assert_eq!(res.status(), StatusCode::OK);
50 assert_eq!(res.text().await, "users#index");
51
52 let res = client.get("/v0/api/users/123").send().await;
53 assert_eq!(res.status(), StatusCode::OK);
54 assert_eq!(res.text().await, "v0: users#show (123)");
55
56 let res = client.get("/v0/api/games/123").send().await;
57 assert_eq!(res.status(), StatusCode::OK);
58 assert_eq!(res.text().await, "v0: games#show (123)");
59 }
60
61 #[crate::test]
wrong_method_nest()62 async fn wrong_method_nest() {
63 let nested_app = Router::new().route("/", get(|| async {}));
64 let app = Router::new().nest("/", nested_app);
65
66 let client = TestClient::new(app);
67
68 let res = client.get("/").send().await;
69 assert_eq!(res.status(), StatusCode::OK);
70
71 let res = client.post("/").send().await;
72 assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
73 assert_eq!(res.headers()[ALLOW], "GET,HEAD");
74
75 let res = client.patch("/foo").send().await;
76 assert_eq!(res.status(), StatusCode::NOT_FOUND);
77 }
78
79 #[crate::test]
nesting_router_at_root()80 async fn nesting_router_at_root() {
81 let nested = Router::new().route("/foo", get(|uri: Uri| async move { uri.to_string() }));
82 let app = Router::new().nest("/", nested);
83
84 let client = TestClient::new(app);
85
86 let res = client.get("/").send().await;
87 assert_eq!(res.status(), StatusCode::NOT_FOUND);
88
89 let res = client.get("/foo").send().await;
90 assert_eq!(res.status(), StatusCode::OK);
91 assert_eq!(res.text().await, "/foo");
92
93 let res = client.get("/foo/bar").send().await;
94 assert_eq!(res.status(), StatusCode::NOT_FOUND);
95 }
96
97 #[crate::test]
nesting_router_at_empty_path()98 async fn nesting_router_at_empty_path() {
99 let nested = Router::new().route("/foo", get(|uri: Uri| async move { uri.to_string() }));
100 let app = Router::new().nest("", nested);
101
102 let client = TestClient::new(app);
103
104 let res = client.get("/").send().await;
105 assert_eq!(res.status(), StatusCode::NOT_FOUND);
106
107 let res = client.get("/foo").send().await;
108 assert_eq!(res.status(), StatusCode::OK);
109 assert_eq!(res.text().await, "/foo");
110
111 let res = client.get("/foo/bar").send().await;
112 assert_eq!(res.status(), StatusCode::NOT_FOUND);
113 }
114
115 #[crate::test]
nesting_handler_at_root()116 async fn nesting_handler_at_root() {
117 let app = Router::new().nest_service("/", get(|uri: Uri| async move { uri.to_string() }));
118
119 let client = TestClient::new(app);
120
121 let res = client.get("/").send().await;
122 assert_eq!(res.status(), StatusCode::OK);
123 assert_eq!(res.text().await, "/");
124
125 let res = client.get("/foo").send().await;
126 assert_eq!(res.status(), StatusCode::OK);
127 assert_eq!(res.text().await, "/foo");
128
129 let res = client.get("/foo/bar").send().await;
130 assert_eq!(res.status(), StatusCode::OK);
131 assert_eq!(res.text().await, "/foo/bar");
132 }
133
134 #[crate::test]
nested_url_extractor()135 async fn nested_url_extractor() {
136 let app = Router::new().nest(
137 "/foo",
138 Router::new().nest(
139 "/bar",
140 Router::new()
141 .route("/baz", get(|uri: Uri| async move { uri.to_string() }))
142 .route(
143 "/qux",
144 get(|req: Request<Body>| async move { req.uri().to_string() }),
145 ),
146 ),
147 );
148
149 let client = TestClient::new(app);
150
151 let res = client.get("/foo/bar/baz").send().await;
152 assert_eq!(res.status(), StatusCode::OK);
153 assert_eq!(res.text().await, "/baz");
154
155 let res = client.get("/foo/bar/qux").send().await;
156 assert_eq!(res.status(), StatusCode::OK);
157 assert_eq!(res.text().await, "/qux");
158 }
159
160 #[crate::test]
nested_url_original_extractor()161 async fn nested_url_original_extractor() {
162 let app = Router::new().nest(
163 "/foo",
164 Router::new().nest(
165 "/bar",
166 Router::new().route(
167 "/baz",
168 get(|uri: extract::OriginalUri| async move { uri.0.to_string() }),
169 ),
170 ),
171 );
172
173 let client = TestClient::new(app);
174
175 let res = client.get("/foo/bar/baz").send().await;
176 assert_eq!(res.status(), StatusCode::OK);
177 assert_eq!(res.text().await, "/foo/bar/baz");
178 }
179
180 #[crate::test]
nested_service_sees_stripped_uri()181 async fn nested_service_sees_stripped_uri() {
182 let app = Router::new().nest(
183 "/foo",
184 Router::new().nest(
185 "/bar",
186 Router::new().route_service(
187 "/baz",
188 service_fn(|req: Request<Body>| async move {
189 let body = boxed(Body::from(req.uri().to_string()));
190 Ok::<_, Infallible>(Response::new(body))
191 }),
192 ),
193 ),
194 );
195
196 let client = TestClient::new(app);
197
198 let res = client.get("/foo/bar/baz").send().await;
199 assert_eq!(res.status(), StatusCode::OK);
200 assert_eq!(res.text().await, "/baz");
201 }
202
203 #[crate::test]
nest_static_file_server()204 async fn nest_static_file_server() {
205 let app = Router::new().nest_service("/static", ServeDir::new("."));
206
207 let client = TestClient::new(app);
208
209 let res = client.get("/static/README.md").send().await;
210 assert_eq!(res.status(), StatusCode::OK);
211 }
212
213 #[crate::test]
nested_multiple_routes()214 async fn nested_multiple_routes() {
215 let app = Router::new()
216 .nest(
217 "/api",
218 Router::new()
219 .route("/users", get(|| async { "users" }))
220 .route("/teams", get(|| async { "teams" })),
221 )
222 .route("/", get(|| async { "root" }));
223
224 let client = TestClient::new(app);
225
226 assert_eq!(client.get("/").send().await.text().await, "root");
227 assert_eq!(client.get("/api/users").send().await.text().await, "users");
228 assert_eq!(client.get("/api/teams").send().await.text().await, "teams");
229 }
230
231 #[test]
232 #[should_panic = "Invalid route \"/\": insertion failed due to conflict with previously registered route: /*__private__axum_nest_tail_param"]
nested_service_at_root_with_other_routes()233 fn nested_service_at_root_with_other_routes() {
234 let _: Router = Router::new()
235 .nest_service("/", Router::new().route("/users", get(|| async {})))
236 .route("/", get(|| async {}));
237 }
238
239 #[test]
nested_at_root_with_other_routes()240 fn nested_at_root_with_other_routes() {
241 let _: Router = Router::new()
242 .nest("/", Router::new().route("/users", get(|| async {})))
243 .route("/", get(|| async {}));
244 }
245
246 #[crate::test]
multiple_top_level_nests()247 async fn multiple_top_level_nests() {
248 let app = Router::new()
249 .nest(
250 "/one",
251 Router::new().route("/route", get(|| async { "one" })),
252 )
253 .nest(
254 "/two",
255 Router::new().route("/route", get(|| async { "two" })),
256 );
257
258 let client = TestClient::new(app);
259
260 assert_eq!(client.get("/one/route").send().await.text().await, "one");
261 assert_eq!(client.get("/two/route").send().await.text().await, "two");
262 }
263
264 #[crate::test]
265 #[should_panic(expected = "Invalid route: nested routes cannot contain wildcards (*)")]
nest_cannot_contain_wildcards()266 async fn nest_cannot_contain_wildcards() {
267 _ = Router::<(), Body>::new().nest("/one/*rest", Router::new());
268 }
269
270 #[crate::test]
outer_middleware_still_see_whole_url()271 async fn outer_middleware_still_see_whole_url() {
272 #[derive(Clone)]
273 struct SetUriExtension<S>(S);
274
275 #[derive(Clone)]
276 struct Uri(http::Uri);
277
278 impl<S, B> Service<Request<B>> for SetUriExtension<S>
279 where
280 S: Service<Request<B>>,
281 {
282 type Response = S::Response;
283 type Error = S::Error;
284 type Future = S::Future;
285
286 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
287 self.0.poll_ready(cx)
288 }
289
290 fn call(&mut self, mut req: Request<B>) -> Self::Future {
291 let uri = Uri(req.uri().clone());
292 req.extensions_mut().insert(uri);
293 self.0.call(req)
294 }
295 }
296
297 async fn handler(Extension(Uri(middleware_uri)): Extension<Uri>) -> impl IntoResponse {
298 middleware_uri.to_string()
299 }
300
301 let app = Router::new()
302 .route("/", get(handler))
303 .route("/foo", get(handler))
304 .route("/foo/bar", get(handler))
305 .nest("/one", Router::new().route("/two", get(handler)))
306 .fallback(handler)
307 .layer(tower::layer::layer_fn(SetUriExtension));
308
309 let client = TestClient::new(app);
310
311 assert_eq!(client.get("/").send().await.text().await, "/");
312 assert_eq!(client.get("/foo").send().await.text().await, "/foo");
313 assert_eq!(client.get("/foo/bar").send().await.text().await, "/foo/bar");
314 assert_eq!(
315 client.get("/not-found").send().await.text().await,
316 "/not-found"
317 );
318 assert_eq!(client.get("/one/two").send().await.text().await, "/one/two");
319 }
320
321 #[crate::test]
nest_at_capture()322 async fn nest_at_capture() {
323 let api_routes = Router::new().route(
324 "/:b",
325 get(|Path((a, b)): Path<(String, String)>| async move { format!("a={a} b={b}") }),
326 );
327
328 let app = Router::new().nest("/:a", api_routes);
329
330 let client = TestClient::new(app);
331
332 let res = client.get("/foo/bar").send().await;
333 assert_eq!(res.status(), StatusCode::OK);
334 assert_eq!(res.text().await, "a=foo b=bar");
335 }
336
337 #[crate::test]
nest_with_and_without_trailing()338 async fn nest_with_and_without_trailing() {
339 let app = Router::new().nest_service("/foo", get(|| async {}));
340
341 let client = TestClient::new(app);
342
343 let res = client.get("/foo").send().await;
344 assert_eq!(res.status(), StatusCode::OK);
345
346 let res = client.get("/foo/").send().await;
347 assert_eq!(res.status(), StatusCode::OK);
348
349 let res = client.get("/foo/bar").send().await;
350 assert_eq!(res.status(), StatusCode::OK);
351 }
352
353 #[tokio::test]
nesting_with_root_inner_router()354 async fn nesting_with_root_inner_router() {
355 let app = Router::new()
356 .nest_service("/service", Router::new().route("/", get(|| async {})))
357 .nest("/router", Router::new().route("/", get(|| async {})))
358 .nest("/router-slash/", Router::new().route("/", get(|| async {})));
359
360 let client = TestClient::new(app);
361
362 // `/service/` does match the `/service` prefix and the remaining path is technically
363 // empty, which is the same as `/` which matches `.route("/", _)`
364 let res = client.get("/service").send().await;
365 assert_eq!(res.status(), StatusCode::OK);
366
367 // `/service/` does match the `/service` prefix and the remaining path is `/`
368 // which matches `.route("/", _)`
369 //
370 // this is perhaps a little surprising but don't think there is much we can do
371 let res = client.get("/service/").send().await;
372 assert_eq!(res.status(), StatusCode::OK);
373
374 // at least it does work like you'd expect when using `nest`
375
376 let res = client.get("/router").send().await;
377 assert_eq!(res.status(), StatusCode::OK);
378
379 let res = client.get("/router/").send().await;
380 assert_eq!(res.status(), StatusCode::NOT_FOUND);
381
382 let res = client.get("/router-slash").send().await;
383 assert_eq!(res.status(), StatusCode::NOT_FOUND);
384
385 let res = client.get("/router-slash/").send().await;
386 assert_eq!(res.status(), StatusCode::OK);
387 }
388
389 macro_rules! nested_route_test {
390 (
391 $name:ident,
392 // the path we nest the inner router at
393 nest = $nested_path:literal,
394 // the route the inner router accepts
395 route = $route_path:literal,
396 // the route we expect to be able to call
397 expected = $expected_path:literal $(,)?
398 ) => {
399 #[crate::test]
400 async fn $name() {
401 let inner = Router::new().route($route_path, get(|| async {}));
402 let app = Router::new().nest($nested_path, inner);
403 let client = TestClient::new(app);
404 let res = client.get($expected_path).send().await;
405 let status = res.status();
406 assert_eq!(status, StatusCode::OK, "Router");
407 }
408 };
409 }
410
411 // test cases taken from https://github.com/tokio-rs/axum/issues/714#issuecomment-1058144460
412 nested_route_test!(nest_1, nest = "", route = "/", expected = "/");
413 nested_route_test!(nest_2, nest = "", route = "/a", expected = "/a");
414 nested_route_test!(nest_3, nest = "", route = "/a/", expected = "/a/");
415 nested_route_test!(nest_4, nest = "/", route = "/", expected = "/");
416 nested_route_test!(nest_5, nest = "/", route = "/a", expected = "/a");
417 nested_route_test!(nest_6, nest = "/", route = "/a/", expected = "/a/");
418 nested_route_test!(nest_7, nest = "/a", route = "/", expected = "/a");
419 nested_route_test!(nest_8, nest = "/a", route = "/a", expected = "/a/a");
420 nested_route_test!(nest_9, nest = "/a", route = "/a/", expected = "/a/a/");
421 nested_route_test!(nest_11, nest = "/a/", route = "/", expected = "/a/");
422 nested_route_test!(nest_12, nest = "/a/", route = "/a", expected = "/a/a");
423 nested_route_test!(nest_13, nest = "/a/", route = "/a/", expected = "/a/a/");
424