aboutsummaryrefslogtreecommitdiff
path: root/src/api/common_error.rs
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2022-05-13 14:30:30 +0200
committerAlex Auvolat <alex@adnab.me>2022-05-13 14:30:30 +0200
commitc0fb9fd0fe553e5eda39dcb1a09f059bcd631b6c (patch)
tree4d73c67a540e032190543fc319fad12c409e1e16 /src/api/common_error.rs
parent983037d965fdcdf089b09fa90fac31501defae9e (diff)
downloadgarage-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.rs108
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(),
+ ))),
+ }
+ }
+}