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