Skip to main content

uapi_sdk_rust/
errors.rs

1use thiserror::Error;
2
3#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
4pub struct RateLimitPolicyEntry {
5    pub name: String,
6    pub quota: Option<i64>,
7    pub unit: Option<String>,
8    pub window_seconds: Option<u64>,
9}
10
11#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
12pub struct RateLimitStateEntry {
13    pub name: String,
14    pub remaining: Option<i64>,
15    pub unit: Option<String>,
16    pub reset_after_seconds: Option<u64>,
17}
18
19#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
20pub struct ResponseMeta {
21    pub request_id: Option<String>,
22    pub retry_after_seconds: Option<u64>,
23    pub debit_status: Option<String>,
24    pub credits_requested: Option<i64>,
25    pub credits_charged: Option<i64>,
26    pub credits_pricing: Option<String>,
27    pub active_quota_buckets: Option<u64>,
28    pub stop_on_empty: Option<bool>,
29    pub rate_limit_policy_raw: Option<String>,
30    pub rate_limit_raw: Option<String>,
31    pub rate_limit_policies: std::collections::BTreeMap<String, RateLimitPolicyEntry>,
32    pub rate_limits: std::collections::BTreeMap<String, RateLimitStateEntry>,
33    pub balance_limit_cents: Option<i64>,
34    pub balance_remaining_cents: Option<i64>,
35    pub quota_limit_credits: Option<i64>,
36    pub quota_remaining_credits: Option<i64>,
37    pub visitor_quota_limit_credits: Option<i64>,
38    pub visitor_quota_remaining_credits: Option<i64>,
39    pub raw_headers: std::collections::BTreeMap<String, String>,
40}
41
42#[derive(Debug, Error)]
43pub enum Error {
44    #[error("authentication failed (status {status})")]
45    AuthenticationError { status: u16, message: Option<String>, request_id: Option<String>, meta: Option<ResponseMeta> },
46
47    #[error("rate limited (status {status})")]
48    RateLimitError {
49        status: u16,
50        message: Option<String>,
51        retry_after_seconds: Option<u64>,
52        request_id: Option<String>,
53        meta: Option<ResponseMeta>,
54    },
55
56    #[error("insufficient credits (status {status})")]
57    InsufficientCredits {
58        status: u16,
59        message: Option<String>,
60        details: Option<serde_json::Value>,
61        request_id: Option<String>,
62        meta: Option<ResponseMeta>,
63    },
64
65    #[error("visitor monthly quota exhausted (status {status})")]
66    VisitorMonthlyQuotaExhausted {
67        status: u16,
68        message: Option<String>,
69        details: Option<serde_json::Value>,
70        request_id: Option<String>,
71        meta: Option<ResponseMeta>,
72    },
73
74    #[error("validation failed (status {status})")]
75    ValidationError { status: u16, message: Option<String>, details: Option<serde_json::Value>, request_id: Option<String>, meta: Option<ResponseMeta> },
76
77    #[error("resource not found (status {status})")]
78    NotFound { status: u16, message: Option<String>, request_id: Option<String>, meta: Option<ResponseMeta> },
79
80    #[error("server error (status {status})")]
81    ServerError { status: u16, message: Option<String>, request_id: Option<String>, meta: Option<ResponseMeta> },
82
83    #[error("api error (status {status})")]
84    ApiError {
85        status: u16,
86        code: Option<String>,
87        message: Option<String>,
88        details: Option<serde_json::Value>,
89        request_id: Option<String>,
90        meta: Option<ResponseMeta>,
91    },
92
93    #[error("invalid header `{name}`")]
94    InvalidHeader { name: String },
95
96    #[error(transparent)]
97    Transport(#[from] reqwest::Error),
98
99    #[error(transparent)]
100    Json(#[from] serde_json::Error),
101
102    #[error(transparent)]
103    Url(#[from] url::ParseError),
104}
105
106impl Error {
107    pub fn status(&self) -> Option<u16> {
108        use Error::*;
109        match self {
110            AuthenticationError { status, .. }
111            | RateLimitError { status, .. }
112            | InsufficientCredits { status, .. }
113            | VisitorMonthlyQuotaExhausted { status, .. }
114            | ValidationError { status, .. }
115            | NotFound { status, .. }
116            | ServerError { status, .. }
117            | ApiError { status, .. } => Some(*status),
118            _ => None,
119        }
120    }
121
122    pub fn request_id(&self) -> Option<&str> {
123        use Error::*;
124        match self {
125            AuthenticationError { request_id, .. }
126            | RateLimitError { request_id, .. }
127            | InsufficientCredits { request_id, .. }
128            | VisitorMonthlyQuotaExhausted { request_id, .. }
129            | ValidationError { request_id, .. }
130            | NotFound { request_id, .. }
131            | ServerError { request_id, .. }
132            | ApiError { request_id, .. } => request_id.as_deref(),
133            _ => None,
134        }
135    }
136
137    pub fn meta(&self) -> Option<&ResponseMeta> {
138        use Error::*;
139        match self {
140            AuthenticationError { meta, .. }
141            | RateLimitError { meta, .. }
142            | InsufficientCredits { meta, .. }
143            | VisitorMonthlyQuotaExhausted { meta, .. }
144            | ValidationError { meta, .. }
145            | NotFound { meta, .. }
146            | ServerError { meta, .. }
147            | ApiError { meta, .. } => meta.as_ref(),
148            _ => None,
149        }
150    }
151}
152
153#[derive(Debug, serde::Deserialize)]
154pub struct ApiErrorBody {
155    pub code: Option<String>,
156    pub error: Option<String>,
157    pub message: Option<String>,
158    pub details: Option<serde_json::Value>,
159    pub quota: Option<serde_json::Value>,
160    pub docs: Option<serde_json::Value>,
161}