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

Make UrlParams public #3017

Open
1 task done
Diggsey opened this issue Nov 6, 2024 · 4 comments
Open
1 task done

Make UrlParams public #3017

Diggsey opened this issue Nov 6, 2024 · 4 comments

Comments

@Diggsey
Copy link

Diggsey commented Nov 6, 2024

  • I have looked for existing issues (including closed) about this

Feature Request

Make UrlParams public.

Motivation

I want to be able to nest a router under a dynamic path (/:foo) and use a middleware to extract the value of :foo and do something with it. The middleware should then be able to remove foo from the UrlParams so that when it calls Next, the nested router only sees path parameters that it understands.

Proposal

Make UrlParams public.

Alternatives

Provide a hygenic way to nest a router under a dynamic path.

@Diggsey
Copy link
Author

Diggsey commented Nov 6, 2024

This branch adds a method to remove parameters from the request: https://github.com/tokio-rs/axum/compare/main...Diggsey:axum:axum-v0.7.7-patched?expand=1

@mladedav
Copy link
Collaborator

mladedav commented Nov 7, 2024

I'm not sure about allowing such changes to the url params. I feel like it could lead to more surprises.

But it's true that nested handlers shouldn't have to be concerned about parameters of routers under which they've been nested.

Would it be good enough for your use case if we added another Path-like extractor which would expose only captures from the innermost router?

I feel like that somewhat follows the design of Uri and OriginalUri.

@Diggsey
Copy link
Author

Diggsey commented Nov 7, 2024

It would solve my use-case, but I think it could be confusing. Especially if Path continues to be the "default".

Axum already hides what constitutes a single router - for example, when you call nest or merge the routers kindof get combined into one. Whereas if you explicitly call oneshot on the inner router it's clearly doing two separate routing steps.

It's unclear how such a Path-like extractor would interact with these.

Another option would be to provide a .isolate() method on router, which would be equivalent to:

    fn isolate(self) -> axum::Router<S> {
        axum::Router::new().fallback(
            |axum::extract::State(state): axum::extract::State<S>,
             mut request: axum::extract::Request| async move {
                clear_url_params(request.extensions_mut());
                self.clone().with_state(state).oneshot(request).await
            },
        )
    }

That way you could truly separate two routers.

@mladedav
Copy link
Collaborator

mladedav commented Nov 7, 2024

It would be of course up to discussion if we should keep the current Path as default for better backwards compatibility or change it for example to OriginalPath for better consistency with OriginalUri.

Calling merge doesn't really matter because then each handler already knows about the whole matched path. In that case, the two routers really are merged into just one and routing happens once. The issue is only with nest where a handler may not expect part of the path and as you kind of pointed out, routing happens once in the outer router and if it matches the prefix, it uses a wildcard capture which is then used for routing in the inner router. It is kind of similar to what you wrote.

An example of what I have in mind would be something like:

let inner_router = Router::new().route("/:id/:version", |path: Path<(String, String)>| todo!());

let router = Router::new()
  .nest("/global/:env", inner_router.clone())
  .nest("/customer/:customer_id/:env", inner_router);

which would fail because the inner_router cannot expect both 3 or 4 path segments (actually it can if it used Path<Vec<String>> and then took just the last two, but I see that just as a workaround). It should be free to expect just the two segements it should be concerned with and allow the other things to be ignored or used by middlewares specific for the given routes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants