【问题标题】:Is there a simpler way to create a custom Filter method to invoke a Warp handler?有没有更简单的方法来创建自定义过滤器方法来调用 Warp 处理程序?
【发布时间】:2020-04-13 20:09:22
【问题描述】:

而不是像这样写:

let hello = get()
    .and(path!(String))
    .and_then(|string| handlers::hello(string).map_err(warp::reject::custom))
    .boxed()

我希望能够写作:

let hello = get()
    .and(path!(String))
    .handle(handlers::hello)

handle 在哪里做and_then -> map_err -> boxed 的事情。

现在我为每个 arity 处理程序使用一组特征。这是 2-arity 处理程序:

pub trait Handle2<A, B, Fut, R, F>
where
    R: Reject,
    F: Fn(A, B) -> Fut,
    Fut: Future<Output = Result<String, R>>,
{
    fn handle(self, f: F) -> BoxedFilter<(String,)>;
}

impl<A, B, Fut, R, F, T, Futr> Handle2<A, B, Fut, R, F> for T
where
    R: Reject,
    F: Fn(A, B) -> Fut + Clone + Sync + Send + 'static,
    Fut: Future<Output = Result<String, R>> + Send,
    Futr: Future<Output = Result<(A, B), Rejection>> + Send,
    T: Filter<Extract = (A, B), Error = Rejection, Future = Futr> + Sync + Send + 'static,
{
    fn handle(self, f: F) -> BoxedFilter<(String,)> {
        self.and_then(move |a, b| f(a, b).map_err(warp::reject::custom))
            .boxed()
    }
}

你可以在 Rust 中做到这一点真是太棒了,但是有没有更简单的方法来实现这一点?

【问题讨论】:

    标签: rust traits rust-warp


    【解决方案1】:

    有。

    在你的 main() 中声明这样一个路由:

    let routes = get().and(path("hello")).and_then(routes::getRoot);
    

    您可以使用async 语法糖将简单的处理程序自动转换为未来(0.3/std 处理程序)。这使得它实现了将其用作warp::Filter 的所有必要特征:

    // routes/mod.rs
    
    pub async fn getRoot() -> Result<impl warp::Reply, warp::Rejection> {
        Ok("Hello world !")
    }
    

    到目前为止非常简单!现在您想要但仍然缺少的一件事是使用 warp::reject::custom 进行正确的错误处理。

    首先,让我们的处理程序返回一个错误:

    // routes/mod.rs
    
    pub async fn getRoot() -> Result<impl warp::Reply, warp::Rejection> {
        let _parsed_url = Url::parse(&"https://whydoesn.it/work?").map_err(ServiceError::from)?;
        Ok("Hello world !")
    }
    

    注意 map_err(ServiceError::from) 和返回类型 warp::Rejection 吗?我们需要将我们的特定错误转换为自定义错误枚举(即 ServiceError,我们将很快定义它),然后提供一种将 ServiceError 自动转换为 warp::Rejection 的方法。

    让我们通过创建一种方法来处理来自所有路由处理函数的错误:

    // ./errors.rs
    
    /// An internal error enum for representing all the possible failure states
    #[derive(thiserror::Error, Debug)]
    pub enum ServiceError {
        #[error("unacceptable !")]
        SomeSpecificWayOfFailing,
        #[error(transparent)]
        Other(#[from] Box<dyn std::error::Error + Sync + Send>), // catchAll error type
    }
    impl warp::reject::Reject for ServiceError {}
    impl From<ServiceError> for warp::reject::Rejection {
        fn from(e: ServiceError) -> Self {
            warp::reject::custom(e)
        }
    }
    

    在我们的例子中,我给出的错误示例返回一个url::ParseError。 让我们添加一种将其映射到 ServiceError 的方法:

    // ./errors.rs
    
    impl From<url::ParseError> for ServiceError {
        fn from(e: url::ParseError) -> Self {
            ServiceError::Other(e.into()) // you can refine that and turn it into a more specific enum variant of ServiceError here
        }
    }
    

    你应该准备好了。现在添加一个新的路由/处理程序应该像添加一个异步函数一样简单(加上 impl ServiceError::from 为您要在处理程序函数中处理的任何新错误类型)

    【讨论】:

      猜你喜欢
      • 2014-04-17
      • 2021-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-07
      • 2017-11-25
      • 1970-01-01
      • 2021-10-21
      相关资源
      最近更新 更多