Skip to main content

vk_bot_api/
error.rs

1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum VkError {
5    #[error("HTTP request failed: {0}")]
6    HttpError(#[from] reqwest::Error),
7
8    #[error("VK API error {code}: {message}")]
9    ApiError { code: i32, message: String },
10
11    #[error("Invalid response format: {0}")]
12    InvalidResponse(String),
13
14    #[error("JSON error: {0}")]
15    JsonError(#[from] serde_json::Error),
16
17    #[error("Missing required field: {0}")]
18    MissingField(String),
19
20    #[error("Rate limit exceeded")]
21    RateLimit,
22
23    #[error("Authentication error: {0}")]
24    AuthError(String),
25
26    #[error("Network error: {0}")]
27    NetworkError(String),
28
29    #[error("Timeout error: {0}")]
30    Timeout(String),
31
32    #[error("Configuration error: {0}")]
33    ConfigError(String),
34
35    #[error("Internal error: {0}")]
36    InternalError(String),
37
38    #[error("{0}")]
39    Custom(String),
40}
41
42impl VkError {
43    pub fn api_error<T: Into<i32>, M: Into<String>>(code: T, message: M) -> Self {
44        VkError::ApiError {
45            code: code.into(),
46            message: message.into(),
47        }
48    }
49
50    pub fn is_rate_limit(&self) -> bool {
51        matches!(self, VkError::RateLimit)
52    }
53
54    pub fn is_api_error(&self) -> bool {
55        matches!(self, VkError::ApiError { .. })
56    }
57
58    pub fn api_error_code(&self) -> Option<i32> {
59        match self {
60            VkError::ApiError { code, .. } => Some(*code),
61            _ => None,
62        }
63    }
64}
65
66pub type VkResult<T> = Result<T, VkError>;
67
68impl From<&str> for VkError {
69    fn from(s: &str) -> Self {
70        VkError::Custom(s.to_string())
71    }
72}
73
74impl From<String> for VkError {
75    fn from(s: String) -> Self {
76        VkError::Custom(s)
77    }
78}
79
80pub trait VkResponseExt {
81    fn extract_error(self) -> VkResult<serde_json::Value>;
82    fn has_error(&self) -> bool;
83}
84
85impl VkResponseExt for serde_json::Value {
86    fn extract_error(self) -> VkResult<serde_json::Value> {
87        if let Some(error) = self.get("error") {
88            let code = error["error_code"]
89                .as_i64()
90                .ok_or_else(|| VkError::InvalidResponse("Missing error_code".to_string()))?;
91
92            let message = error["error_msg"]
93                .as_str()
94                .ok_or_else(|| VkError::InvalidResponse("Missing error_msg".to_string()))?
95                .to_string();
96
97            Err(VkError::api_error(code as i32, message))
98        } else {
99            Ok(self)
100        }
101    }
102
103    fn has_error(&self) -> bool {
104        self.get("error").is_some()
105    }
106}