Skip to main content

wave_api/
error.rs

1use serde::Deserialize;
2
3/// Errors returned by the Wave API client.
4#[derive(Debug, thiserror::Error)]
5pub enum WaveError {
6    /// HTTP transport error from reqwest.
7    #[error("HTTP error: {0}")]
8    Http(#[from] reqwest::Error),
9
10    /// JSON serialization/deserialization error.
11    #[error("JSON error: {0}")]
12    Json(#[from] serde_json::Error),
13
14    /// GraphQL-level errors returned in the `errors` array.
15    #[error("GraphQL errors: {}", format_graphql_errors(.0))]
16    GraphQL(Vec<GraphqlError>),
17
18    /// Mutation returned `didSucceed: false` with input validation errors.
19    #[error("Mutation failed: {}", format_input_errors(.0))]
20    MutationFailed(Vec<InputError>),
21
22    /// Authentication error (missing or invalid token).
23    #[error("Authentication error: {0}")]
24    Auth(String),
25
26    /// Token refresh failed.
27    #[error("Token refresh failed: {0}")]
28    TokenRefresh(String),
29}
30
31/// A GraphQL error from the `errors` array in the response.
32#[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/// Extension data on a GraphQL error.
41#[derive(Debug, Clone, Deserialize)]
42pub struct GraphqlErrorExtensions {
43    pub id: Option<String>,
44    pub code: Option<String>,
45}
46
47/// A mutation validation error from the `inputErrors` array.
48#[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}