Skip to main content

ytcli/api/
error.rs

1//! Typed API failures.
2//!
3//! The variants exist so the shell can map them to distinct exit codes and to
4//! actionable messages; a single opaque "request failed" would make both
5//! impossible.
6
7use crate::exit::ExitCode;
8
9#[derive(Debug, thiserror::Error)]
10pub enum ApiError {
11    #[error("transport error talking to Tracker")]
12    Transport(#[from] reqwest::Error),
13    #[error("not authenticated: the token was rejected (401)")]
14    Unauthorized,
15    #[error("forbidden (403): the account lacks rights, or the organisation header is wrong")]
16    Forbidden,
17    #[error("{0} not found")]
18    NotFound(String),
19    #[error("rate limited by Tracker (429)")]
20    RateLimited,
21    #[error("Tracker rejected the request ({status}): {message}")]
22    Rejected {
23        status: reqwest::StatusCode,
24        message: String,
25    },
26    #[error("could not decode the Tracker response")]
27    Decode(#[source] serde_json::Error),
28}
29
30impl ApiError {
31    #[must_use]
32    pub fn exit_code(&self) -> ExitCode {
33        match self {
34            Self::Unauthorized => ExitCode::Auth,
35            Self::NotFound(_) => ExitCode::NotFound,
36            Self::Forbidden | Self::RateLimited | Self::Rejected { .. } => ExitCode::ApiRejected,
37            Self::Transport(_) | Self::Decode(_) => ExitCode::Failure,
38        }
39    }
40}