use serde::Deserialize;
#[derive(Debug, thiserror::Error)]
pub enum WaveError {
#[error("HTTP error: {0}")]
Http(#[from] reqwest::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("GraphQL errors: {}", format_graphql_errors(.0))]
GraphQL(Vec<GraphqlError>),
#[error("Mutation failed: {}", format_input_errors(.0))]
MutationFailed(Vec<InputError>),
#[error("Authentication error: {0}")]
Auth(String),
#[error("Token refresh failed: {0}")]
TokenRefresh(String),
}
#[derive(Debug, Clone, Deserialize)]
pub struct GraphqlError {
pub message: String,
#[serde(default)]
pub path: Vec<String>,
pub extensions: Option<GraphqlErrorExtensions>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct GraphqlErrorExtensions {
pub id: Option<String>,
pub code: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct InputError {
pub path: Option<Vec<String>>,
pub message: Option<String>,
pub code: Option<String>,
}
impl std::fmt::Display for GraphqlError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::fmt::Display for InputError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(msg) = &self.message {
write!(f, "{msg}")?;
}
if let Some(path) = &self.path {
write!(f, " (at {})", path.join("."))?;
}
Ok(())
}
}
fn format_graphql_errors(errors: &[GraphqlError]) -> String {
errors
.iter()
.map(|e| e.message.as_str())
.collect::<Vec<_>>()
.join("; ")
}
fn format_input_errors(errors: &[InputError]) -> String {
errors
.iter()
.map(|e| format!("{e}"))
.collect::<Vec<_>>()
.join("; ")
}