google_cloud_bigquery/http/
error.rs

1use std::fmt;
2
3#[derive(thiserror::Error, Debug)]
4pub enum Error {
5    /// An error returned from the Google Cloud Storage service.
6    #[error(transparent)]
7    Response(#[from] ErrorResponse),
8
9    /// An error from the HTTP client.
10    #[error(transparent)]
11    HttpClient(#[from] reqwest::Error),
12
13    /// An error from the HTTP client.
14    #[error(transparent)]
15    HttpMiddleware(anyhow::Error),
16
17    /// An error from a token source.
18    #[error("token source failed: {0}")]
19    TokenSource(Box<dyn std::error::Error + Send + Sync>),
20}
21
22impl From<reqwest_middleware::Error> for Error {
23    fn from(error: reqwest_middleware::Error) -> Self {
24        match error {
25            reqwest_middleware::Error::Reqwest(err) => Error::HttpClient(err),
26            reqwest_middleware::Error::Middleware(err) => Error::HttpMiddleware(err),
27        }
28    }
29}
30
31#[derive(Debug, serde::Deserialize)]
32#[serde(rename_all = "camelCase")]
33pub struct ErrorResponse {
34    /// An HTTP status value, without the textual description.
35    ///
36    /// Example values include: `400` (Bad Request), `401` (Unauthorized), and `404` (Not Found).
37    pub code: u16,
38
39    /// Detailed error code & message from the Google API frontend.
40    pub errors: Option<Vec<ErrorResponseItem>>,
41
42    /// Description of the error. Same as `errors.message`.
43    pub message: String,
44}
45
46const RETRYABLE_CODES: [u16; 4] = [500, 502, 503, 504];
47
48impl ErrorResponse {
49    pub fn is_retryable(&self, retryable_reasons: &[&str]) -> bool {
50        if RETRYABLE_CODES.contains(&self.code) {
51            return true;
52        }
53        match &self.errors {
54            None => false,
55            Some(details) => {
56                for detail in details {
57                    for reason in retryable_reasons {
58                        if &detail.reason == reason {
59                            return true;
60                        }
61                    }
62                }
63                false
64            }
65        }
66    }
67}
68
69impl fmt::Display for ErrorResponse {
70    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71        self.message.fmt(f)
72    }
73}
74
75impl std::error::Error for ErrorResponse {}
76
77/// ErrorItem is a detailed error code & message from the Google API frontend.
78#[derive(Debug, serde::Deserialize)]
79#[serde(rename_all = "camelCase")]
80pub struct ErrorResponseItem {
81    /// Message is the human-readable description of the error.
82    pub message: String,
83
84    /// Reason is the typed error code. For example: "some_example".
85    pub reason: String,
86}
87
88impl fmt::Display for ErrorResponseItem {
89    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90        self.message.fmt(f)
91    }
92}
93
94#[derive(serde::Deserialize)]
95pub(crate) struct ErrorWrapper {
96    pub(crate) error: ErrorResponse,
97}