llm_edge_proxy/
error.rs

1use axum::{
2    http::StatusCode,
3    response::{IntoResponse, Response},
4    Json,
5};
6use serde::Serialize;
7use thiserror::Error;
8
9#[derive(Error, Debug)]
10pub enum ProxyError {
11    #[error("HTTP error: {0}")]
12    Http(#[from] hyper::Error),
13
14    #[error("Configuration error: {0}")]
15    Config(String),
16
17    #[error("Authentication failed: {0}")]
18    Authentication(String),
19
20    #[error("Rate limit exceeded: {0}")]
21    RateLimit(String),
22
23    #[error("Validation error: {0}")]
24    Validation(String),
25
26    #[error("Request timeout")]
27    Timeout,
28
29    #[error("Bad request: {0}")]
30    BadRequest(String),
31
32    #[error("Invalid request: {0}")]
33    InvalidRequest(String),
34
35    #[error("Internal error: {0}")]
36    Internal(String),
37
38    #[error("Service unavailable: {0}")]
39    ServiceUnavailable(String),
40}
41
42/// Error response structure
43#[derive(Serialize)]
44pub struct ErrorResponse {
45    pub error: ErrorDetail,
46}
47
48#[derive(Serialize)]
49pub struct ErrorDetail {
50    pub code: String,
51    pub message: String,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub details: Option<serde_json::Value>,
54}
55
56impl ProxyError {
57    fn error_code(&self) -> &str {
58        match self {
59            ProxyError::Http(_) => "HTTP_ERROR",
60            ProxyError::Config(_) => "CONFIG_ERROR",
61            ProxyError::Authentication(_) => "AUTH_ERROR",
62            ProxyError::RateLimit(_) => "RATE_LIMIT_EXCEEDED",
63            ProxyError::Validation(_) => "VALIDATION_ERROR",
64            ProxyError::Timeout => "TIMEOUT",
65            ProxyError::BadRequest(_) => "BAD_REQUEST",
66            ProxyError::InvalidRequest(_) => "INVALID_REQUEST",
67            ProxyError::Internal(_) => "INTERNAL_ERROR",
68            ProxyError::ServiceUnavailable(_) => "SERVICE_UNAVAILABLE",
69        }
70    }
71
72    fn status_code(&self) -> StatusCode {
73        match self {
74            ProxyError::Http(_) => StatusCode::BAD_GATEWAY,
75            ProxyError::Config(_) => StatusCode::INTERNAL_SERVER_ERROR,
76            ProxyError::Authentication(_) => StatusCode::UNAUTHORIZED,
77            ProxyError::RateLimit(_) => StatusCode::TOO_MANY_REQUESTS,
78            ProxyError::Validation(_) => StatusCode::BAD_REQUEST,
79            ProxyError::Timeout => StatusCode::GATEWAY_TIMEOUT,
80            ProxyError::BadRequest(_) => StatusCode::BAD_REQUEST,
81            ProxyError::InvalidRequest(_) => StatusCode::BAD_REQUEST,
82            ProxyError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
83            ProxyError::ServiceUnavailable(_) => StatusCode::SERVICE_UNAVAILABLE,
84        }
85    }
86}
87
88impl IntoResponse for ProxyError {
89    fn into_response(self) -> Response {
90        let status = self.status_code();
91        let error_response = ErrorResponse {
92            error: ErrorDetail {
93                code: self.error_code().to_string(),
94                message: self.to_string(),
95                details: None,
96            },
97        };
98
99        (status, Json(error_response)).into_response()
100    }
101}
102
103// Implement From conversions for common error types
104impl From<std::io::Error> for ProxyError {
105    fn from(err: std::io::Error) -> Self {
106        ProxyError::Internal(err.to_string())
107    }
108}
109
110impl From<serde_json::Error> for ProxyError {
111    fn from(err: serde_json::Error) -> Self {
112        ProxyError::BadRequest(err.to_string())
113    }
114}
115
116pub type ProxyResult<T> = Result<T, ProxyError>;