use axum::{Json, http::StatusCode, response::IntoResponse}; use thiserror::Error; use crate::{sync::SyncError, users::UserError}; // The AppError represents the different error types from upstream kosync server #[derive(Error, Debug)] pub enum AppError { #[error("Username already taken")] UsernameTaken, #[error("Unauthorized")] Unauthorized, #[error("Account not found")] AccountNotFound, #[error(transparent)] Internal(#[from] anyhow::Error), } impl From for AppError { fn from(value: UserError) -> Self { match value { UserError::UnknownError(error) => Self::Internal(error), UserError::UserAlreadyExists => Self::UsernameTaken, UserError::DatabaseFailure(error) => Self::Internal(error.into()), } } } impl From for AppError { fn from(value: SyncError) -> Self { match value { SyncError::DatabaseFailure(error) => Self::Internal(error.into()), } } } impl IntoResponse for AppError { fn into_response(self) -> axum::response::Response { let (status, error_code, msg) = match self { AppError::UsernameTaken => (StatusCode::PAYMENT_REQUIRED, 2002, "Username is already registered"), AppError::Internal(error) => { tracing::error!(err=?error, "Internal server error"); (StatusCode::INTERNAL_SERVER_ERROR, 2000, "Internal server error") }, AppError::Unauthorized => { (StatusCode::UNAUTHORIZED, 2001, "Unauthorized") } AppError::AccountNotFound => { (StatusCode::UNAUTHORIZED, 2006, "Account not found") } }; let body = serde_json::json!({ "code": error_code, "message": msg }); (status, Json(body)).into_response() } }