1use serde::Deserialize;
2
3#[derive(Debug, thiserror::Error)]
5pub enum WaveError {
6 #[error("HTTP error: {0}")]
8 Http(#[from] reqwest::Error),
9
10 #[error("JSON error: {0}")]
12 Json(#[from] serde_json::Error),
13
14 #[error("GraphQL errors: {}", format_graphql_errors(.0))]
16 GraphQL(Vec<GraphqlError>),
17
18 #[error("Mutation failed: {}", format_input_errors(.0))]
20 MutationFailed(Vec<InputError>),
21
22 #[error("Authentication error: {0}")]
24 Auth(String),
25
26 #[error("Token refresh failed: {0}")]
28 TokenRefresh(String),
29}
30
31#[derive(Debug, Clone, Deserialize)]
33pub struct GraphqlError {
34 pub message: String,
35 #[serde(default)]
36 pub path: Vec<String>,
37 pub extensions: Option<GraphqlErrorExtensions>,
38}
39
40#[derive(Debug, Clone, Deserialize)]
42pub struct GraphqlErrorExtensions {
43 pub id: Option<String>,
44 pub code: Option<String>,
45}
46
47#[derive(Debug, Clone, Deserialize)]
49pub struct InputError {
50 pub path: Option<Vec<String>>,
51 pub message: Option<String>,
52 pub code: Option<String>,
53}
54
55impl std::fmt::Display for GraphqlError {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 write!(f, "{}", self.message)
58 }
59}
60
61impl std::fmt::Display for InputError {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 if let Some(msg) = &self.message {
64 write!(f, "{msg}")?;
65 }
66 if let Some(path) = &self.path {
67 write!(f, " (at {})", path.join("."))?;
68 }
69 Ok(())
70 }
71}
72
73fn format_graphql_errors(errors: &[GraphqlError]) -> String {
74 errors
75 .iter()
76 .map(|e| e.message.as_str())
77 .collect::<Vec<_>>()
78 .join("; ")
79}
80
81fn format_input_errors(errors: &[InputError]) -> String {
82 errors
83 .iter()
84 .map(|e| format!("{e}"))
85 .collect::<Vec<_>>()
86 .join("; ")
87}