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("invalid multipart body: {message}")]
97    InvalidMultipartBody { message: String },
98
99    #[error(transparent)]
100    Io(#[from] std::io::Error),
101
102    #[error(transparent)]
103    Transport(#[from] reqwest::Error),
104
105    #[error(transparent)]
106    Json(#[from] serde_json::Error),
107
108    #[error(transparent)]
109    Url(#[from] url::ParseError),
110}
111
112impl Error {
113    pub fn status(&self) -> Option<u16> {
114        use Error::*;
115        match self {
116            AuthenticationError { status, .. }
117            | RateLimitError { status, .. }
118            | InsufficientCredits { status, .. }
119            | VisitorMonthlyQuotaExhausted { status, .. }
120            | ValidationError { status, .. }
121            | NotFound { status, .. }
122            | ServerError { status, .. }
123            | ApiError { status, .. } => Some(*status),
124            _ => None,
125        }
126    }
127
128    pub fn request_id(&self) -> Option<&str> {
129        use Error::*;
130        match self {
131            AuthenticationError { request_id, .. }
132            | RateLimitError { request_id, .. }
133            | InsufficientCredits { request_id, .. }
134            | VisitorMonthlyQuotaExhausted { request_id, .. }
135            | ValidationError { request_id, .. }
136            | NotFound { request_id, .. }
137            | ServerError { request_id, .. }
138            | ApiError { request_id, .. } => request_id.as_deref(),
139            _ => None,
140        }
141    }
142
143    pub fn meta(&self) -> Option<&ResponseMeta> {
144        use Error::*;
145        match self {
146            AuthenticationError { meta, .. }
147            | RateLimitError { meta, .. }
148            | InsufficientCredits { meta, .. }
149            | VisitorMonthlyQuotaExhausted { meta, .. }
150            | ValidationError { meta, .. }
151            | NotFound { meta, .. }
152            | ServerError { meta, .. }
153            | ApiError { meta, .. } => meta.as_ref(),
154            _ => None,
155        }
156    }
157}
158
159#[derive(Debug, serde::Deserialize)]
160pub struct ApiErrorBody {
161    pub code: Option<String>,
162    pub error: Option<String>,
163    pub message: Option<String>,
164    pub details: Option<serde_json::Value>,
165    pub quota: Option<serde_json::Value>,
166    pub docs: Option<serde_json::Value>,
167}