use reqwest::{StatusCode, header::HeaderMap};
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("{path}: {message}")]
pub struct ValidationError {
pub path: String,
pub message: String,
}
impl ValidationError {
pub(crate) fn new(path: impl Into<String>, message: impl Into<String>) -> Self {
Self {
path: path.into(),
message: message.into(),
}
}
}
#[derive(Debug, Clone, thiserror::Error)]
#[error("TypeSafe API returned HTTP {status}")]
pub struct ApiError {
pub status: StatusCode,
pub headers: HeaderMap,
pub body: String,
}
impl ApiError {
pub fn json(&self) -> Result<serde_json::Value, serde_json::Error> {
serde_json::from_str(&self.body)
}
pub fn is_retryable(&self) -> bool {
matches!(self.status.as_u16(), 429 | 529)
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("invalid client configuration: {0}")]
Configuration(String),
#[error(transparent)]
Validation(#[from] ValidationError),
#[error("HTTP transport failed: {0}")]
Transport(#[from] reqwest::Error),
#[error(transparent)]
Api(#[from] Box<ApiError>),
#[error("failed to decode the evaluation response: {0}")]
Decode(#[source] serde_json::Error),
#[error("evaluation timed out")]
Timeout,
}