101 lines
2.6 KiB
Rust
101 lines
2.6 KiB
Rust
|
use actix_web::{
|
||
|
dev::HttpResponseBuilder,
|
||
|
http::StatusCode,
|
||
|
HttpResponse,
|
||
|
error::ResponseError,
|
||
|
};
|
||
|
use serde::Serialize;
|
||
|
|
||
|
#[derive(thiserror::Error, Debug)]
|
||
|
#[error("conversion error")]
|
||
|
pub struct ConversionError;
|
||
|
|
||
|
#[derive(thiserror::Error, Debug)]
|
||
|
#[error("{0}")]
|
||
|
pub struct ValidationError(pub &'static str);
|
||
|
|
||
|
#[derive(thiserror::Error, Debug)]
|
||
|
pub enum DatabaseError {
|
||
|
#[error("database pool error")]
|
||
|
DatabasePoolError(#[from] deadpool_postgres::PoolError),
|
||
|
|
||
|
#[error("database client error")]
|
||
|
DatabaseClientError(#[from] tokio_postgres::Error),
|
||
|
|
||
|
#[error("database type error")]
|
||
|
DatabaseTypeError(#[from] ConversionError),
|
||
|
|
||
|
#[error("{0}")]
|
||
|
NotFound(&'static str), // object type
|
||
|
|
||
|
#[error("{0}")]
|
||
|
AlreadyExists(&'static str), // object type
|
||
|
}
|
||
|
|
||
|
#[derive(thiserror::Error, Debug)]
|
||
|
pub enum HttpError {
|
||
|
#[error(transparent)]
|
||
|
ActixError(#[from] actix_web::Error),
|
||
|
|
||
|
#[error("database error")]
|
||
|
DatabaseError(#[source] DatabaseError),
|
||
|
|
||
|
#[error("{0}")]
|
||
|
ValidationError(String),
|
||
|
|
||
|
#[error("{0}")]
|
||
|
ValidationErrorAuto(#[from] ValidationError),
|
||
|
|
||
|
#[error("{0}")]
|
||
|
SessionError(&'static str),
|
||
|
|
||
|
#[error("permission error")]
|
||
|
PermissionError,
|
||
|
|
||
|
#[error("{0} not found")]
|
||
|
NotFoundError(&'static str),
|
||
|
|
||
|
#[error("operation not supported")]
|
||
|
NotSupported,
|
||
|
|
||
|
#[error("internal error")]
|
||
|
InternalError,
|
||
|
}
|
||
|
|
||
|
impl From<DatabaseError> for HttpError {
|
||
|
fn from(err: DatabaseError) -> Self {
|
||
|
match err {
|
||
|
DatabaseError::NotFound(name) => HttpError::NotFoundError(name),
|
||
|
DatabaseError::AlreadyExists(name) => HttpError::ValidationError(
|
||
|
format!("{} already exists", name),
|
||
|
),
|
||
|
_ => HttpError::DatabaseError(err),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[derive(Serialize)]
|
||
|
struct ErrorInfo {
|
||
|
message: String,
|
||
|
}
|
||
|
|
||
|
impl ResponseError for HttpError {
|
||
|
fn error_response(&self) -> HttpResponse {
|
||
|
let err = ErrorInfo { message: self.to_string() };
|
||
|
HttpResponseBuilder::new(self.status_code()).json(err)
|
||
|
}
|
||
|
|
||
|
fn status_code(&self) -> StatusCode {
|
||
|
match self {
|
||
|
HttpError::ActixError(err) => err.as_response_error().status_code(),
|
||
|
HttpError::ValidationError(_) => StatusCode::BAD_REQUEST,
|
||
|
HttpError::ValidationErrorAuto(_) => StatusCode::BAD_REQUEST,
|
||
|
HttpError::SessionError(_) => StatusCode::UNAUTHORIZED,
|
||
|
HttpError::PermissionError => StatusCode::FORBIDDEN,
|
||
|
HttpError::NotFoundError(_) => StatusCode::NOT_FOUND,
|
||
|
HttpError::NotSupported => StatusCode::IM_A_TEAPOT,
|
||
|
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||
|
}
|
||
|
}
|
||
|
}
|