From 3c19623c8a66cddaa1c3df3e3ea974983807aec5 Mon Sep 17 00:00:00 2001 From: Walther Chen Date: Mon, 28 Oct 2019 12:17:24 -0400 Subject: [PATCH 1/5] Param filter with user-defined rejection --- src/filters/path.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/filters/path.rs b/src/filters/path.rs index bfaa33d82..93d6f65ca 100644 --- a/src/filters/path.rs +++ b/src/filters/path.rs @@ -274,6 +274,79 @@ pub fn param( }) } +======= +/// Extract a parameter from a path segment. +/// +/// This will try to parse a value from the current request path +/// segment, and if successful, the value is returned as the `Filter`'s +/// "extracted" value. +/// +/// If the value could not be parsed, rejects with a user-defined [`Rejection`][]. +/// +/// The associated `Err` on the `FromStr` must impl `From` for `Rejection`. See example. +/// +/// If [`warp::reject::custom`][] is used to create a `Rejection`, a [`recover`][] filter +/// should convert this `Rejection` into a `Reply`, or else this will be returned as a +/// `500 Internal Server Error`. +/// +/// [`Rejection`]: ../../reject/struct.Rejection.html +/// [`recover`]: ../trait.Filter.html#method.recover +/// [`warp::reject::custom`]: ../../reject/fn.custom.html +/// +/// +/// # Example +/// +/// ``` +/// use std::convert::From; +/// use std::str::FromStr; +/// use warp::{Filter, Rejection}; +/// +/// #[derive(Debug)] +/// struct MyStruct { +/// id: u32, +/// } +/// +/// impl FromStr for MyStruct { +/// type Err = MyError; +/// +/// fn from_str(s: &str) -> Result { +/// let id = s.parse::().map_err(|_| MyError)?; +/// +/// Ok(MyStruct { id }) +/// } +/// } +/// +/// struct MyError; +/// +/// impl From for Rejection { +/// fn from(err: MyError) -> Rejection { +/// warp::reject::custom("My Custom Rejection") +/// } +/// } +/// +/// let route = warp::path::param_with_err() +/// .map(|id: MyStruct| { +/// format!("You asked for /{:?}", id) +/// }); +/// +/// ``` +pub fn param_with_err() -> impl Filter, Error = Rejection> + Copy +where + T: FromStr + Send + 'static, + T::Err: Into, +{ + segment(|seg| { + log::trace!("param?: {:?}", seg); + if seg.is_empty() { + return Err(reject::not_found()); + } + T::from_str(seg).map(one).map_err(|err| { + #[allow(deprecated)] + err.into() + }) + }) +} + /// Extract the unmatched tail of the path. /// /// This will return a `Tail`, which allows access to the rest of the path From 94eeab1679f9de305c9bee39cd429ceaea84d146 Mon Sep 17 00:00:00 2001 From: Walther Chen Date: Mon, 28 Oct 2019 20:21:39 -0400 Subject: [PATCH 2/5] return custom Rejection directly --- src/filters/path.rs | 48 +++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/filters/path.rs b/src/filters/path.rs index 93d6f65ca..8705284c3 100644 --- a/src/filters/path.rs +++ b/src/filters/path.rs @@ -281,13 +281,11 @@ pub fn param( /// segment, and if successful, the value is returned as the `Filter`'s /// "extracted" value. /// -/// If the value could not be parsed, rejects with a user-defined [`Rejection`][]. +/// If the value could not be parsed, rejects with a custom [`Rejection`][]. /// -/// The associated `Err` on the `FromStr` must impl `From` for `Rejection`. See example. -/// -/// If [`warp::reject::custom`][] is used to create a `Rejection`, a [`recover`][] filter -/// should convert this `Rejection` into a `Reply`, or else this will be returned as a -/// `500 Internal Server Error`. +/// Since [`warp::reject::custom`][] is used to create a `Rejection` under the hood, +/// a [`recover`][] filter should convert this `Rejection` into a `Reply`, or else +/// this will be returned as a `500 Internal Server Error`. /// /// [`Rejection`]: ../../reject/struct.Rejection.html /// [`recover`]: ../trait.Filter.html#method.recover @@ -297,9 +295,17 @@ pub fn param( /// # Example /// /// ``` +/// use futures::future; /// use std::convert::From; /// use std::str::FromStr; -/// use warp::{Filter, Rejection}; +/// use warp::{ +/// http::{ +/// status, +/// Response, +/// }, +/// Filter, +/// Rejection +/// }; /// /// #[derive(Debug)] /// struct MyStruct { @@ -316,24 +322,40 @@ pub fn param( /// } /// } /// +/// #[derive(Debug)] /// struct MyError; /// -/// impl From for Rejection { -/// fn from(err: MyError) -> Rejection { -/// warp::reject::custom("My Custom Rejection") +/// impl std::fmt::Display for MyError { +/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +/// write!(f, "MyError") /// } /// } /// +/// impl std::error::Error for MyError {}; +/// /// let route = warp::path::param_with_err() /// .map(|id: MyStruct| { /// format!("You asked for /{:?}", id) -/// }); +/// }) +/// .recover(|err: Rejection| { +/// let err = { +/// if let Some(e) = err.find_cause::() { +/// Ok(Response::builder() +/// .status(status::StatusCode::from_u16(404).unwrap()) +/// .body(e.to_string()) +/// ) +/// } else { +/// Err(err) +/// } +/// }; +/// future::ready(err) +/// }); /// /// ``` pub fn param_with_err() -> impl Filter, Error = Rejection> + Copy where T: FromStr + Send + 'static, - T::Err: Into, + T::Err: Into, { segment(|seg| { log::trace!("param?: {:?}", seg); @@ -342,7 +364,7 @@ where } T::from_str(seg).map(one).map_err(|err| { #[allow(deprecated)] - err.into() + reject::custom(err.into()) }) }) } From 6941758f24fd3aa40e745755d4b1988e0fb6cce8 Mon Sep 17 00:00:00 2001 From: Walther Chen Date: Fri, 15 Nov 2019 17:49:09 -0500 Subject: [PATCH 3/5] rebase cleanup --- src/filters/path.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/filters/path.rs b/src/filters/path.rs index 8705284c3..ed98b9e80 100644 --- a/src/filters/path.rs +++ b/src/filters/path.rs @@ -274,7 +274,6 @@ pub fn param( }) } -======= /// Extract a parameter from a path segment. /// /// This will try to parse a value from the current request path From 50dd90c1a1c0e387c138f6ffcc346ea6b3773b55 Mon Sep 17 00:00:00 2001 From: Walther Chen Date: Fri, 15 Nov 2019 18:31:20 -0500 Subject: [PATCH 4/5] update for new rejection system --- src/filters/path.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/filters/path.rs b/src/filters/path.rs index ed98b9e80..c2b4ccfed 100644 --- a/src/filters/path.rs +++ b/src/filters/path.rs @@ -282,10 +282,13 @@ pub fn param( /// /// If the value could not be parsed, rejects with a custom [`Rejection`][]. /// +/// You'll need to implement [`reject::Reject`][] as a marker trait. +/// /// Since [`warp::reject::custom`][] is used to create a `Rejection` under the hood, /// a [`recover`][] filter should convert this `Rejection` into a `Reply`, or else /// this will be returned as a `500 Internal Server Error`. /// +/// [`reject::Reject`]: ../../reject/trait.Reject.html /// [`Rejection`]: ../../reject/struct.Rejection.html /// [`recover`]: ../trait.Filter.html#method.recover /// [`warp::reject::custom`]: ../../reject/fn.custom.html @@ -302,8 +305,11 @@ pub fn param( /// status, /// Response, /// }, +/// reject::{ +/// Reject, +/// Rejection, +/// }, /// Filter, -/// Rejection /// }; /// /// #[derive(Debug)] @@ -331,6 +337,7 @@ pub fn param( /// } /// /// impl std::error::Error for MyError {}; +/// impl Reject for MyError {}; /// /// let route = warp::path::param_with_err() /// .map(|id: MyStruct| { @@ -338,7 +345,7 @@ pub fn param( /// }) /// .recover(|err: Rejection| { /// let err = { -/// if let Some(e) = err.find_cause::() { +/// if let Some(e) = err.find::() { /// Ok(Response::builder() /// .status(status::StatusCode::from_u16(404).unwrap()) /// .body(e.to_string()) @@ -354,7 +361,7 @@ pub fn param( pub fn param_with_err() -> impl Filter, Error = Rejection> + Copy where T: FromStr + Send + 'static, - T::Err: Into, + T::Err: reject::Reject, { segment(|seg| { log::trace!("param?: {:?}", seg); @@ -363,7 +370,7 @@ where } T::from_str(seg).map(one).map_err(|err| { #[allow(deprecated)] - reject::custom(err.into()) + reject::custom(err) }) }) } From ef5b1cd37afa7617d679409c3b4a3e93ccc0887e Mon Sep 17 00:00:00 2001 From: Walther Chen Date: Wed, 22 Apr 2020 18:31:53 -0400 Subject: [PATCH 5/5] update param_with_err to param_with_reject --- src/filters/path.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/filters/path.rs b/src/filters/path.rs index c2b4ccfed..2c9e7f6e0 100644 --- a/src/filters/path.rs +++ b/src/filters/path.rs @@ -318,34 +318,33 @@ pub fn param( /// } /// /// impl FromStr for MyStruct { -/// type Err = MyError; +/// type Err = MyRejection; /// /// fn from_str(s: &str) -> Result { -/// let id = s.parse::().map_err(|_| MyError)?; +/// let id = s.parse::().map_err(|_| MyRejection)?; /// /// Ok(MyStruct { id }) /// } /// } /// /// #[derive(Debug)] -/// struct MyError; +/// struct MyRejection; /// -/// impl std::fmt::Display for MyError { +/// impl std::fmt::Display for MyRejection { /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -/// write!(f, "MyError") +/// write!(f, "My Rejection: something wrong happened.") /// } /// } /// -/// impl std::error::Error for MyError {}; -/// impl Reject for MyError {}; +/// impl Reject for MyRejection {}; /// -/// let route = warp::path::param_with_err() +/// let route = warp::path::param_with_reject() /// .map(|id: MyStruct| { /// format!("You asked for /{:?}", id) /// }) /// .recover(|err: Rejection| { /// let err = { -/// if let Some(e) = err.find::() { +/// if let Some(e) = err.find::() { /// Ok(Response::builder() /// .status(status::StatusCode::from_u16(404).unwrap()) /// .body(e.to_string()) @@ -358,20 +357,17 @@ pub fn param( /// }); /// /// ``` -pub fn param_with_err() -> impl Filter, Error = Rejection> + Copy +pub fn param_with_reject() -> impl Filter, Error = Rejection> + Copy where T: FromStr + Send + 'static, T::Err: reject::Reject, { - segment(|seg| { + filter_segment(|seg| { log::trace!("param?: {:?}", seg); if seg.is_empty() { return Err(reject::not_found()); } - T::from_str(seg).map(one).map_err(|err| { - #[allow(deprecated)] - reject::custom(err) - }) + T::from_str(seg).map(one).map_err(|err| reject::custom(err)) }) }