#[derive(thiserror::Error, Debug)] pub enum Error { #[error("Database error: {0}")] Sqlx(#[from] sqlx::Error), #[error("Route not found: {0}")] RouteNotFound(axum::http::Uri), #[error("User not found")] UserNotFound, #[error("Required header not found: {0}")] HeaderNotFound(axum::http::HeaderName), #[error("Failed to parse header: {0} (wrong token type?)")] Header(axum_extra::typed_header::TypedHeaderRejection), #[error("Invalid user token")] InvalidToken, #[error("User with that email already exists")] EmailExists, #[error("Invalid email: {0}")] EmailInvalid(#[from] email_address::Error), #[error("Failed to reach authentication server: {0}")] AuthRequest(#[from] axum::http::Error), #[error("Not authorization values found")] Unauthorized, #[error("Authentication error: {0}")] Auth(#[from] crate::auth::error::Error), } impl From for Error { fn from(value: axum_extra::typed_header::TypedHeaderRejection) -> Self { if value.is_missing() { Self::HeaderNotFound(value.name().clone()) } else { Self::Header(value) } } } impl axum::response::IntoResponse for Error { fn into_response(self) -> axum::response::Response { use axum::http::header::AUTHORIZATION; use axum::http::StatusCode; let status = match self { Self::RouteNotFound(_) | Self::UserNotFound => StatusCode::NOT_FOUND, Self::EmailExists => StatusCode::CONFLICT, Self::InvalidToken | Self::Unauthorized => StatusCode::UNAUTHORIZED, Self::HeaderNotFound(ref h) if h == AUTHORIZATION => StatusCode::UNAUTHORIZED, Self::HeaderNotFound(_) => StatusCode::BAD_REQUEST, Self::EmailInvalid(_) | Self::Header(_) => StatusCode::UNPROCESSABLE_ENTITY, Self::AuthRequest(_) | Self::Sqlx(_) => StatusCode::INTERNAL_SERVER_ERROR, Self::Auth(err) => return err.into_response(), }; (status, self.to_string()).into_response() } }