Actix web correct error handling

I want to match my error messages on the basis of the status codes I get from my endpoint

// error message enum
#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
pub enum ErrorResponse {
    /// When item is not found from storage.
    NotFound(String),
    /// When unauthorized to complete operation
    Unauthorized(String),
    /// The server cannot process the request due to a client error
    BadRequest(String),
    /// The client does not have access to the content
    Forbidden(String),
    /// The request was well-formed but was unable to be followed due to semantic errors
    UnprocessableContent(String),
    /// The server encountered an unexpected condition that prevented it from fulfilling the request
    InternalServerError(String),
    BadGateway(String)
}
// one of my endpoints
#[get("/statistics/all")]
pub async fn get_all_statistics() -> Result<HttpResponse, ErrorResponse> {
    //TODO: writing a service function that calculates statistic data
    let cache: RedisCache = RedisCache::default();
    let vec: Vec<String> = vec![cache.get_str("statistics").await.unwrap()];

    Ok(HttpResponse::Ok().json(vec))
}

I want to create a struct like this

pub struct ErrorMessage {
    pub cause: String,
    pub message: String,
    pub status_code: i32
}

How can I change my endpoint or create a function that handles the response based on the given status code? I cannot find an actix function like get_status_code().

I can only find actix_web::dev::ServiceResponse that can be used as a wrapper but I cannot figure out how to use it correctly.

You get access to the service response in your middleware. You could create your ErrorMessage there, though I personally would just return it from your endpoints directly instead of ErrorResponse, I don't see a need for both types as the former is just the latter in more specific.

And how can I get the status codes to return my ErrorMessage type?

To do something like this in my endpoint

match status_codes {
    200 => Ok(HttpResponse::Ok().json(some_json)),
    _ => Err(ErrorMessage {
           cause,
           message,
           status_code
         })
}

Maybe more specific: if I have 401, 404, and 200 how can I set my response messages? I cannot find a way to manipulate multiple HTTP responses. Two at most.

Actix-web provides you with a helper trait for handling errors where you can set the corresponding status code: Errors | Actix

Where is the status_code variable in your endpoint coming from? Don't you decide what it is? You can match multiple patterns in one match arm with |, i.e. 401 | 402 => {}.

I want to get the status with actix_web::HttpResponse.status() and then matching them like this:

let mut err: HttpError = HttpError::default();
let mut code: HttpResponse = HttpResponse::new(StatusCode::BAD_GATEWAY);
let code = code.status();

match code {
        StatusCode::OK => HttpResponse::Ok().json(vec),
        StatusCode::UNAUTHORIZED => err.error_response(),
        _ => HttpResponse::BadGateway().body("Cannot handle request")
    }

But that does not return my expected fancy Response message like:

impl actix_web::error::ResponseError for HttpError {
    fn status_code(&self) -> StatusCode {
        match self.error_type {
            ErrorResponse::NotFound => StatusCode::NOT_FOUND,
            ErrorResponse::Unauthorized => StatusCode::UNAUTHORIZED,
            ErrorResponse::BadRequest => StatusCode::BAD_REQUEST,
            ErrorResponse::Forbidden => StatusCode::FORBIDDEN,
            ErrorResponse::UnprocessableContent => StatusCode::UNPROCESSABLE_ENTITY,
            ErrorResponse::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR,
            ErrorResponse::BadGateway => StatusCode::BAD_GATEWAY
        }
    }
    fn error_response(&self) -> HttpResponse<BoxBody> {
        HttpResponse::build(self.status_code())
            .json(Self {
                cause: self.cause.clone(),
                message: self.message.clone(),
                status_code: self.status_code.to_string(),
                error_type: self.error_type.clone(),
            })
    }
}

I still get this:

Screenshot from 2024-05-02 12-07-17

Using the Doc link from @firebits.io helped to create the custom error.

And the Middleware is necessary for the error message if there is no JWT passed @jofas

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.