Warp.rs: warp :: Отклонение и обработка ошибок с использованием '?' - PullRequest
0 голосов
/ 03 апреля 2020

Используя warp.rs 0.2.2 , давайте рассмотрим базовый c веб-сервис с одним маршрутом для GET /:

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    let getRoot = warp::get().and(warp::path::end()).and_then(routes::getRoot);
    warp::serve(getRoot).run(([0, 0, 0, 0], 3030)).await;
    Ok(())
}

Моя цель - использовать ? для обработки ошибок в обработчиках маршрута, поэтому давайте напишем тот, который может ошибаться и возвращаться рано в crate::routes:

use crate::errors::ServiceError;
use url::Url;

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 !")
}

Эта версия работает. Здесь ошибка, возвращаемая Url::parse(), представляет собой url::ParseError

Для преобразования между типами ошибок из url::ParseError в ServiceError, затем из ServiceError в warp::Rejection, я написал несколько помощники по ошибкам в crate::errors:

#[derive(thiserror::Error, Debug)]
pub enum ServiceError {
    #[error(transparent)]
    Other(#[from] anyhow::Error), // source and Display delegate to anyhow::Error
}
impl warp::reject::Reject for ServiceError {}
impl From<ServiceError> for warp::reject::Rejection {
    fn from(e: ServiceError) -> Self {
        warp::reject::custom(e)
    }
}
impl From<url::ParseError> for ServiceError {
    fn from(e: url::ParseError) -> Self {
        ServiceError::Other(e.into())
    }
}

Теперь вышеприведенное работает, и я пытаюсь сократить второй блок кода, чтобы использовать ? для прямой обработки ошибок, и автоматически преобразовать из основная ошибка (здесь url::ParseError) до warp::Rejection. Вот что я попробовал:

use crate::errors::ServiceError;
use url::Url;

pub async fn getRoot() -> Result<impl warp::Reply, ServiceError> {
    let _parsed_url = Url::parse(&"https://whydoesn.it/work?")?;

    Ok("Hello world !")
}

url::ParseError, возвращаемое Url::Parse, преобразует штраф в ServiceError для возврата, но возврат ServiceError из моего обработчика не работает. Первая ошибка компиляции, которую я получаю:

error[E0277]: the trait bound `errors::ServiceError: warp::reject::sealed::CombineRejection<warp::reject::Rejection>` is not satisfied
   --> src/main.rs:102:54
    |
102 |     let getRoot = warp::get().and(warp::path::end()).and_then(routes::getRoot);
    |                                                      ^^^^^^^^ the trait `warp::reject::sealed::CombineRejection<warp::reject::Rejection>` is not implemented for `errors::ServiceError`

Есть ли способ сохранить краткую обработку ошибок, используя только ? и либо:

  • make ServiceError Implement warp::reject::sealed::CombineRejection<warp::reject::Rejection>?
  • обойти это?
...