ggen_api/
error.rs

1//! API error types and handling
2
3use axum::{
4    http::StatusCode,
5    response::{IntoResponse, Response},
6    Json,
7};
8use serde_json::json;
9use thiserror::Error;
10
11#[derive(Error, Debug)]
12pub enum ApiError {
13    #[error("Unauthorized: {0}")]
14    Unauthorized(String),
15
16    #[error("Forbidden: {0}")]
17    Forbidden(String),
18
19    #[error("Not found: {0}")]
20    NotFound(String),
21
22    #[error("Bad request: {0}")]
23    BadRequest(String),
24
25    #[error("Conflict: {0}")]
26    Conflict(String),
27
28    #[error("Quota exceeded: {0}")]
29    QuotaExceeded(String),
30
31    #[error("Internal server error: {0}")]
32    InternalError(String),
33
34    #[error("Payment error: {0}")]
35    PaymentError(String),
36
37    #[error("Authentication failed: {0}")]
38    AuthenticationFailed(String),
39}
40
41impl IntoResponse for ApiError {
42    fn into_response(self) -> Response {
43        let (status, error_message) = match self {
44            ApiError::Unauthorized(msg) => (StatusCode::UNAUTHORIZED, msg),
45            ApiError::Forbidden(msg) => (StatusCode::FORBIDDEN, msg),
46            ApiError::NotFound(msg) => (StatusCode::NOT_FOUND, msg),
47            ApiError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
48            ApiError::Conflict(msg) => (StatusCode::CONFLICT, msg),
49            ApiError::QuotaExceeded(msg) => (StatusCode::PAYMENT_REQUIRED, msg),
50            ApiError::InternalError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
51            ApiError::PaymentError(msg) => (StatusCode::PAYMENT_REQUIRED, msg),
52            ApiError::AuthenticationFailed(msg) => (StatusCode::UNAUTHORIZED, msg),
53        };
54
55        let body = Json(json!({
56            "error": error_message,
57            "status": status.as_u16(),
58        }));
59
60        (status, body).into_response()
61    }
62}
63
64pub type ApiResult<T> = Result<T, ApiError>;