1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct GraphQLError {
7 pub message: String,
8 #[serde(default)]
9 pub extensions: Option<serde_json::Value>,
10}
11
12#[derive(Debug)]
14pub enum LinearError {
15 Authentication(String),
17 RateLimited {
19 retry_after: Option<f64>,
20 message: String,
21 },
22 InvalidInput(String),
24 Forbidden(String),
26 Network(reqwest::Error),
28 GraphQL(Vec<GraphQLError>),
30 MissingData(String),
32 HttpError { status: u16, body: String },
34 AuthConfig(String),
36}
37
38impl fmt::Display for LinearError {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 match self {
41 Self::Authentication(msg) => write!(f, "Authentication error: {}", msg),
42 Self::RateLimited { message, .. } => write!(f, "Rate limited: {}", message),
43 Self::InvalidInput(msg) => write!(f, "Invalid input: {}", msg),
44 Self::Forbidden(msg) => write!(f, "Forbidden: {}", msg),
45 Self::Network(e) => write!(f, "Network error: {}", e),
46 Self::GraphQL(errors) => {
47 let msgs: Vec<String> = errors
48 .iter()
49 .map(|e| {
50 if let Some(ext) = &e.extensions {
51 format!("{} ({})", e.message, ext)
52 } else {
53 e.message.clone()
54 }
55 })
56 .collect();
57 write!(f, "GraphQL errors: {}", msgs.join("; "))
58 }
59 Self::HttpError { status, body } => {
60 write!(f, "HTTP error {}: {}", status, body)
61 }
62 Self::MissingData(path) => write!(f, "Missing data at path: {}", path),
63 Self::AuthConfig(msg) => write!(f, "Auth configuration error: {}", msg),
64 }
65 }
66}
67
68impl std::error::Error for LinearError {
69 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
70 match self {
71 Self::Network(e) => Some(e),
72 _ => None,
73 }
74 }
75}
76
77impl From<reqwest::Error> for LinearError {
78 fn from(e: reqwest::Error) -> Self {
79 Self::Network(e)
80 }
81}