use actix_web::{error::ResponseError, http::StatusCode, HttpResponse}; use deadpool_postgres::PoolError; use serde::Serialize; use std::fmt; use tokio_postgres::error::Error; #[derive(Debug, Eq, PartialEq)] pub enum AppErrorType { DbError, NotFoundError, AuthorizationError, GitError, } #[derive(Debug)] pub struct AppError { pub message: Option, pub cause: Option, pub error_type: AppErrorType, } impl AppError { pub fn message(&self) -> String { match &*self { AppError { message: Some(message), .. } => message.clone(), AppError { message: None, error_type: AppErrorType::NotFoundError, .. } => "The requested item was not found".to_string(), _ => "An unexpected error has occurred".to_string(), } } } impl From for AppError { fn from(error: PoolError) -> AppError { AppError { message: None, cause: Some(error.to_string()), error_type: AppErrorType::DbError, } } } impl From for AppError { fn from(error: Error) -> AppError { AppError { message: None, cause: Some(error.to_string()), error_type: AppErrorType::DbError, } } } impl fmt::Display for AppError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:?}", self) } } #[derive(Serialize)] pub struct AppErrorResponse { pub detail: String, } impl ResponseError for AppError { fn status_code(&self) -> StatusCode { match self.error_type { AppErrorType::DbError => StatusCode::INTERNAL_SERVER_ERROR, AppErrorType::NotFoundError => StatusCode::NOT_FOUND, AppErrorType::AuthorizationError => StatusCode::UNAUTHORIZED, AppErrorType::GitError => StatusCode::BAD_REQUEST, } } /// Returns a JSON response with "detail" as key fn error_response(&self) -> HttpResponse { HttpResponse::build(self.status_code()).json(AppErrorResponse { detail: self.message(), }) } }