feat(api): enhance error handling with serde_path_to_error integration
Some checks failed
build / checks-build (push) Has been cancelled
build / codecov (push) Has been cancelled
docs / docs (push) Has been cancelled
build / checks-matrix (push) Has been cancelled

This commit is contained in:
uttarayan21
2025-10-08 15:35:41 +05:30
parent c18e92ff01
commit 160ca86da5
4 changed files with 51 additions and 13 deletions

View File

@@ -7,8 +7,8 @@ use thiserror::Error;
pub enum ApiError {
#[error("HTTP request failed: {0}")]
Request(#[from] reqwest::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("Deserialization error: {0}")]
Deserialization(#[from] serde_path_to_error::Error<serde_json::Error>),
#[error("API error: {message}")]
Api { message: String },
}
@@ -47,7 +47,31 @@ impl SonarrClient {
}
let text = response.text().await?;
serde_json::from_str(&text).map_err(ApiError::from)
let deser = &mut serde_json::Deserializer::from_str(&text);
serde_path_to_error::deserialize(deser).map_err(ApiError::from)
}
async fn get_debug<T: for<'de> Deserialize<'de>>(&self, endpoint: &str) -> Result<T> {
let url = format!("{}/api/v3{}", self.base_url, endpoint);
let response = self
.client
.get(&url)
.header("X-Api-Key", &self.api_key)
.send()
.await?;
if !response.status().is_success() {
return Err(ApiError::Api {
message: format!("HTTP {}: {}", response.status(), response.text().await?),
});
}
let text = response.text().await?;
std::fs::write(endpoint.replace("/", "_"), &text);
let deser = &mut serde_json::Deserializer::from_str(&text);
serde_path_to_error::deserialize(deser).map_err(ApiError::from)
}
async fn post<T: Serialize, R: for<'de> Deserialize<'de>>(
@@ -71,7 +95,8 @@ impl SonarrClient {
}
let text = response.text().await?;
serde_json::from_str(&text).map_err(ApiError::from)
let deser = &mut serde_json::Deserializer::from_str(&text);
serde_path_to_error::deserialize(deser).map_err(ApiError::from)
}
pub async fn get_system_status(&self) -> Result<SystemStatus> {
@@ -147,7 +172,7 @@ impl SonarrClient {
}
pub async fn search_series(&self, term: &str) -> Result<Vec<Series>> {
self.get(&format!(
self.get_debug(&format!(
"/series/lookup?term={}",
urlencoding::encode(term)
))
@@ -199,7 +224,7 @@ pub struct SystemStatus {
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Series {
pub id: u32,
pub id: Option<u32>,
pub title: Option<String>,
pub alternate_titles: Option<Vec<AlternateTitle>>,
pub sort_title: Option<String>,
@@ -215,14 +240,14 @@ pub struct Series {
pub original_language: Option<Language>,
pub remote_poster: Option<String>,
pub seasons: Option<Vec<Season>>,
pub year: i32,
pub year: u32,
pub path: Option<String>,
pub quality_profile_id: u32,
pub season_folder: bool,
pub monitored: bool,
pub monitor_new_items: String,
pub use_scene_numbering: bool,
pub runtime: i32,
pub runtime: u32,
pub tvdb_id: u32,
pub tv_rage_id: u32,
pub tv_maze_id: u32,
@@ -501,8 +526,8 @@ pub struct HistoryItem {
pub quality_cutoff_not_met: bool,
pub date: chrono::DateTime<chrono::Utc>,
pub download_id: Option<String>,
pub event_type: String,
pub data: Option<HashMap<String, String>>,
pub event_type: Option<String>,
pub data: Option<HashMap<String, Option<String>>>,
pub episode: Option<Episode>,
pub series: Option<Series>,
}
@@ -521,7 +546,7 @@ pub struct EpisodePagingResource {
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct HealthResource {
pub id: u32,
pub id: Option<i32>,
pub source: Option<String>,
#[serde(rename = "type")]
pub health_type: String,

View File

@@ -901,7 +901,7 @@ fn render_history_tab(f: &mut Frame, area: Rect, app: &App) {
.as_ref()
.map(|e| format!("S{:02}E{:02}", e.season_number, e.episode_number))
.unwrap_or_default();
let event = &h.event_type;
let event = h.event_type.as_deref().unwrap_or("Unknown");
let quality = h
.quality
.as_ref()
@@ -912,7 +912,7 @@ fn render_history_tab(f: &mut Frame, area: Rect, app: &App) {
Cell::from(date),
Cell::from(series),
Cell::from(episode),
Cell::from(event.as_str()),
Cell::from(event),
Cell::from(quality),
])
})