Skip to content

Commit 32709f5

Browse files
authored
Merge pull request #254 from gameldar/master
Fix the documentation for wildcards for path definitions to match implementation
2 parents 8b667fe + 5c483ba commit 32709f5

File tree

2 files changed

+180
-8
lines changed

2 files changed

+180
-8
lines changed

tests/wildcard.rs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@ async fn add_one(cx: Context<()>) -> Result<String, tide::Error> {
1010
Ok((num + 1).to_string())
1111
}
1212

13+
async fn add_two(cx: Context<()>) -> Result<String, tide::Error> {
14+
let one: i64 = cx.param("one").client_err()?;
15+
let two: i64 = cx.param("two").client_err()?;
16+
Ok((one + two).to_string())
17+
}
18+
19+
async fn echo_path(cx: Context<()>) -> Result<String, tide::Error> {
20+
let path: String = cx.param("path").client_err()?;
21+
Ok(path)
22+
}
23+
24+
async fn echo_empty(cx: Context<()>) -> Result<String, tide::Error> {
25+
let path: String = cx.param("").client_err()?;
26+
Ok(path)
27+
}
28+
1329
#[test]
1430
fn wildcard() {
1531
let mut app = tide::App::new();
@@ -56,3 +72,156 @@ fn not_found_error() {
5672
let res = server.simulate(req).unwrap();
5773
assert_eq!(res.status(), 404);
5874
}
75+
76+
#[test]
77+
fn wildpath() {
78+
let mut app = tide::App::new();
79+
app.at("/echo/*path").get(echo_path);
80+
let mut server = make_server(app.into_http_service()).unwrap();
81+
82+
let req = http::Request::get("/echo/some_path")
83+
.body(Body::empty())
84+
.unwrap();
85+
let res = server.simulate(req).unwrap();
86+
assert_eq!(res.status(), 200);
87+
let body = block_on(res.into_body().into_vec()).unwrap();
88+
assert_eq!(&*body, &*b"some_path");
89+
90+
let req = http::Request::get("/echo/multi/segment/path")
91+
.body(Body::empty())
92+
.unwrap();
93+
let res = server.simulate(req).unwrap();
94+
assert_eq!(res.status(), 200);
95+
let body = block_on(res.into_body().into_vec()).unwrap();
96+
assert_eq!(&*body, &*b"multi/segment/path");
97+
98+
let req = http::Request::get("/echo/").body(Body::empty()).unwrap();
99+
let res = server.simulate(req).unwrap();
100+
assert_eq!(res.status(), 404);
101+
let body = block_on(res.into_body().into_vec()).unwrap();
102+
assert_eq!(&*body, &*b"");
103+
}
104+
105+
#[test]
106+
fn multi_wildcard() {
107+
let mut app = tide::App::new();
108+
app.at("/add_two/:one/:two/").get(add_two);
109+
let mut server = make_server(app.into_http_service()).unwrap();
110+
111+
let req = http::Request::get("/add_two/1/2/")
112+
.body(Body::empty())
113+
.unwrap();
114+
let res = server.simulate(req).unwrap();
115+
assert_eq!(res.status(), 200);
116+
let body = block_on(res.into_body().into_vec()).unwrap();
117+
assert_eq!(&*body, &*b"3");
118+
119+
let req = http::Request::get("/add_two/-1/2/")
120+
.body(Body::empty())
121+
.unwrap();
122+
let res = server.simulate(req).unwrap();
123+
assert_eq!(res.status(), 200);
124+
let body = block_on(res.into_body().into_vec()).unwrap();
125+
assert_eq!(&*body, &*b"1");
126+
let req = http::Request::get("/add_two/1")
127+
.body(Body::empty())
128+
.unwrap();
129+
let res = server.simulate(req).unwrap();
130+
assert_eq!(res.status(), 404);
131+
}
132+
133+
#[test]
134+
fn wild_last_segment() {
135+
let mut app = tide::App::new();
136+
app.at("/echo/:path/*").get(echo_path);
137+
let mut server = make_server(app.into_http_service()).unwrap();
138+
139+
let req = http::Request::get("/echo/one/two")
140+
.body(Body::empty())
141+
.unwrap();
142+
let res = server.simulate(req).unwrap();
143+
assert_eq!(res.status(), 200);
144+
let body = block_on(res.into_body().into_vec()).unwrap();
145+
assert_eq!(&*body, &*b"one");
146+
147+
let req = http::Request::get("/echo/one/two/three/four")
148+
.body(Body::empty())
149+
.unwrap();
150+
let res = server.simulate(req).unwrap();
151+
assert_eq!(res.status(), 200);
152+
let body = block_on(res.into_body().into_vec()).unwrap();
153+
assert_eq!(&*body, &*b"one");
154+
}
155+
156+
#[test]
157+
fn invalid_wildcard() {
158+
let mut app = tide::App::new();
159+
app.at("/echo/*path/:one/").get(echo_path);
160+
let mut server = make_server(app.into_http_service()).unwrap();
161+
162+
let req = http::Request::get("/echo/one/two")
163+
.body(Body::empty())
164+
.unwrap();
165+
let res = server.simulate(req).unwrap();
166+
assert_eq!(res.status(), 404);
167+
}
168+
169+
#[test]
170+
fn nameless_wildcard() {
171+
let mut app = tide::App::new();
172+
app.at("/echo/:").get(async move |_| "");
173+
174+
let mut server = make_server(app.into_http_service()).unwrap();
175+
176+
let req = http::Request::get("/echo/one/two")
177+
.body(Body::empty())
178+
.unwrap();
179+
let res = server.simulate(req).unwrap();
180+
assert_eq!(res.status(), 404);
181+
182+
let req = http::Request::get("/echo/one").body(Body::empty()).unwrap();
183+
let res = server.simulate(req).unwrap();
184+
assert_eq!(res.status(), 200);
185+
}
186+
187+
#[test]
188+
fn nameless_internal_wildcard() {
189+
let mut app = tide::App::new();
190+
app.at("/echo/:/:path").get(echo_path);
191+
let mut server = make_server(app.into_http_service()).unwrap();
192+
193+
let req = http::Request::get("/echo/one").body(Body::empty()).unwrap();
194+
let res = server.simulate(req).unwrap();
195+
assert_eq!(res.status(), 404);
196+
197+
let req = http::Request::get("/echo/one/two")
198+
.body(Body::empty())
199+
.unwrap();
200+
let res = server.simulate(req).unwrap();
201+
assert_eq!(res.status(), 200);
202+
let body = block_on(res.into_body().into_vec()).unwrap();
203+
assert_eq!(&*body, &*b"two");
204+
205+
let req = http::Request::get("/echo/one/two")
206+
.body(Body::empty())
207+
.unwrap();
208+
let res = server.simulate(req).unwrap();
209+
assert_eq!(res.status(), 200);
210+
let body = block_on(res.into_body().into_vec()).unwrap();
211+
assert_eq!(&*body, &*b"two");
212+
}
213+
214+
#[test]
215+
fn nameless_internal_wildcard2() {
216+
let mut app = tide::App::new();
217+
app.at("/echo/:/:path").get(echo_empty);
218+
let mut server = make_server(app.into_http_service()).unwrap();
219+
220+
let req = http::Request::get("/echo/one/two")
221+
.body(Body::empty())
222+
.unwrap();
223+
let res = server.simulate(req).unwrap();
224+
assert_eq!(res.status(), 200);
225+
let body = block_on(res.into_body().into_vec()).unwrap();
226+
assert_eq!(&*body, &*b"one");
227+
}

tide-core/src/app.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use crate::{
4141
/// # Routing and parameters
4242
///
4343
/// Tide's routing system is simple and similar to many other frameworks. It
44-
/// uses `:foo` for "wildcard" URL segments, and `:foo*` to match the rest of a
44+
/// uses `:foo` for "wildcard" URL segments, and `*foo` to match the rest of a
4545
/// URL (which may include multiple segments). Here's an example using wildcard
4646
/// segments as parameters to endpoints:
4747
///
@@ -183,12 +183,13 @@ impl<State: Send + Sync + 'static> App<State> {
183183
/// parameter called `name`. It is not possible to define wildcard segments
184184
/// with different names for otherwise identical paths.
185185
///
186-
/// Wildcard definitions can be followed by an optional *wildcard
187-
/// modifier*. Currently, there is only one modifier: `*`, which means that
188-
/// the wildcard will match to the end of given path, no matter how many
189-
/// segments are left, even nothing. It is an error to define two wildcard
190-
/// segments with different wildcard modifiers, or to write other path
191-
/// segment after a segment with wildcard modifier.
186+
/// Alternatively a wildcard definitions can start with a `*`, for example
187+
/// `*path`, which means that the wildcard will match to the end of given
188+
/// path, no matter how many segments are left, even nothing.
189+
///
190+
/// The name of the parameter can be omitted to define a path that matches
191+
/// the required structure, but where the parameters are not required.
192+
/// `:` will match a segment, and `*` will match an entire path.
192193
///
193194
/// Here are some examples omitting the HTTP verb based endpoint selection:
194195
///
@@ -197,7 +198,9 @@ impl<State: Send + Sync + 'static> App<State> {
197198
/// app.at("/");
198199
/// app.at("/hello");
199200
/// app.at("add_two/:num");
200-
/// app.at("static/:path*");
201+
/// app.at("files/:user/*");
202+
/// app.at("static/*path");
203+
/// app.at("static/:context/:");
201204
/// ```
202205
///
203206
/// There is no fallback route matching, i.e. either a resource is a full

0 commit comments

Comments
 (0)