diff options
author | Alex Auvolat <alex@adnab.me> | 2022-05-13 14:30:30 +0200 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2022-05-13 14:30:30 +0200 |
commit | c0fb9fd0fe553e5eda39dcb1a09f059bcd631b6c (patch) | |
tree | 4d73c67a540e032190543fc319fad12c409e1e16 /src/api/common_error.rs | |
parent | 983037d965fdcdf089b09fa90fac31501defae9e (diff) | |
download | garage-c0fb9fd0fe553e5eda39dcb1a09f059bcd631b6c.tar.gz garage-c0fb9fd0fe553e5eda39dcb1a09f059bcd631b6c.zip |
Common error type and admin error type that uses it
Diffstat (limited to 'src/api/common_error.rs')
-rw-r--r-- | src/api/common_error.rs | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/api/common_error.rs b/src/api/common_error.rs new file mode 100644 index 00000000..8be85f97 --- /dev/null +++ b/src/api/common_error.rs @@ -0,0 +1,108 @@ +use err_derive::Error; +use hyper::header::HeaderValue; +use hyper::{Body, HeaderMap, StatusCode}; + +use garage_model::helper::error::Error as HelperError; +use garage_util::error::Error as GarageError; + +use crate::generic_server::ApiError; + +/// Errors of this crate +#[derive(Debug, Error)] +pub enum CommonError { + // Category: internal error + /// Error related to deeper parts of Garage + #[error(display = "Internal error: {}", _0)] + InternalError(#[error(source)] GarageError), + + /// Error related to Hyper + #[error(display = "Internal error (Hyper error): {}", _0)] + Hyper(#[error(source)] hyper::Error), + + /// Error related to HTTP + #[error(display = "Internal error (HTTP error): {}", _0)] + Http(#[error(source)] http::Error), + + /// The client sent an invalid request + #[error(display = "Bad request: {}", _0)] + BadRequest(String), +} + +impl CommonError { + pub fn http_status_code(&self) -> StatusCode { + match self { + CommonError::InternalError( + GarageError::Timeout + | GarageError::RemoteError(_) + | GarageError::Quorum(_, _, _, _), + ) => StatusCode::SERVICE_UNAVAILABLE, + CommonError::InternalError(_) | CommonError::Hyper(_) | CommonError::Http(_) => + StatusCode::INTERNAL_SERVER_ERROR, + CommonError::BadRequest(_) => StatusCode::BAD_REQUEST, + } + } +} + +/// Trait to map error to the Bad Request error code +pub trait OkOrBadRequest { + type S; + fn ok_or_bad_request<M: AsRef<str>>(self, reason: M) -> Result<Self::S, CommonError>; +} + +impl<T, E> OkOrBadRequest for Result<T, E> +where + E: std::fmt::Display, +{ + type S = T; + fn ok_or_bad_request<M: AsRef<str>>(self, reason: M) -> Result<T, CommonError> { + match self { + Ok(x) => Ok(x), + Err(e) => Err(CommonError::BadRequest(format!("{}: {}", reason.as_ref(), e))), + } + } +} + +impl<T> OkOrBadRequest for Option<T> { + type S = T; + fn ok_or_bad_request<M: AsRef<str>>(self, reason: M) -> Result<T, CommonError> { + match self { + Some(x) => Ok(x), + None => Err(CommonError::BadRequest(reason.as_ref().to_string())), + } + } +} + +/// Trait to map an error to an Internal Error code +pub trait OkOrInternalError { + type S; + fn ok_or_internal_error<M: AsRef<str>>(self, reason: M) -> Result<Self::S, CommonError>; +} + +impl<T, E> OkOrInternalError for Result<T, E> +where + E: std::fmt::Display, +{ + type S = T; + fn ok_or_internal_error<M: AsRef<str>>(self, reason: M) -> Result<T, CommonError> { + match self { + Ok(x) => Ok(x), + Err(e) => Err(CommonError::InternalError(GarageError::Message(format!( + "{}: {}", + reason.as_ref(), + e + )))), + } + } +} + +impl<T> OkOrInternalError for Option<T> { + type S = T; + fn ok_or_internal_error<M: AsRef<str>>(self, reason: M) -> Result<T, CommonError> { + match self { + Some(x) => Ok(x), + None => Err(CommonError::InternalError(GarageError::Message( + reason.as_ref().to_string(), + ))), + } + } +} |