this repo has no description
1use axum::{ 2 Json, 3 http::StatusCode, 4 response::{IntoResponse, Response}, 5}; 6use serde::Serialize; 7 8#[derive(Debug, Serialize)] 9struct ErrorBody { 10 error: &'static str, 11 #[serde(skip_serializing_if = "Option::is_none")] 12 message: Option<String>, 13} 14 15#[derive(Debug)] 16pub enum ApiError { 17 InternalError, 18 AuthenticationRequired, 19 AuthenticationFailed, 20 AuthenticationFailedMsg(String), 21 InvalidRequest(String), 22 InvalidToken, 23 ExpiredToken, 24 ExpiredTokenMsg(String), 25 TokenRequired, 26 AccountDeactivated, 27 AccountTakedown, 28 AccountNotFound, 29 RepoNotFound, 30 RepoNotFoundMsg(String), 31 RecordNotFound, 32 BlobNotFound, 33 InvalidHandle, 34 HandleNotAvailable, 35 HandleTaken, 36 InvalidEmail, 37 EmailTaken, 38 InvalidInviteCode, 39 DuplicateCreate, 40 DuplicateAppPassword, 41 AppPasswordNotFound, 42 InvalidSwap, 43 Forbidden, 44 InvitesDisabled, 45 DatabaseError, 46 UpstreamFailure, 47} 48 49impl ApiError { 50 fn status_code(&self) -> StatusCode { 51 match self { 52 Self::InternalError | Self::DatabaseError | Self::UpstreamFailure => { 53 StatusCode::INTERNAL_SERVER_ERROR 54 } 55 Self::AuthenticationRequired 56 | Self::AuthenticationFailed 57 | Self::AuthenticationFailedMsg(_) 58 | Self::InvalidToken 59 | Self::ExpiredToken 60 | Self::ExpiredTokenMsg(_) 61 | Self::TokenRequired 62 | Self::AccountDeactivated 63 | Self::AccountTakedown => StatusCode::UNAUTHORIZED, 64 Self::Forbidden | Self::InvitesDisabled => StatusCode::FORBIDDEN, 65 Self::AccountNotFound 66 | Self::RepoNotFound 67 | Self::RepoNotFoundMsg(_) 68 | Self::RecordNotFound 69 | Self::BlobNotFound 70 | Self::AppPasswordNotFound => StatusCode::NOT_FOUND, 71 Self::InvalidRequest(_) 72 | Self::InvalidHandle 73 | Self::HandleNotAvailable 74 | Self::HandleTaken 75 | Self::InvalidEmail 76 | Self::EmailTaken 77 | Self::InvalidInviteCode 78 | Self::DuplicateCreate 79 | Self::DuplicateAppPassword 80 | Self::InvalidSwap => StatusCode::BAD_REQUEST, 81 } 82 } 83 84 fn error_name(&self) -> &'static str { 85 match self { 86 Self::InternalError | Self::DatabaseError | Self::UpstreamFailure => "InternalError", 87 Self::AuthenticationRequired => "AuthenticationRequired", 88 Self::AuthenticationFailed | Self::AuthenticationFailedMsg(_) => "AuthenticationFailed", 89 Self::InvalidToken => "InvalidToken", 90 Self::ExpiredToken | Self::ExpiredTokenMsg(_) => "ExpiredToken", 91 Self::TokenRequired => "TokenRequired", 92 Self::AccountDeactivated => "AccountDeactivated", 93 Self::AccountTakedown => "AccountTakedown", 94 Self::Forbidden => "Forbidden", 95 Self::InvitesDisabled => "InvitesDisabled", 96 Self::AccountNotFound => "AccountNotFound", 97 Self::RepoNotFound | Self::RepoNotFoundMsg(_) => "RepoNotFound", 98 Self::RecordNotFound => "RecordNotFound", 99 Self::BlobNotFound => "BlobNotFound", 100 Self::AppPasswordNotFound => "AppPasswordNotFound", 101 Self::InvalidRequest(_) => "InvalidRequest", 102 Self::InvalidHandle => "InvalidHandle", 103 Self::HandleNotAvailable => "HandleNotAvailable", 104 Self::HandleTaken => "HandleTaken", 105 Self::InvalidEmail => "InvalidEmail", 106 Self::EmailTaken => "EmailTaken", 107 Self::InvalidInviteCode => "InvalidInviteCode", 108 Self::DuplicateCreate => "DuplicateCreate", 109 Self::DuplicateAppPassword => "DuplicateAppPassword", 110 Self::InvalidSwap => "InvalidSwap", 111 } 112 } 113 114 fn message(&self) -> Option<String> { 115 match self { 116 Self::AuthenticationFailedMsg(msg) 117 | Self::ExpiredTokenMsg(msg) 118 | Self::InvalidRequest(msg) 119 | Self::RepoNotFoundMsg(msg) => Some(msg.clone()), 120 _ => None, 121 } 122 } 123} 124 125impl IntoResponse for ApiError { 126 fn into_response(self) -> Response { 127 let body = ErrorBody { 128 error: self.error_name(), 129 message: self.message(), 130 }; 131 (self.status_code(), Json(body)).into_response() 132 } 133} 134 135impl From<sqlx::Error> for ApiError { 136 fn from(e: sqlx::Error) -> Self { 137 tracing::error!("Database error: {:?}", e); 138 Self::DatabaseError 139 } 140} 141 142impl From<crate::auth::TokenValidationError> for ApiError { 143 fn from(e: crate::auth::TokenValidationError) -> Self { 144 match e { 145 crate::auth::TokenValidationError::AccountDeactivated => Self::AccountDeactivated, 146 crate::auth::TokenValidationError::AccountTakedown => Self::AccountTakedown, 147 crate::auth::TokenValidationError::KeyDecryptionFailed => Self::InternalError, 148 crate::auth::TokenValidationError::AuthenticationFailed => Self::AuthenticationFailed, 149 } 150 } 151} 152 153impl From<crate::util::DbLookupError> for ApiError { 154 fn from(e: crate::util::DbLookupError) -> Self { 155 match e { 156 crate::util::DbLookupError::NotFound => Self::AccountNotFound, 157 crate::util::DbLookupError::DatabaseError(db_err) => { 158 tracing::error!("Database error: {:?}", db_err); 159 Self::DatabaseError 160 } 161 } 162 } 163}