typesafe_systemone/
error.rs1use std::time::Duration;
2
3pub type Result<T> = std::result::Result<T, Error>;
5
6#[derive(Debug, thiserror::Error)]
10#[non_exhaustive]
11pub enum Error {
12 #[error("configuration error: {0}")]
14 Config(String),
15
16 #[error("invalid request: {0}")]
18 InvalidRequest(String),
19
20 #[error("no {expected} answer for question `{id}`")]
22 MissingAnswer { id: String, expected: &'static str },
23
24 #[error("bad request: {message}")]
26 BadRequest { message: String },
27
28 #[error("authentication failed: {message}")]
30 Authentication { message: String },
31
32 #[error("permission denied: {message}")]
34 PermissionDenied { message: String },
35
36 #[error("not found: {message}")]
38 NotFound { message: String },
39
40 #[error("unprocessable entity: {message}")]
42 UnprocessableEntity { message: String },
43
44 #[error("rate limited: {message}")]
46 RateLimit {
47 retry_after: Option<Duration>,
48 message: String,
49 },
50
51 #[error("overloaded: {message}")]
53 Overloaded {
54 retry_after: Option<Duration>,
55 message: String,
56 },
57
58 #[error("server error {status}: {message}")]
60 Server { status: u16, message: String },
61
62 #[error("unexpected status {status}: {message}")]
64 UnexpectedStatus { status: u16, message: String },
65
66 #[error("connection error: {0}")]
68 Connection(#[source] reqwest::Error),
69
70 #[error("request timed out")]
72 Timeout(#[source] reqwest::Error),
73
74 #[error("response validation failed: {0}")]
76 ResponseValidation(#[source] serde_json::Error),
77
78 #[error("request serialization failed: {0}")]
80 RequestSerialization(#[source] serde_json::Error),
81}
82
83impl Error {
84 pub fn status(&self) -> Option<u16> {
86 match self {
87 Self::BadRequest { .. } => Some(400),
88 Self::Authentication { .. } => Some(401),
89 Self::PermissionDenied { .. } => Some(403),
90 Self::NotFound { .. } => Some(404),
91 Self::UnprocessableEntity { .. } => Some(422),
92 Self::RateLimit { .. } => Some(429),
93 Self::Overloaded { .. } => Some(529),
94 Self::Server { status, .. } | Self::UnexpectedStatus { status, .. } => Some(*status),
95 _ => None,
96 }
97 }
98
99 pub(crate) fn from_status(status: u16, retry_after: Option<Duration>, message: String) -> Self {
100 match status {
101 400 => Self::BadRequest { message },
102 401 => Self::Authentication { message },
103 403 => Self::PermissionDenied { message },
104 404 => Self::NotFound { message },
105 422 => Self::UnprocessableEntity { message },
106 429 => Self::RateLimit { retry_after, message },
107 529 => Self::Overloaded { retry_after, message },
108 500..=599 => Self::Server { status, message },
109 _ => Self::UnexpectedStatus { status, message },
110 }
111 }
112
113 pub(crate) fn from_transport(err: reqwest::Error) -> Self {
114 if err.is_timeout() {
115 Self::Timeout(err)
116 } else {
117 Self::Connection(err)
118 }
119 }
120}