dceapi_rs/
error.rs

1//! Error types for the DCE API client.
2//!
3//! This module provides error handling following the API specification:
4//! - 200: Success
5//! - 400: Parameter error
6//! - 401: Permission denied
7//! - 402: Token expired
8//! - 500: Server error
9//! - 501: Rate limit
10
11use thiserror::Error;
12
13/// API error codes as defined by the DCE API.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[repr(i32)]
16pub enum ErrorCode {
17    /// 200: Success
18    Success = 200,
19    /// 400: Parameter error
20    ParamError = 400,
21    /// 401: Permission denied
22    NoPermission = 401,
23    /// 402: Token expired
24    TokenExpired = 402,
25    /// 500: Internal server error
26    ServerError = 500,
27    /// 501: Rate limit exceeded
28    RateLimit = 501,
29}
30
31impl ErrorCode {
32    /// Create ErrorCode from i32 value.
33    pub fn from_code(code: i32) -> Option<ErrorCode> {
34        match code {
35            200 => Some(ErrorCode::Success),
36            400 => Some(ErrorCode::ParamError),
37            401 => Some(ErrorCode::NoPermission),
38            402 => Some(ErrorCode::TokenExpired),
39            500 => Some(ErrorCode::ServerError),
40            501 => Some(ErrorCode::RateLimit),
41            _ => None,
42        }
43    }
44}
45
46/// The main error type for the DCE API client.
47#[derive(Error, Debug)]
48pub enum Error {
49    /// API returned an error response.
50    #[error("API error {code}: {message}")]
51    Api {
52        /// The error code from the API.
53        code: i32,
54        /// The error message from the API.
55        message: String,
56    },
57
58    /// Authentication failed.
59    #[error("authentication error: {reason}")]
60    Auth {
61        /// The reason for the authentication failure.
62        reason: String,
63    },
64
65    /// Network or HTTP error.
66    #[error("network error: {0}")]
67    Network(#[from] reqwest::Error),
68
69    /// Validation error for request parameters.
70    #[error("validation error on field '{field}': {message}")]
71    Validation {
72        /// The field that failed validation.
73        field: String,
74        /// The validation error message.
75        message: String,
76    },
77
78    /// JSON parsing error.
79    #[error("parse error: {err}, raw response: {raw_response}")]
80    Parse {
81        /// The raw response that failed to parse.
82        raw_response: String,
83        /// The parsing error.
84        err: String,
85    },
86}
87
88impl Error {
89    /// Create a new API error.
90    pub fn api(code: i32, message: impl Into<String>) -> Self {
91        Error::Api {
92            code,
93            message: message.into(),
94        }
95    }
96
97    /// Create a new authentication error.
98    pub fn auth(reason: impl Into<String>) -> Self {
99        Error::Auth {
100            reason: reason.into(),
101        }
102    }
103
104    /// Create a new validation error.
105    pub fn validation(field: impl Into<String>, message: impl Into<String>) -> Self {
106        Error::Validation {
107            field: field.into(),
108            message: message.into(),
109        }
110    }
111
112    /// Create a new parse error.
113    pub fn parse(raw_response: impl Into<String>, err: impl Into<String>) -> Self {
114        Error::Parse {
115            raw_response: raw_response.into(),
116            err: err.into(),
117        }
118    }
119
120    /// Check if this is a token expired error.
121    pub fn is_token_expired(&self) -> bool {
122        matches!(self, Error::Api { code, .. } if *code == ErrorCode::TokenExpired as i32)
123    }
124
125    /// Get the error code if this is an API error.
126    pub fn error_code(&self) -> Option<ErrorCode> {
127        if let Error::Api { code, .. } = self {
128            ErrorCode::from_code(*code)
129        } else {
130            None
131        }
132    }
133}
134
135/// Result type alias for DCE API operations.
136pub type Result<T> = std::result::Result<T, Error>;