6

I am trying to capture errors that may occur for requests made to my server.

This came up when I was receiving a 400 on one of my POST requests (which was thrown before even getting to my request handler method) and I was receiving no feedback as to what the issue was after enabling the debug logs I saw the issue

[actix_web::types::json] Failed to deserialize Json from payload. Request path: /new_endpoint
Json deserialize error: invalid length: expected one of [36, 32], found 10 at line 2 column 20
[DEBUG actix_web::middleware::logger] Error in response: Deserialize(Error("invalid length: expected one of [36, 32], found 10", line: 2, column: 20))

Now, I want to be able to capture that error so that it can be sent back in the body of the 400 response.

I've started with

App::new()
    .wrap(ErrorHandlers::new().handler(http::StatusCode::BAD_REQUEST, handle_bad_request))

and in handle_bad_request I am able to modify the response body to contain new information

fn handle_bad_request<B>(mut res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<Body>> {
    res.response_mut().headers_mut().insert(
        http::header::CONTENT_TYPE,
        http::HeaderValue::from_static("application/json"),
    );
    let new_res: ServiceResponse<Body> = res.map_body(|_head, _body| {
        ResponseBody::Other(Body::Message(Box::new("New Response Body")))
    });
    Ok(ErrorHandlerResponse::Response(new_res))
}

Ideally what I want to do is take the error in ServiceResponse and send it back in the response. I am able to read the error by doing

match res.response().error() {
    Some(e) =>  println!("{0}", e),
    None =>  println!("Error None")
};

but as for actually taking that error and sending it back in the response I am not able to figure that out.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
rpascal
  • 723
  • 1
  • 8
  • 25
  • Can't you just put `format!("{:?}", res.reponse().error())` in your response body? – Jmb Feb 26 '20 at 07:34
  • Just got the chance to try this and it appears to be working! I can't believe I never thought to try that. I will update with an answer here shortly. – rpascal Feb 27 '20 at 02:32

1 Answers1

4

To solve this format!("{:?}", res.reponse().error()) was needed. That does return Some(error message) so just to account for that the following worked.

let errorMsg: String = match res.response().error() {
    Some(e) => format!("{:?}", e),
    None =>  String::from("Unknown Error")
};
let new_res: ServiceResponse<Body> = res.map_body(|_head, _body| {
    ResponseBody::Other(Body::Message(Box::new(errorMsg)))
});
Ok(ErrorHandlerResponse::Response(new_res))
rpascal
  • 723
  • 1
  • 8
  • 25