Skip to content

Commit 0a1327a

Browse files
authored
Merge pull request #709 from http-rs/param-error
Remove parsing from `Request::param`
2 parents 904a45e + 4e1152d commit 0a1327a

File tree

7 files changed

+52
-96
lines changed

7 files changed

+52
-96
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ async-trait = "0.1.36"
4242
femme = { version = "2.0.1", optional = true }
4343
futures-util = "0.3.5"
4444
http-client = { version = "6.0.0", default-features = false }
45-
http-types = "2.2.1"
45+
http-types = "2.5.0"
4646
kv-log-macro = "1.0.4"
4747
log = { version = "0.4.8", features = ["std"] }
4848
pin-project-lite = "0.1.7"

examples/fib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ fn fib(n: usize) -> usize {
1010

1111
async fn fibsum(req: Request<()>) -> tide::Result<String> {
1212
use std::time::Instant;
13-
let n: usize = req.param("n").unwrap_or(0);
13+
let n: usize = req.param("n")?.parse().unwrap_or(0);
1414
// Start a stopwatch
1515
let start = Instant::now();
1616
// Compute the nth number in the fibonacci sequence

examples/upload.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ async fn main() -> Result<(), IoError> {
3636

3737
app.at(":file")
3838
.put(|req: Request<TempDirState>| async move {
39-
let path: String = req.param("file")?;
39+
let path = req.param("file")?;
4040
let fs_path = req.state().path().join(path);
4141

4242
let file = OpenOptions::new()
@@ -55,7 +55,7 @@ async fn main() -> Result<(), IoError> {
5555
Ok(json!({ "bytes": bytes_written }))
5656
})
5757
.get(|req: Request<TempDirState>| async move {
58-
let path: String = req.param("file")?;
58+
let path = req.param("file")?;
5959
let fs_path = req.state().path().join(path);
6060

6161
if let Ok(body) = Body::from_file(fs_path).await {

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ pub mod sessions;
9090
pub use endpoint::Endpoint;
9191
pub use middleware::{Middleware, Next};
9292
pub use redirect::Redirect;
93-
pub use request::{ParamError, Request};
93+
pub use request::Request;
9494
pub use response::Response;
9595
pub use response_builder::ResponseBuilder;
9696
pub use route::Route;

src/request.rs

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ use route_recognizer::Params;
44

55
use std::ops::Index;
66
use std::pin::Pin;
7-
use std::{fmt, str::FromStr};
87

98
use crate::cookies::CookieData;
109
use crate::http::cookies::Cookie;
10+
use crate::http::format_err;
1111
use crate::http::headers::{self, HeaderName, HeaderValues, ToHeaderValues};
1212
use crate::http::{self, Body, Method, Mime, StatusCode, Url, Version};
1313
use crate::Response;
@@ -29,23 +29,6 @@ pin_project_lite::pin_project! {
2929
}
3030
}
3131

32-
#[derive(Debug)]
33-
pub enum ParamError<E> {
34-
NotFound(String),
35-
ParsingError(E),
36-
}
37-
38-
impl<E: fmt::Debug + fmt::Display> fmt::Display for ParamError<E> {
39-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40-
match self {
41-
ParamError::NotFound(name) => write!(f, "Param \"{}\" not found!", name),
42-
ParamError::ParsingError(err) => write!(f, "Param failed to parse: {}", err),
43-
}
44-
}
45-
}
46-
47-
impl<T: fmt::Debug + fmt::Display> std::error::Error for ParamError<T> {}
48-
4932
impl<State> Request<State> {
5033
/// Create a new `Request`.
5134
pub(crate) fn new(state: State, req: http_types::Request, route_params: Vec<Params>) -> Self {
@@ -287,10 +270,7 @@ impl<State> Request<State> {
287270
///
288271
/// # Errors
289272
///
290-
/// Yields a `ParamError::ParsingError` if the parameter was found but failed to parse as an
291-
/// instance of type `T`.
292-
///
293-
/// Yields a `ParamError::NotFound` if `key` is not a parameter for the route.
273+
/// An error is returned if `key` is not a valid parameter for the route.
294274
///
295275
/// # Examples
296276
///
@@ -301,7 +281,7 @@ impl<State> Request<State> {
301281
/// use tide::{Request, Result};
302282
///
303283
/// async fn greet(req: Request<()>) -> Result<String> {
304-
/// let name = req.param("name").unwrap_or("world".to_owned());
284+
/// let name = req.param("name").unwrap_or("world");
305285
/// Ok(format!("Hello, {}!", name))
306286
/// }
307287
///
@@ -312,13 +292,12 @@ impl<State> Request<State> {
312292
/// #
313293
/// # Ok(()) })}
314294
/// ```
315-
pub fn param<T: FromStr>(&self, key: &str) -> Result<T, ParamError<T::Err>> {
295+
pub fn param(&self, key: &str) -> crate::Result<&str> {
316296
self.route_params
317297
.iter()
318298
.rev()
319299
.find_map(|params| params.find(key))
320-
.ok_or_else(|| ParamError::NotFound(key.to_string()))
321-
.and_then(|param| param.parse().map_err(ParamError::ParsingError))
300+
.ok_or_else(|| format_err!("Param \"{}\" not found", key.to_string()))
322301
}
323302

324303
/// Parse the URL query component into a struct, using [serde_qs](https://docs.rs/serde_qs). To

tests/params.rs

Lines changed: 20 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,39 @@
11
use http_types::{self, Method, Url};
2-
use tide::{self, Request, Response, Result, StatusCode};
2+
use tide::{self, Request, Response, Result};
33

44
#[async_std::test]
5-
async fn test_param_invalid_type() {
6-
async fn get_by_id(req: Request<()>) -> Result<Response> {
7-
assert_eq!(
8-
req.param::<i32>("id").unwrap_err().to_string(),
9-
"Param failed to parse: invalid digit found in string"
10-
);
11-
let _ = req.param::<i32>("id")?;
12-
Result::Ok(Response::new(StatusCode::Ok))
13-
}
14-
let mut server = tide::new();
15-
server.at("/by_id/:id").get(get_by_id);
16-
17-
let req = http_types::Request::new(
18-
Method::Get,
19-
Url::parse("http://example.com/by_id/wrong").unwrap(),
20-
);
21-
let res: http_types::Response = server.respond(req).await.unwrap();
22-
assert_eq!(res.status(), StatusCode::InternalServerError);
23-
}
24-
25-
#[async_std::test]
26-
async fn test_missing_param() {
5+
async fn test_missing_param() -> tide::Result<()> {
276
async fn greet(req: Request<()>) -> Result<Response> {
28-
assert_eq!(
29-
req.param::<String>("name").unwrap_err().to_string(),
30-
"Param \"name\" not found!"
31-
);
32-
let _: String = req.param("name")?;
33-
Result::Ok(Response::new(StatusCode::Ok))
7+
assert_eq!(req.param("name")?, "Param \"name\" not found");
8+
Ok(Response::new(200))
349
}
10+
3511
let mut server = tide::new();
3612
server.at("/").get(greet);
3713

38-
let req = http_types::Request::new(Method::Get, Url::parse("http://example.com/").unwrap());
39-
let res: http_types::Response = server.respond(req).await.unwrap();
40-
assert_eq!(res.status(), StatusCode::InternalServerError);
14+
let req = http_types::Request::new(Method::Get, Url::parse("http://example.com/")?);
15+
let res: http_types::Response = server.respond(req).await?;
16+
assert_eq!(res.status(), 500);
17+
Ok(())
4118
}
4219

4320
#[async_std::test]
44-
async fn hello_world_parametrized() {
45-
async fn greet(req: tide::Request<()>) -> Result<Response> {
46-
let name = req.param("name").unwrap_or_else(|_| "nori".to_owned());
47-
let mut response = tide::Response::new(StatusCode::Ok);
48-
response.set_body(format!("{} says hello", name));
49-
Ok(response)
21+
async fn hello_world_parametrized() -> Result<()> {
22+
async fn greet(req: tide::Request<()>) -> Result<impl Into<Response>> {
23+
let body = format!("{} says hello", req.param("name").unwrap_or("nori"));
24+
Ok(Response::builder(200).body(body))
5025
}
5126

5227
let mut server = tide::new();
5328
server.at("/").get(greet);
5429
server.at("/:name").get(greet);
5530

56-
let req = http_types::Request::new(Method::Get, Url::parse("http://example.com/").unwrap());
57-
let mut res: http_types::Response = server.respond(req).await.unwrap();
58-
assert_eq!(
59-
res.body_string().await.unwrap(),
60-
"nori says hello".to_string()
61-
);
31+
let req = http_types::Request::new(Method::Get, Url::parse("http://example.com/")?);
32+
let mut res: http_types::Response = server.respond(req).await?;
33+
assert_eq!(res.body_string().await?, "nori says hello");
6234

63-
let req = http_types::Request::new(Method::Get, Url::parse("http://example.com/iron").unwrap());
64-
let mut res: http_types::Response = server.respond(req).await.unwrap();
65-
assert_eq!(
66-
res.body_string().await.unwrap(),
67-
"iron says hello".to_string()
68-
);
35+
let req = http_types::Request::new(Method::Get, Url::parse("http://example.com/iron")?);
36+
let mut res: http_types::Response = server.respond(req).await?;
37+
assert_eq!(res.body_string().await?, "iron says hello");
38+
Ok(())
6939
}

tests/wildcard.rs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,34 @@
11
mod test_utils;
22
use test_utils::ServerTestingExt;
3-
use tide::{Request, StatusCode};
3+
use tide::{Error, Request, StatusCode};
4+
45
async fn add_one(req: Request<()>) -> Result<String, tide::Error> {
5-
match req.param::<i64>("num") {
6-
Ok(num) => Ok((num + 1).to_string()),
7-
Err(err) => Err(tide::Error::new(StatusCode::BadRequest, err)),
8-
}
6+
let num: i64 = req
7+
.param("num")?
8+
.parse()
9+
.map_err(|err| Error::new(StatusCode::BadRequest, err))?;
10+
Ok((num + 1).to_string())
911
}
1012

1113
async fn add_two(req: Request<()>) -> Result<String, tide::Error> {
12-
let one = req
13-
.param::<i64>("one")
14-
.map_err(|err| tide::Error::new(StatusCode::BadRequest, err))?;
15-
let two = req
16-
.param::<i64>("two")
17-
.map_err(|err| tide::Error::new(StatusCode::BadRequest, err))?;
14+
let one: i64 = req
15+
.param("one")?
16+
.parse()
17+
.map_err(|err| Error::new(StatusCode::BadRequest, err))?;
18+
let two: i64 = req
19+
.param("two")?
20+
.parse()
21+
.map_err(|err| Error::new(StatusCode::BadRequest, err))?;
1822
Ok((one + two).to_string())
1923
}
2024

2125
async fn echo_path(req: Request<()>) -> Result<String, tide::Error> {
22-
match req.param::<String>("path") {
23-
Ok(path) => Ok(path),
24-
Err(err) => Err(tide::Error::new(StatusCode::BadRequest, err)),
26+
match req.param("path") {
27+
Ok(path) => Ok(path.into()),
28+
Err(mut err) => {
29+
err.set_status(StatusCode::BadRequest);
30+
Err(err)
31+
}
2532
}
2633
}
2734

@@ -124,7 +131,7 @@ async fn nameless_internal_wildcard() -> tide::Result<()> {
124131
async fn nameless_internal_wildcard2() -> tide::Result<()> {
125132
let mut app = tide::new();
126133
app.at("/echo/:/:path").get(|req: Request<()>| async move {
127-
assert_eq!(req.param::<String>("path")?, "two");
134+
assert_eq!(req.param("path")?, "two");
128135
Ok("")
129136
});
130137

0 commit comments

Comments
 (0)