use std::fmt;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("HTTP transport error: {0}")]
Http(#[from] reqwest::Error),
#[error(transparent)]
Api(#[from] ApiError),
#[error("failed to decode Namecheap XML response: {0}")]
Decode(#[from] quick_xml::DeError),
#[error("unexpected HTTP status {status}")]
UnexpectedStatus {
status: reqwest::StatusCode,
body: String,
},
#[error("the API reported success but returned no command result")]
EmptyResponse,
#[error("invalid client configuration: {0}")]
Configuration(String),
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct ApiError {
pub errors: Vec<ApiErrorEntry>,
}
impl ApiError {
#[must_use]
pub fn has_code(&self, code: &str) -> bool {
self.errors.iter().any(|entry| entry.number == code)
}
#[must_use]
pub fn first(&self) -> Option<&ApiErrorEntry> {
self.errors.first()
}
}
impl fmt::Display for ApiError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Namecheap API error")?;
for (index, entry) in self.errors.iter().enumerate() {
let separator = if index == 0 { ": " } else { "; " };
write!(f, "{separator}[{}] {}", entry.number, entry.message)?;
}
Ok(())
}
}
impl std::error::Error for ApiError {}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct ApiErrorEntry {
pub number: String,
pub message: String,
}