improved error messages
continuous-integration/drone/push Build is passing Details

This commit is contained in:
LordMZTE 2021-01-05 20:05:13 +01:00
parent bb33d3b015
commit 10c5cb88db
4 changed files with 47 additions and 5 deletions

View File

@ -3,4 +3,5 @@
## cli
- optimized listing by not searching on the client but on the server
- categories now shown with name instead of just ID
- improved API response deserialize error messages

View File

@ -15,6 +15,7 @@ anyhow = "1.0.34"
clap = "2.33.3"
env_logger = "0.8.2"
fuzzy-matcher = "0.3.7"
lazy_static = "1.4.0"
log = "0.4.11"
once_cell = "1.5.2"
opener = "0.4.1"
@ -24,7 +25,7 @@ serde_json = "1.0.60"
structopt = "0.3.21"
term-table = "1.3.0"
term_size = "0.3.2"
thiserror = "1.0.23"
tokio = { version = "0.2.23", features = ["macros", "fs", "process"] }
url = "2.2.0"
lazy_static = "1.4.0"

View File

@ -41,7 +41,7 @@ pub async fn run(
.await?;
let status = res.status();
let res = serde_json::from_slice::<UpResp>(&res.bytes().await?)?;
let res = util::api::try_deserialize_api_reponse::<UpResp>(&res.bytes().await?)?;
println!("Server responded with code {}", status);

View File

@ -35,6 +35,7 @@ pub mod api {
collections::HashMap,
sync::{Arc, Mutex},
};
use thiserror::Error;
use url::Url;
// cached api responses
@ -46,6 +47,14 @@ pub mod api {
Mutex::new(HashMap::new());
}
#[derive(Error, Debug)]
#[error("Error Deserializing JSON api response: \n{json}\nError: {error}")]
pub struct ApiDeserializeError {
pub json: String,
#[source]
pub error: serde_json::Error,
}
pub async fn cats(http: &Client) -> Result<&Vec<Category>> {
Ok(init_once_cell!(CATS, {
info!("Requesting categories from server");
@ -53,7 +62,7 @@ pub mod api {
.get("https://data.tilera.xyz/api/jensmemes/categories")
.send()
.await?;
let cats = serde_json::from_slice::<CatsResp>(&res.bytes().await?)?;
let cats = try_deserialize_api_reponse::<CatsResp>(&res.bytes().await?)?;
cats.categories.into_iter().collect()
}))
}
@ -84,7 +93,7 @@ pub mod api {
info!("Requesting memes from server");
let res = http.get(url).send().await?;
let memes = serde_json::from_slice::<MemesResp>(&res.bytes().await?)?;
let memes = try_deserialize_api_reponse::<MemesResp>(&res.bytes().await?)?;
Ok(MEMES
.lock()
@ -101,10 +110,41 @@ pub mod api {
.get("https://data.tilera.xyz/api/jensmemes/users")
.send()
.await?;
let users = serde_json::from_slice::<UsersResp>(&res.bytes().await?)?;
let users = try_deserialize_api_reponse::<UsersResp>(&res.bytes().await?)?;
users.users
}))
}
/// tries to deserialize `json` as `T`, and if it fails converts the error
/// to a `ApiDeserializeError`
pub fn try_deserialize_api_reponse<'a, T: serde::Deserialize<'a>>(json: &'a [u8]) -> Result<T> {
let result = serde_json::from_slice::<T>(&json);
result.map_err(|error| match std::str::from_utf8(json) {
Err(e) => e.into(),
Ok(json) => ApiDeserializeError {
json: json.into(),
error,
}
.into(),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn api_deserialize_error() {
let incorrect_json = r#"
{
"foo": "bar"
}
"#;
let result = try_deserialize_api_reponse::<UsersResp>(incorrect_json.as_bytes());
println!("{}", result.unwrap_err());
}
}
}
pub async fn open_link(url: &str) -> anyhow::Result<()> {