use reqwest::StatusCode;
use serde::Deserialize;
use thiserror::Error;
pub type ApiResult<T> = Result<T, ApiError>;
#[derive(Debug, Error)]
pub enum ApiError {
#[error("Authorization failed. Check your .ROBLOSECURITY cookie.")]
AuthorizationFailed,
#[error("Roblox error ({status_code}) : {reason}")]
Roblox {
status_code: StatusCode,
reason: String,
},
#[error("Failed to parse JSON response: {0}")]
ParseJson(#[from] serde_json::Error),
#[error("Request Error")]
RequestError { reason: String },
}
impl From<ApiError> for String {
fn from(e: ApiError) -> Self {
e.to_string()
}
}
impl From<reqwest::Error> for ApiError {
fn from(value: reqwest::Error) -> Self {
ApiError::RequestError {
reason: value.to_string(),
}
}
}
#[derive(Deserialize, Debug)]
pub struct RobloxApiErrorResponse {
#[serde(alias = "Message")]
pub message: Option<String>,
#[serde(alias = "Title")]
pub title: Option<String>,
#[serde(alias = "Errors")]
pub errors: Option<Vec<RobloxApiErrorResponse>>,
#[serde(alias = "Success")]
pub success: Option<bool>,
}
impl RobloxApiErrorResponse {
pub fn is_empty(&self) -> bool {
self.message.is_none()
&& self.title.is_none()
&& self.errors.is_none()
&& self.success.is_none()
}
pub fn reason(self) -> Option<String> {
if let Some(message) = self.message {
return Some(message);
} else if let Some(title) = self.title {
return Some(title);
} else if let Some(errors) = self.errors {
for error in errors {
if let Some(message) = error.reason() {
return Some(message);
}
}
return None;
}
None
}
}