use serde::{Deserialize, Serialize};
use crate::types::messages::ApiErrorBody;
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("API error {status}{}: {message}", error_type.as_ref().map(|t| format!(" ({t:?})")).unwrap_or_default())]
Api {
status: http::StatusCode,
error_type: Option<ErrorType>,
message: String,
request_id: Option<String>,
raw: String,
},
#[error("JSON encode/decode error: {0}")]
Serde(#[from] serde_json::Error),
#[error("invalid configuration: {0}")]
Config(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
#[allow(missing_docs)] pub enum ErrorType {
InvalidRequestError,
AuthenticationError,
BillingError,
PermissionError,
NotFoundError,
RateLimitError,
TimeoutError,
ApiError,
OverloadedError,
GatewayTimeoutError,
#[serde(other)]
Unknown,
}
pub(crate) fn api_error_from_response(
status: http::StatusCode,
request_id: Option<String>,
raw: String,
) -> Error {
if let Ok(body) = serde_json::from_str::<ApiErrorBody>(&raw) {
let error_type =
serde_json::from_value::<ErrorType>(serde_json::Value::String(body.error.kind.clone()))
.ok();
Error::Api {
status,
error_type,
message: body.error.message,
request_id,
raw,
}
} else {
Error::Api {
status,
error_type: None,
message: format!("non-JSON error body (HTTP {})", status.as_u16()),
request_id,
raw,
}
}
}