use std::fmt;
use serde::{Deserialize, Serialize};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("invalid configuration: {0}")]
Config(String),
#[error("http transport error: {0}")]
Http(#[from] reqwest::Error),
#[error("serialization error: {0}")]
Serde(#[from] serde_json::Error),
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("url error: {0}")]
Url(#[from] url::ParseError),
#[error("api error: {0}")]
Api(#[from] ApiError),
#[error("unexpected response: {0}")]
UnexpectedResponse(String),
}
impl Error {
pub fn status(&self) -> Option<u16> {
match self {
Error::Api(e) => Some(e.status),
Error::Http(e) => e.status().map(|s| s.as_u16()),
_ => None,
}
}
pub fn api(&self) -> Option<&ApiError> {
match self {
Error::Api(e) => Some(e),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ApiError {
pub status: u16,
pub message: String,
#[serde(default)]
pub data: serde_json::Value,
}
impl fmt::Display for ApiError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} (status {})", self.message, self.status)
}
}
impl std::error::Error for ApiError {}