1use aonyx_core::AonyxError;
9use axum::http::StatusCode;
10use axum::response::{IntoResponse, Response};
11use axum::Json;
12use serde_json::json;
13
14pub type ApiResult<T> = std::result::Result<T, ApiError>;
16
17#[derive(Debug, thiserror::Error)]
20pub enum ApiError {
21 #[error("{0}")]
23 Unauthorized(String),
24
25 #[error("{0}")]
28 Forbidden(String),
29
30 #[error("{0}")]
32 BadRequest(String),
33
34 #[error("{0}")]
36 NotFound(String),
37
38 #[error("{0}")]
40 Internal(String),
41}
42
43impl ApiError {
44 fn parts(&self) -> (StatusCode, &'static str) {
46 match self {
47 ApiError::Unauthorized(_) => (StatusCode::UNAUTHORIZED, "unauthorized"),
48 ApiError::Forbidden(_) => (StatusCode::FORBIDDEN, "forbidden"),
49 ApiError::BadRequest(_) => (StatusCode::BAD_REQUEST, "bad_request"),
50 ApiError::NotFound(_) => (StatusCode::NOT_FOUND, "not_found"),
51 ApiError::Internal(_) => (StatusCode::INTERNAL_SERVER_ERROR, "internal"),
52 }
53 }
54}
55
56impl IntoResponse for ApiError {
57 fn into_response(self) -> Response {
58 let (status, ty) = self.parts();
59 let body = Json(json!({ "error": { "type": ty, "message": self.to_string() } }));
60 (status, body).into_response()
61 }
62}
63
64impl From<AonyxError> for ApiError {
65 fn from(e: AonyxError) -> Self {
66 match e {
67 AonyxError::Config(m) => ApiError::BadRequest(m),
68 AonyxError::ApprovalRejected(m) => ApiError::Forbidden(m),
69 other => ApiError::Internal(other.to_string()),
70 }
71 }
72}