From 8510ed3e43ff0a92565815b02645cc7bf5cb6b18 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Thu, 7 Oct 2021 23:19:31 +0200 Subject: Modernize error handling This sprinkles in some thiserror and anyhow instead of the hand-rolled 'error_froms!' macros and the MainResult. The benefit of this is that we're hooking into an established ecosystem of error handling and we're saving a lot of effort in the hand-written Display and Error implementations. The reason for not sprinkling anyhow everywhere is because the retrieval/rendering part of kondou could be split off into a library at some point, in which case we want to have a proper KondouError type. However, the argument could be made that the current split of errors is not very good, especially because many of them boil down to the same inner errors (RenderError wrapping ApiError wrapping reqwest::Error), which keeps unnecessary information. Some future improvements may include 1.) Unifying those error enums into one bigger enum 2.) Attaching more context through anyhow in the application layer 3.) Properly define an API and split off the inner logic from the UI logic --- src/api/mod.rs | 49 ++++++++++++------------------------------------- 1 file changed, 12 insertions(+), 37 deletions(-) (limited to 'src/api') diff --git a/src/api/mod.rs b/src/api/mod.rs index 1d069cd..7cec4e6 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -18,51 +18,26 @@ use image::DynamicImage; use itertools::Itertools; use reqwest::{blocking::Client, StatusCode, Url}; use serde::{de::DeserializeOwned, Serialize}; -use std::{error::Error, fmt, path::Path}; +use std::path::Path; +use thiserror::Error; use super::cache::{Cache, CacheError}; /// The base URL of the official Guild Wars 2 API. const BASE_URL: &str = "https://api.guildwars2.com/v2/"; -#[derive(Debug)] +#[derive(Error, Debug)] pub enum ApiError { + #[error("The requested item could not be found in the API")] ItemNotFound, - SerializationError(serde_json::Error), - CacheError(CacheError), - HttpError(reqwest::Error), - ImageError(image::ImageError), -} - -error_froms! { ApiError, - err: serde_json::Error => ApiError::SerializationError(err), - err: CacheError => ApiError::CacheError(err), - err: reqwest::Error => ApiError::HttpError(err), - err: image::ImageError => ApiError::ImageError(err), -} - -impl fmt::Display for ApiError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ApiError::ItemNotFound => write!(f, "the requested item was not found in the API"), - ApiError::SerializationError(_) => write!(f, "error deserializing the returned value"), - ApiError::CacheError(_) => write!(f, "error accessing the cache"), - ApiError::HttpError(_) => write!(f, "HTTP error"), - ApiError::ImageError(_) => write!(f, "image processing error"), - } - } -} - -impl Error for ApiError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match *self { - ApiError::SerializationError(ref err) => Some(err), - ApiError::CacheError(ref err) => Some(err), - ApiError::HttpError(ref err) => Some(err), - ApiError::ImageError(ref err) => Some(err), - _ => None, - } - } + #[error("Error deserializing the API response")] + SerializationError(#[from] serde_json::Error), + #[error("Error accessing the cache")] + CacheError(#[from] CacheError), + #[error("Underlying HTTP error")] + HttpError(#[from] reqwest::Error), + #[error("Image loading error")] + ImageError(#[from] image::ImageError), } trait ApiResponse -- cgit v1.2.3