1use axum::{
2 http::StatusCode,
3 response::{IntoResponse, Response},
4 Json,
5};
6use serde_json::json;
7use thiserror::Error;
8
9#[cfg(feature = "rust-bitcoin")]
10use crate::bitcoin::error::BitcoinError;
11
12#[derive(Error, Debug)]
13pub enum ApiError {
14 #[error("Authentication required: {0}")]
15 AuthenticationRequired(String),
16
17 #[error("Authorization failed: {0}")]
18 AuthorizationFailed(String),
19
20 #[error("Resource not found: {0}")]
21 NotFound(String),
22
23 #[error("Invalid request: {0}")]
24 BadRequest(String),
25
26 #[cfg(feature = "rust-bitcoin")]
27 #[error("Bitcoin operation failed: {0}")]
28 BitcoinError(#[from] BitcoinError),
29
30 #[error("Internal server error: {0}")]
31 InternalError(String),
32}
33
34impl IntoResponse for ApiError {
35 fn into_response(self) -> Response {
36 let (status, error_message) = match self {
37 ApiError::AuthenticationRequired(msg) => (StatusCode::UNAUTHORIZED, msg),
38 ApiError::AuthorizationFailed(msg) => (StatusCode::FORBIDDEN, msg),
39 ApiError::NotFound(msg) => (StatusCode::NOT_FOUND, msg),
40 ApiError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
41 #[cfg(feature = "rust-bitcoin")]
42 ApiError::BitcoinError(e) => match e {
43 BitcoinError::WalletNotFound(_) => (StatusCode::NOT_FOUND, e.to_string()),
44 BitcoinError::InvalidAddress(_) => (StatusCode::BAD_REQUEST, e.to_string()),
45 BitcoinError::InsufficientFunds => (StatusCode::BAD_REQUEST, e.to_string()),
46 _ => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
47 },
48 ApiError::InternalError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
49 };
50
51 let body = Json(json!({
52 "success": false,
53 "message": error_message
54 }));
55
56 (status, body).into_response()
57 }
58}