freedom_api/
error.rs

1//! Error and Result types for Freedom API
2use reqwest::StatusCode;
3use serde::{Serialize, Serializer};
4
5/// Result type for the API
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// The combined error type for the client builder and for API errors
9#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq, Serialize)]
10#[non_exhaustive]
11pub enum Error {
12    #[error("Failed to get valid response from server: {0}")]
13    Response(String),
14
15    #[error("Server responded with {status}: {error}")]
16    ResponseStatus {
17        #[serde(serialize_with = "serialize_status")]
18        status: StatusCode,
19        error: String,
20    },
21
22    #[error("Failed to deserialize the response: {0}")]
23    Deserialization(String),
24
25    #[error("Paginated item failed deserialized: {0}")]
26    PaginationItemDeserialization(String),
27
28    // We do not place the time::error::Error in the error since it includes std::io::Error which
29    // does not implement Clone, PartialEq, or Eq
30    #[error("Time parsing error: {0}")]
31    TimeFormatError(String),
32
33    #[error("Failed to parse item into valid URI: {0}")]
34    InvalidUri(String),
35
36    #[error("Failed to retrieve the HATEOAS URI: {0}")]
37    MissingUri(&'static str),
38
39    #[error("Failed to parse the final segment of the path as an ID.")]
40    InvalidId,
41}
42
43fn serialize_status<S: Serializer>(
44    status: &StatusCode,
45    serializer: S,
46) -> std::result::Result<S::Ok, S::Error> {
47    serializer.serialize_u16(status.as_u16())
48}
49
50impl Error {
51    /// Shorthand for creating a runtime pagination error
52    pub(crate) fn pag_item(s: String) -> Self {
53        Self::PaginationItemDeserialization(s)
54    }
55}
56
57impl From<reqwest::Error> for Error {
58    fn from(value: reqwest::Error) -> Self {
59        let error = value.to_string();
60        match value.status() {
61            Some(status) => Self::ResponseStatus { status, error },
62            None => Error::Response(error),
63        }
64    }
65}
66
67impl From<serde_json::Error> for Error {
68    fn from(value: serde_json::Error) -> Self {
69        Error::Deserialization(value.to_string())
70    }
71}
72
73impl From<time::error::Error> for Error {
74    fn from(value: time::error::Error) -> Self {
75        Error::TimeFormatError(value.to_string())
76    }
77}
78
79impl From<time::error::Format> for Error {
80    fn from(value: time::error::Format) -> Self {
81        Error::TimeFormatError(value.to_string())
82    }
83}
84
85impl From<url::ParseError> for Error {
86    fn from(value: url::ParseError) -> Self {
87        Self::InvalidUri(value.to_string())
88    }
89}