Added wildcard feature#586
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests.
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
ElijahAhianyo
left a comment
There was a problem hiding this comment.
@dharshan-0 Thanks a lot for your contribution. This is a great start! Let's address the comments, and it's good to merge.
| (Some('/') | None, State::Param { start }) => { | ||
| panic!("Unclosed parameter: `{}`", &path_pattern[start..index]); | ||
| } | ||
| (Some('*'), State::Literal { start }) => { |
There was a problem hiding this comment.
Currently, this branch implies that routes such as /foo/va*path are valid. I don't think we should support this, as it introduces ambiguity around how characters preceding the * should be handled.
To keep the routing semantics simple and predictable, wildcard segments should be required to begin with the * operator. In other words, patterns like *path would be valid, whereas va*path would not.
There was a problem hiding this comment.
I also think that, for the sake of consistency with path params, we should have wildcards in curly braces as well. i.e {*path} instead of plain *path
| ); | ||
|
|
||
| parts.push(PathPart::Literal(literal_name.to_string())); | ||
| parts.push(PathPart::Param { |
There was a problem hiding this comment.
It would be nice to add some type safety here and model wildcards explicitly. Instead of encoding wildcard semantics in the parameter name, we could introduce a PathPart::Wildcard variant and help the compiler distinguish between wildcards and regular path params.
|
|
||
| parts.push(PathPart::Literal(literal_name.to_string())); | ||
| parts.push(PathPart::Param { | ||
| name: (*param_name).to_string(), |
There was a problem hiding this comment.
I'm not sure we should include the * when storing the parameter name. Doing so forces downstream consumers to handle the wildcard marker themselves, which feels like a leaky abstraction.
For example:
let path_parser = PathMatcher::new("/{*path}");
assert_eq!(
path_parser.capture("/foo/bar"),
Some(CaptureResult::new(
vec![PathParam::new("*path", "foo/bar")],
""
))
);Instead, the * should be treated as part of the route syntax rather than part of the parameter name:
let path_parser = PathMatcher::new("/{*path}");
assert_eq!(
path_parser.capture("/foo/bar"),
Some(CaptureResult::new(
vec![PathParam::new("path", "foo/bar")],
""
))
);Similarly, when using ReverseParamMap, callers should not have to include the * in the parameter name:
let path_parser = PathMatcher::new("/users/{*path}");
let mut params = ReverseParamMap::new();
params.insert("path", "foo"); // `path` instead of `*path`
assert_eq!(
path_parser.reverse(¶ms).unwrap(),
"/users/123/foo"
);| let path_parser = PathMatcher::new("/users/rand/*path"); | ||
| assert_eq!( | ||
| path_parser.capture("/users/rand/"), | ||
| Some(CaptureResult::new(vec![PathParam::new("*path", "")], "")) |
There was a problem hiding this comment.
For consistency with matching params, users/rand/{*path} should not match users/rand (however, users/rand/foo should be a match).
|
@ElijahAhianyo Thanks for your comments, I will look into it. |
Related issue or discussion
Description
It closes #545 by adding wildcard routing feature.
It uses this
*param_nameto define wildcard.Type of change
Checklist
just test-all)just clippy)cargo fmt)