use std::{collections::HashMap, fmt::Display};
use serde::{Deserialize, Deserializer};
use thiserror::Error;
use crate::results::result_code::ResultCode;
#[derive(Debug, Deserialize)]
pub struct ApiError {
code: ResultCode,
message: String,
#[serde(deserialize_with = "deserialize_validations")]
validations: HashMap<String, Vec<String>>,
}
impl std::error::Error for ApiError {}
impl Display for ApiError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(
f,
"Error code ({}) ocurred while communicating with zarinpal api: {}",
self.code, self.message
)?;
writeln!(f, "Here're detailed information:")?;
writeln!(f, "{:#?}", self.validations)
}
}
impl ApiError {
pub fn code(&self) -> ResultCode {
self.code
}
pub fn message(&self) -> &str {
self.message.as_ref()
}
pub fn validations(&self) -> &HashMap<String, Vec<String>> {
&self.validations
}
}
fn deserialize_validations<'de, D>(
deserializer: D,
) -> Result<HashMap<String, Vec<String>>, D::Error>
where
D: Deserializer<'de>,
{
let opening = Vec::<HashMap<String, String>>::deserialize(deserializer)?;
let mut result = HashMap::<String, Vec<String>>::new();
for item in opening {
for (key, val) in item {
let entry = result.entry(key);
let vec = entry.or_insert_with(|| vec![]);
vec.push(val)
}
}
Ok(result)
}
#[derive(Debug, Error)]
pub enum Error {
#[error("Zarinpal api error: {0}")]
ZarinpalApiError(ApiError),
#[error("Http client error: {0}")]
HttpClientError(reqwest::Error),
}
impl From<reqwest::Error> for Error {
fn from(value: reqwest::Error) -> Self {
Error::HttpClientError(value)
}
}
impl From<ApiError> for Error {
fn from(value: ApiError) -> Self {
Error::ZarinpalApiError(value)
}
}
pub type ZarinResult<T> = Result<T, Error>;