use serde_json::Value;
use thiserror::Error;
use crate::{MiddlewareError, MimeType};
#[derive(Debug, Error)]
pub enum ApiError {
#[error("Service discovery error: {0}")]
ServiceDiscovery(anyhow::Error),
#[error("Invalid URL: {0}")]
InvalidUrl(reqwest::Error),
#[error("Build request error: {0}")]
BuildRequest(reqwest::Error),
#[error("Generic reqwest error: {0}")]
Reqwest(reqwest::Error),
#[error("Middleware error: {0}")]
Middleware(anyhow::Error),
#[error("Invalid multipart form")]
MultipartForm,
#[error("HTTP Client status error: [{0}] {1}")]
HttpClientStatus(u16, String),
#[error("HTTP Server status error: [{0}] {1}")]
HttpServerStatus(u16, String),
#[error("Unsupported Content-Type: {0}")]
UnsupportedContentType(MimeType),
#[error("Incompatible Content-Type: perfer {0}, actual {1}")]
IncompatibleContentType(MimeType, MimeType),
#[error("Decode response error: {0} => {1}")]
DecodeResponse(MimeType, String),
#[error("Decode json error: {0}")]
DecodeJson(#[from] serde_json::Error),
#[error("Decode xml error: {0}")]
DecodeXml(#[from] quick_xml::DeError),
#[error("Decode text error")]
DecodeText,
#[error("Illegal json: {0}")]
IllegalJson(Value),
#[error("Service error: {0} - {1:?}")]
ServiceError(i64, Option<String>),
#[error("Other error: {0}")]
Other(String),
#[error("It's impossible here.")]
Impossible,
}
impl ApiError {
pub fn new(code: i64, message: impl ToString) -> Self {
Self::ServiceError(code, Some(message.to_string()))
}
pub fn as_error_code(&self) -> i32 {
match self {
Self::ServiceDiscovery(..)
| Self::InvalidUrl(..)
| Self::BuildRequest(..)
| Self::Reqwest(..)
| Self::Middleware(..)
| Self::MultipartForm => 400,
Self::HttpClientStatus(c, _) => *c as i32,
Self::HttpServerStatus(c, _) => *c as i32,
Self::UnsupportedContentType(..)
| Self::IncompatibleContentType(..)
| Self::DecodeResponse(..)
| Self::DecodeJson(..)
| Self::DecodeXml(..)
| Self::DecodeText
| Self::IllegalJson(..) => 500,
Self::ServiceError(c, _) => *c as i32,
Self::Other(..) | Self::Impossible => 500,
}
}
}
impl From<reqwest::Error> for ApiError {
fn from(e: reqwest::Error) -> Self {
if e.is_status() {
let status = e.status().unwrap_or_default();
if status.is_client_error() {
ApiError::HttpClientStatus(status.as_u16(), status.to_string())
} else {
ApiError::HttpServerStatus(status.as_u16(), status.to_string())
}
} else {
ApiError::Reqwest(e)
}
}
}
impl From<MiddlewareError> for ApiError {
fn from(e: MiddlewareError) -> Self {
match e {
MiddlewareError::Reqwest(e) => Self::Reqwest(e),
MiddlewareError::Middleware(e) => Self::Middleware(e),
}
}
}
pub type ApiResult<T> = Result<T, ApiError>;