Using Actix and anyhow together

My goal is to use Anyhow::Result in everything except my Actix request handlers, then ideally convert the error types automatically. Here's my code:

fn map_error<V, E, F, RE>(r: Result<V, E>, error_constructor: F, message: &str, status_code: u16) -> Result<V>
where E: std::fmt::Debug,
      RE: Into<actix_web::Error>,
      F: Fn(String, StatusCode) -> RE
{
    r.map_err(|err| {
        error!("{:?}", err);
        error_constructor(
            message.to_string(),
            StatusCode::from_u16(status_code).expect("bad status code")
        ).into()
    })
}

pub async fn login(
    session: Session,
    app_state: web::Data<AppState>,
    item: web::Json<LoginRequest>,
) -> Result<web::Json<ApiUser>> {
    let conn = map_error(app_state.db.get(), error::InternalError::new, "Could not get database connection", 500)?;
    let user = map_error(session::authenticate_user(&conn, &item.email, &item.password), error::InternalError::new, "Couldn't authenticate user", 401)?;
    Ok(web::Json(ApiUser { email: user.email }))
}

Here's a possibly relevant thread (not sure) about using derive_more: https://github.com/actix/actix-web/pull/1412

I feel like I'm ice-skating uphill. I suspect that the endgame for what I'm doing here is recapitulating all of the HTTP error types through this function. How do y'all handle this?

How about adding your own error type like this:

struct MyError {
    err: anyhow::Error,
}
impl actix_web::error::ResponseError for MyError {
    ...
}
impl From<anyhow::Error> for MyError {
    fn from(err: anyhow::Error) -> MyError {
        MyError { err }
    }
}

The first impl makes it usable as the error type in a Responder, and the second impl makes the question mark operator work with anyhow's error type. You can use downcast_ref to check for the underlying error type, and use that to find the corresponding error code.

This is probably what I ought to do. I'll give it a whirl the next time I need to float an error up. Thank you!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.