cloudflare/framework/response/
apifail.rs

1use serde::de::DeserializeOwned;
2use serde_json::value::Value as JValue;
3use std::collections::HashMap;
4
5use std::fmt;
6use std::fmt::Debug;
7/// Note that APIError's `eq` implementation only compares `code` and `message`.
8/// It does NOT compare the `other` values.
9#[derive(Deserialize, Debug)]
10pub struct ApiError {
11    pub code: u16,
12    pub message: String,
13    #[serde(flatten)]
14    pub other: HashMap<String, JValue>,
15}
16
17/// Note that APIErrors's `eq` implementation only compares `code` and `message`.
18/// It does NOT compare the `other` values.
19#[derive(Deserialize, Debug, Default)]
20pub struct ApiErrors {
21    #[serde(flatten)]
22    pub other: HashMap<String, JValue>,
23    pub errors: Vec<ApiError>,
24}
25
26impl PartialEq for ApiErrors {
27    fn eq(&self, other: &Self) -> bool {
28        self.errors == other.errors
29    }
30}
31
32impl PartialEq for ApiError {
33    fn eq(&self, other: &Self) -> bool {
34        self.code == other.code && self.message == other.message
35    }
36}
37
38impl Eq for ApiError {}
39impl Eq for ApiErrors {}
40
41impl fmt::Display for ApiError {
42    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43        write!(f, "Error {}: {}", self.code, self.message)
44    }
45}
46
47pub trait ApiResult: DeserializeOwned + Debug {}
48
49#[derive(Debug)]
50pub enum ApiFailure {
51    Error(reqwest::StatusCode, ApiErrors),
52    Invalid(reqwest::Error),
53}
54
55impl PartialEq for ApiFailure {
56    fn eq(&self, other: &ApiFailure) -> bool {
57        match (self, other) {
58            (ApiFailure::Invalid(e1), ApiFailure::Invalid(e2)) => e1.to_string() == e2.to_string(),
59            (ApiFailure::Error(status1, e1), ApiFailure::Error(status2, e2)) => {
60                status1 == status2 && e1 == e2
61            }
62            _ => false,
63        }
64    }
65}
66impl Eq for ApiFailure {}
67
68impl fmt::Display for ApiFailure {
69    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70        match self {
71            ApiFailure::Error(status, api_errors) => {
72                let mut output = "".to_owned();
73                output.push_str(&format!("HTTP {}", status));
74                for err in &api_errors.errors {
75                    output.push_str(&format!(
76                        "\n{}: {} ({:?})",
77                        err.code, err.message, err.other
78                    ));
79                }
80                for (k, v) in &api_errors.other {
81                    output.push_str(&format!("\n{}: {}", k, v));
82                }
83                write!(f, "{}", output)
84            }
85            ApiFailure::Invalid(err) => write!(f, "{}", err),
86        }
87    }
88}
89
90impl From<reqwest::Error> for ApiFailure {
91    fn from(error: reqwest::Error) -> Self {
92        ApiFailure::Invalid(error)
93    }
94}