trakt_core/
error.rs

1//! Error types for the API.
2
3use http::{header::InvalidHeaderValue, StatusCode};
4
5#[derive(Debug, thiserror::Error)]
6pub enum ApiError {
7    #[error("Bad Request")]
8    BadRequest,
9    #[error("Unauthorized")]
10    Unauthorized,
11    #[error("Forbidden")]
12    Forbidden,
13    #[error("Not Found")]
14    NotFound,
15    #[error("Resource Already Exists")]
16    AlreadyExists,
17    #[error("Resource Expired")]
18    Expired,
19    #[error("Invalid Content-Type")]
20    InvalidContentType,
21    #[error("User denied the request")]
22    Denied,
23    #[error("Account limit exceeded")]
24    AccountLimitExceeded,
25    #[error("Validation Error")]
26    ValidationError,
27    #[error("Locked User Account")]
28    LockedUserAccount,
29    #[error("VIP Only")]
30    VipOnly,
31    #[error("Rate Limit Exceeded")]
32    RateLimitExceeded,
33    #[error("Server Error")]
34    ServerError,
35    #[error("Service Unavailable")]
36    ServiceUnavailable,
37    #[error("Cloudflare Error")]
38    CloudflareError,
39    #[error("Unknown Error: {0}")]
40    UnknownError(StatusCode),
41}
42
43impl From<StatusCode> for ApiError {
44    fn from(value: StatusCode) -> Self {
45        match value.as_u16() {
46            400 => Self::BadRequest,
47            401 => Self::Unauthorized,
48            403 => Self::Forbidden,
49            404 => Self::NotFound,
50            409 => Self::AlreadyExists,
51            410 => Self::Expired,
52            412 => Self::InvalidContentType,
53            418 => Self::Denied,
54            420 => Self::AccountLimitExceeded,
55            422 => Self::ValidationError,
56            423 => Self::LockedUserAccount,
57            426 => Self::VipOnly,
58            429 => Self::RateLimitExceeded,
59            500 => Self::ServerError,
60            502..=504 => Self::ServiceUnavailable,
61            520..=522 => Self::CloudflareError,
62            _ => Self::UnknownError(value),
63        }
64    }
65}
66
67/// Error type for converting a request into an HTTP request.
68#[derive(Debug, thiserror::Error)]
69pub enum IntoHttpError {
70    #[error("JSON Error: {0}")]
71    Json(#[from] serde_json::Error),
72    #[error("Invalid Header Value: {0}")]
73    Header(#[from] InvalidHeaderValue),
74    #[error("HTTP Error: {0}")]
75    Http(#[from] http::Error),
76    #[error("Url params error: {0}")]
77    UrlParams(#[from] UrlError),
78    #[error("Query params error: {0}")]
79    QueryParams(#[from] serde_urlencoded::ser::Error),
80    #[error("Missing oauth token")]
81    MissingToken,
82    #[error("Validation Error: {0}")]
83    Validation(String),
84}
85
86#[derive(Debug, thiserror::Error)]
87pub enum FromHttpError {
88    #[error("API Error: {0}")]
89    Api(#[from] ApiError),
90    #[error("Deserialize Error: {0}")]
91    Deserialize(#[from] DeserializeError),
92}
93
94#[derive(Debug, thiserror::Error)]
95pub enum DeserializeError {
96    #[error("JSON Error: {0}")]
97    Json(#[from] serde_json::Error),
98    #[error("Header Error: {0}")]
99    Header(#[from] HeaderError),
100    #[error("Integer Parse Error: {0}")]
101    ParseInt(#[from] std::num::ParseIntError),
102}
103
104#[derive(Debug, thiserror::Error)]
105pub enum HeaderError {
106    #[error("Invalid Header Value: {0}")]
107    ToStrError(#[from] http::header::ToStrError),
108    #[error("Missing Header")]
109    MissingHeader,
110}
111
112#[derive(Debug, PartialEq, Eq, thiserror::Error)]
113pub enum UrlError {
114    #[error("{0}")]
115    Message(String),
116    #[error("Top level serializer only supports structs")]
117    TopLevel,
118    #[error("Invalid endpoint")]
119    InvalidEndpoint,
120    #[error("Value not supported")]
121    ValueNotSupported,
122    #[error("Key not found: {0}")]
123    KeyNotFound(&'static str),
124    #[error("Unfilled field: {0}")]
125    UnfilledField(String),
126}
127
128impl serde::ser::Error for UrlError {
129    fn custom<T: std::fmt::Display>(msg: T) -> Self {
130        Self::Message(msg.to_string())
131    }
132}