ibraheemdev / matchit

A high performance, zero-copy URL router.
https://docs.rs/matchit
MIT License
366 stars 37 forks source link

Provide a parser that can return the parameters in the URL #58

Closed zllak closed 1 month ago

zllak commented 1 month ago

Feature idea

For a project I'm working on that uses matchit as the URL router, I would really need some way to extract the parameters from the URL. So, either I reimplement the parser in my project, or, if this features interests you, I can implement this directly in matchit. You decide whether or not you deem this feature interesting to be integrated directly here.

Proposal

If you decide you want this implemented here, I can offer this kind of API:

let router = Router::new();
let params = router.extract_params("/path/{id}")?;

Or completely outside of the Router:

let params: std::collections::HashSet<String> = matchit::extract_params("/path/{id}")?;

Feel free to weigh in on the name and method.

The major issue I see with this feature, from having look at how the parsing is done, is that I would need to implement the parsing completely out of the insert method, because the parsing is tightly coupled with the internal tree, making it very hard to extract to reuse the parsing. Unless you have an efficient way to reuse the parsing code from insert, I'm afraid it would require the "duplicate" the parsing, which is far from ideal.

Don't hesitate to reply and let me know what you think. If you find it interesting, I'll start working on a PR.

ibraheemdev commented 1 month ago

Hmm I'm not sure I fully understand. Would extract_params("/{foo}") return ["foo"]? Some context would probably help.

zllak commented 1 month ago

Hello,

Indeed the idea of that is to have exactly what you described, parse the URL and return the named parameters.

ibraheemdev commented 1 month ago

This would be relatively easy to implement using the find_wildcard helper, but I'm not sure I see the use case.

zllak commented 1 month ago

That's why I ask first here, because you're right, there is no real use case for this library in particular, it's just a use case I have for another project, so it might not be interesting for you to implement this here. If not, I would probably implement in a fork.

Let me know what you want to do.

ibraheemdev commented 1 month ago

I'm wondering about your use case, if it seems reasonable I'm happy to accept a PR for this :) FWIW you can emulate this feature currently with:


let route = "/{foo}/{bar}";

let mut router = Router::new();
router.insert(route, ());
let params: Vec<&str> = router
    .at(route)
    .unwrap()
    .params
    .iter()
    .map(|(k, _)| k)
    .collect();
zllak commented 1 month ago

Oh wow, I did not though of that. So that makes this idea not really interesting now ... Because you are right, this serves a very specific purpose that can be emulated already. I think I can close this, unless you want this in a PR, but it will indeed end up doing this trick I think...

zllak commented 1 month ago

I'm closing this as I thought the use case I had was not possible at the time, but it was. Also, the purpose was not obvious to add to upstream, and now that I know there's a way around it that works, it makes even less sense to add to matchit.