error.rs
1 use axum::http::StatusCode; 2 use axum::response::{IntoResponse, Response}; 3 use axum::Json; 4 use serde_json::json; 5 6 use radicle::git::raw::ErrorExt; 7 8 /// Errors relating to the API backend. 9 #[derive(Debug, thiserror::Error)] 10 pub enum Error { 11 /// The entity was not found. 12 #[error("entity not found")] 13 NotFound, 14 15 /// An error occurred with env variables. 16 #[error(transparent)] 17 Env(#[from] std::env::VarError), 18 19 /// Profile error. 20 #[error(transparent)] 21 Profile(#[from] radicle::profile::Error), 22 23 /// Crypto error. 24 #[error(transparent)] 25 Crypto(#[from] radicle::crypto::Error), 26 27 /// Storage error. 28 #[error(transparent)] 29 Storage(#[from] radicle::storage::Error), 30 31 /// Cob cache error. 32 #[error(transparent)] 33 CobCache(#[from] radicle::cob::cache::Error), 34 35 /// Cob issue cache error. 36 #[error(transparent)] 37 CacheIssue(#[from] radicle::cob::issue::cache::Error), 38 39 /// Cob issue error. 40 #[error(transparent)] 41 CobIssue(#[from] radicle::cob::issue::Error), 42 43 /// Cob patch error. 44 #[error(transparent)] 45 CobPatch(#[from] radicle::cob::patch::Error), 46 47 /// Cob patch cache error. 48 #[error(transparent)] 49 CachePatch(#[from] radicle::cob::patch::cache::Error), 50 51 /// Cob store error. 52 #[error(transparent)] 53 CobStore(#[from] radicle::cob::store::Error), 54 55 /// Repository error. 56 #[error(transparent)] 57 Repository(#[from] radicle::storage::RepositoryError), 58 59 /// Routing error. 60 #[error(transparent)] 61 Routing(#[from] radicle::node::routing::Error), 62 63 /// Project doc error. 64 #[error(transparent)] 65 ProjectDoc(#[from] radicle::identity::doc::PayloadError), 66 67 /// Surf directory error. 68 #[error(transparent)] 69 SurfDir(#[from] radicle_surf::fs::error::Directory), 70 71 /// Surf error. 72 #[error(transparent)] 73 Surf(#[from] radicle_surf::Error), 74 75 /// Git2 error. 76 #[error(transparent)] 77 Git2(#[from] radicle::git::raw::Error), 78 79 /// Storage refs error. 80 #[error(transparent)] 81 StorageRef(#[from] radicle::storage::refs::Error), 82 83 /// Identity doc error. 84 #[error(transparent)] 85 IdentityDoc(#[from] radicle::identity::doc::DocError), 86 87 /// Tracking store error. 88 #[error(transparent)] 89 TrackingStore(#[from] radicle::node::policy::store::Error), 90 91 /// Node database error. 92 #[error(transparent)] 93 Database(#[from] radicle::node::db::Error), 94 95 /// Node error. 96 #[error(transparent)] 97 Node(#[from] radicle::node::Error), 98 } 99 100 impl IntoResponse for Error { 101 fn into_response(self) -> Response { 102 let message = self.to_string(); 103 let (status, msg) = match self { 104 Error::NotFound => (StatusCode::NOT_FOUND, None), 105 Error::CobStore(e @ radicle::cob::store::Error::NotFound(_, _)) => { 106 (StatusCode::NOT_FOUND, Some(e.to_string())) 107 } 108 Error::Crypto(msg) => (StatusCode::BAD_REQUEST, Some(msg.to_string())), 109 Error::Surf(radicle_surf::Error::Git(e)) if e.is_not_found() => { 110 (StatusCode::NOT_FOUND, Some(e.message().to_owned())) 111 } 112 Error::Surf(radicle_surf::Error::Directory( 113 e @ radicle_surf::fs::error::Directory::PathNotFound(_), 114 )) => (StatusCode::NOT_FOUND, Some(e.to_string())), 115 Error::Git2(e) if e.is_not_found() => { 116 (StatusCode::NOT_FOUND, Some(e.message().to_owned())) 117 } 118 Error::Git2(e) => ( 119 StatusCode::INTERNAL_SERVER_ERROR, 120 Some(e.message().to_owned()), 121 ), 122 Error::Storage(err) if err.is_not_found() => { 123 (StatusCode::NOT_FOUND, Some(err.to_string())) 124 } 125 Error::Repository(err) if err.is_not_found() => { 126 (StatusCode::NOT_FOUND, Some(err.to_string())) 127 } 128 Error::StorageRef(err) if err.is_not_found() => { 129 (StatusCode::NOT_FOUND, Some(err.to_string())) 130 } 131 other => { 132 tracing::error!("Error: {message}"); 133 tracing::debug!("Error Debug: {:?}", other); 134 135 if cfg!(debug_assertions) { 136 (StatusCode::INTERNAL_SERVER_ERROR, Some(other.to_string())) 137 } else { 138 (StatusCode::INTERNAL_SERVER_ERROR, None) 139 } 140 } 141 }; 142 143 let body = Json(json!({ 144 "error": msg.or_else(|| status.canonical_reason().map(|r| r.to_string())), 145 "code": status.as_u16() 146 })); 147 148 (status, body).into_response() 149 } 150 }