spotify_rs/
error.rs

1use oauth2::basic::BasicErrorResponseType;
2use serde::Deserialize;
3use snafu::prelude::*;
4
5/// A convenience result type that uses [`enum@Error`] by default.
6pub type Result<T, E = Error> = std::result::Result<T, E>;
7
8#[derive(Debug, Snafu)]
9#[snafu(visibility(pub(crate)))]
10pub enum Error {
11    /// The client has not yet been authenticated.
12    NotAuthenticated,
13
14    /// The access token has expired and auto-refresh is turned off.
15    ExpiredToken,
16
17    /// The (CSRF) state parameter supplied is not the same as the one initially generated and sent to the server.
18    ///
19    /// Learn more about CSRF [here](https://datatracker.ietf.org/doc/html/rfc6749#section-10.12).
20    #[snafu(display(
21        "The supplied (CSRF) state parameter is not the same as the one sent to the authorisation server. Learn more about CSRF here: https://datatracker.ietf.org/doc/html/rfc6749#section-10.12"
22    ))]
23    InvalidStateParameter,
24
25    /// The access token has expired and refreshing it is not possible in the current authorisation flow.
26    RefreshUnavailable,
27
28    // There are no remaining pages left, either before or after the current one.
29    NoRemainingPages,
30
31    /// An error that indicates that an internal error occurred and the
32    /// client had no PKCE verifier when authenticating.
33    ///
34    /// This error *should not* occur realistically.
35    #[snafu(display(
36        "Internal error: the client's PKCE verifier was missing when authenticating."
37    ))]
38    InvalidClientState,
39
40    /// The returned data is not valid valid UTF-8.
41    InvalidResponse,
42
43    /// An error returned by Spotify.
44    #[snafu(display("Error returned by the Spotify API: {status} {description}"))]
45    Spotify {
46        /// The HTTP status code of the error.
47        status: u16,
48        /// A description of the error, as returned by Spotify.
49        description: String,
50    },
51
52    #[snafu(display("An error ocurred during the authentication process."))]
53    Authentication {
54        source: OauthError,
55    },
56
57    /// An error related to parsing items.
58    #[snafu(display("{description}"))]
59    Parse {
60        description: String,
61    },
62
63    /// An error that resulted from deserializing data, either as a [model](crate::model) type,
64    /// or as a `Nil`.
65    #[snafu(display("An error occurred during deserialization."))]
66    Deserialization {
67        source: serde_json::Error,
68        body: String,
69    },
70
71    /// An HTTP error, as returned from the underlying HTTP client.
72    #[snafu(display("An HTTP error occurred."))]
73    Http {
74        source: reqwest::Error,
75    },
76}
77
78#[derive(Deserialize)]
79pub(crate) struct SpotifyError {
80    error: Details,
81}
82
83#[derive(Deserialize)]
84struct Details {
85    status: u16,
86    message: String,
87}
88
89// Error encountered when requesting an OAuth2 access token.
90type OauthError = oauth2::RequestTokenError<
91    oauth2::reqwest::Error<reqwest::Error>,
92    oauth2::StandardErrorResponse<BasicErrorResponseType>,
93>;
94
95// Enables the use of the `?` operator.
96impl From<OauthError> for Error {
97    fn from(source: OauthError) -> Self {
98        Self::Authentication { source }
99    }
100}
101
102// Enables the use of the `?` operator.
103impl From<reqwest::Error> for Error {
104    fn from(source: reqwest::Error) -> Self {
105        Self::Http { source }
106    }
107}
108
109// Enables the use of the `?` operator.
110impl From<SpotifyError> for Error {
111    fn from(value: SpotifyError) -> Self {
112        Self::Spotify {
113            status: value.error.status,
114            description: value.error.message,
115        }
116    }
117}