syncable_cli/platform/api/
error.rs

1//! Error types for the Platform API client
2//!
3//! Provides structured error types for all API operations.
4
5use thiserror::Error;
6
7/// Errors that can occur when interacting with the Syncable Platform API
8#[derive(Debug, Error)]
9pub enum PlatformApiError {
10    /// HTTP request failed (network error, timeout, etc.)
11    #[error("HTTP request failed: {0}")]
12    HttpError(#[from] reqwest::Error),
13
14    /// API returned an error response
15    #[error("API error ({status}): {message}")]
16    ApiError {
17        /// HTTP status code
18        status: u16,
19        /// Error message from the API
20        message: String,
21    },
22
23    /// Failed to parse the API response
24    #[error("Failed to parse response: {0}")]
25    ParseError(String),
26
27    /// User is not authenticated - needs to run `sync-ctl auth login`
28    #[error("Not authenticated - run `sync-ctl auth login` first")]
29    Unauthorized,
30
31    /// Requested resource was not found
32    #[error("Not found: {0}")]
33    NotFound(String),
34
35    /// User does not have permission for the requested operation
36    #[error("Permission denied: {0}")]
37    PermissionDenied(String),
38
39    /// Rate limit exceeded
40    #[error("Rate limit exceeded - please try again later")]
41    RateLimited,
42
43    /// Server error
44    #[error("Server error ({status}): {message}")]
45    ServerError {
46        /// HTTP status code (5xx)
47        status: u16,
48        /// Error message
49        message: String,
50    },
51
52    /// Could not connect to the Syncable API
53    #[error("Could not connect to Syncable API - check your internet connection")]
54    ConnectionFailed,
55}
56
57impl PlatformApiError {
58    /// Get a user-friendly suggestion for resolving this error
59    ///
60    /// Returns actionable advice that helps users fix the issue.
61    pub fn suggestion(&self) -> Option<&'static str> {
62        match self {
63            Self::Unauthorized => Some("Run `sync-ctl auth login` to authenticate"),
64            Self::RateLimited => Some("Wait a moment and try again"),
65            Self::HttpError(_) => Some("Check your internet connection"),
66            Self::ServerError { .. } => {
67                Some("The server is experiencing issues. Try again later")
68            }
69            Self::PermissionDenied(_) => {
70                Some("Check your project permissions in the Syncable dashboard")
71            }
72            Self::NotFound(_) => Some("Verify the resource ID is correct"),
73            Self::ParseError(_) => Some("This may be a bug - please report it"),
74            Self::ApiError { status, .. } if *status >= 400 && *status < 500 => {
75                Some("Check the request parameters")
76            }
77            Self::ConnectionFailed => {
78                Some("Check your internet connection and try again")
79            }
80            _ => None,
81        }
82    }
83
84    /// Format the error with suggestion if available
85    ///
86    /// Returns the error message followed by a suggestion on how to resolve it.
87    pub fn with_suggestion(&self) -> String {
88        match self.suggestion() {
89            Some(suggestion) => format!("{}\n  → {}", self, suggestion),
90            None => self.to_string(),
91        }
92    }
93}
94
95/// Result type alias for Platform API operations
96pub type Result<T> = std::result::Result<T, PlatformApiError>;