diff --git a/backend/sync_server/src/errors.rs b/backend/sync_server/src/errors.rs index 4f36824..ff6ff3c 100644 --- a/backend/sync_server/src/errors.rs +++ b/backend/sync_server/src/errors.rs @@ -2,7 +2,11 @@ use aide::OperationOutput; use axum::{ http::StatusCode, response::{IntoResponse, Response}, + Json, }; +use log::{info, warn}; +use schemars::JsonSchema; +use serde::Serialize; use thiserror::Error; #[derive(Error, Debug)] @@ -10,33 +14,70 @@ pub enum SyncServerError { #[error("Initialisation error: {0}")] InitError(#[source] anyhow::Error), - #[error("Client error: {0}")] + #[error("Client error: {0:?}")] ClientError(#[source] anyhow::Error), - #[error("Server error: {0}")] + #[error("Server error: {0:?}")] ServerError(#[source] anyhow::Error), #[error("Not found: {0}")] NotFound(#[source] anyhow::Error), - #[error("Permission denier error: {0}")] + #[error("Unauthorized: {0}")] + Unauthorized(#[source] anyhow::Error), + + #[error("Permission denied error: {0}")] PermissionDeniedError(#[source] anyhow::Error), } +impl SyncServerError { + pub fn serialize(&self) -> SerializedError { + match self { + Self::InitError(error) => format_anyhow_error(error), + Self::ClientError(error) => format_anyhow_error(error), + Self::ServerError(error) => format_anyhow_error(error), + Self::NotFound(error) => format_anyhow_error(error), + Self::Unauthorized(error) => format_anyhow_error(error), + Self::PermissionDeniedError(error) => format_anyhow_error(error), + } + } +} + impl IntoResponse for SyncServerError { fn into_response(self) -> Response { - let body = self.to_string(); + let body = Json(self.serialize()); match self { Self::InitError(_) => (StatusCode::INTERNAL_SERVER_ERROR, body).into_response(), Self::ClientError(_) => (StatusCode::BAD_REQUEST, body).into_response(), Self::ServerError(_) => (StatusCode::INTERNAL_SERVER_ERROR, body).into_response(), Self::NotFound(_) => (StatusCode::NOT_FOUND, body).into_response(), + Self::Unauthorized(_) => (StatusCode::UNAUTHORIZED, body).into_response(), Self::PermissionDeniedError(_) => (StatusCode::FORBIDDEN, body).into_response(), } } } +#[derive(Debug, Clone, Serialize, JsonSchema)] +pub struct SerializedError { + pub message: String, + pub causes: Vec, +} + +fn format_anyhow_error(error: &anyhow::Error) -> SerializedError { + let mut causes = vec![]; + let mut current_error = error.source(); + while let Some(error) = current_error { + causes.push(error.to_string()); + current_error = error.source(); + } + + SerializedError { + message: error.to_string(), + causes, + } +} + impl OperationOutput for SyncServerError { type Inner = Self; } @@ -46,17 +87,26 @@ pub fn init_error(error: anyhow::Error) -> SyncServerError { } pub fn server_error(error: anyhow::Error) -> SyncServerError { + warn!("Server error: {:?}", error); SyncServerError::ServerError(error) } pub fn client_error(error: anyhow::Error) -> SyncServerError { + info!("Client error: {:?}", error); SyncServerError::ClientError(error) } pub fn not_found_error(error: anyhow::Error) -> SyncServerError { + info!("Not found error: {:?}", error); SyncServerError::NotFound(error) } +pub fn unauthorized_error(error: anyhow::Error) -> SyncServerError { + info!("Unauthorized error: {:?}", error); + SyncServerError::Unauthorized(error) +} + pub fn permission_denied_error(error: anyhow::Error) -> SyncServerError { + info!("Permission denied error: {:?}", error); SyncServerError::PermissionDeniedError(error) }