Catch and raise when API response data cannot be deserialized

* Introduce a `StringOrObject::Value` variant that captures the
  undeserializable JSON value
* Generate an error with the undeserializable JSON value when
  deserialization is attempted
This commit is contained in:
Paul van Tilburg 2023-01-16 20:00:53 +01:00
parent e268a6ebca
commit e1d70e8a59
Signed by: paul
GPG Key ID: C6DE073EDA9EEC4D
1 changed files with 10 additions and 2 deletions

View File

@ -9,7 +9,7 @@ use std::sync::Arc;
use chrono::{DateTime, Local, TimeZone}; use chrono::{DateTime, Local, TimeZone};
use md5::{Digest, Md5}; use md5::{Digest, Md5};
use reqwest::{cookie::Jar as CookieJar, Client, ClientBuilder, Url}; use reqwest::{cookie::Jar as CookieJar, Client, ClientBuilder, Url};
use rocket::async_trait; use rocket::{async_trait, serde::json::Value as JsonValue};
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
use url::ParseError; use url::ParseError;
@ -86,7 +86,8 @@ fn api_url() -> Result<Url, ParseError> {
/// Captures JSON values that can either be a string or an object. /// Captures JSON values that can either be a string or an object.
/// ///
/// This is used for the API responses where the data field is either an object or an empty string /// This is used for the API responses where the data field is either an object or an empty string
/// instead of `null`. /// instead of `null`. If the response is not deserializable object, the JSON value is preserved
/// for debugging purposes.
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
enum StringOrObject<'a, T> { enum StringOrObject<'a, T> {
@ -94,6 +95,8 @@ enum StringOrObject<'a, T> {
Object(T), Object(T),
/// The value is a string. /// The value is a string.
String(&'a str), String(&'a str),
/// The value is not some JSON value not deserializable as type `T`.
Value(JsonValue),
} }
/// Deserialize either a string or an object as an option of type `T`. /// Deserialize either a string or an object as an option of type `T`.
@ -109,6 +112,11 @@ where
Ok(StringOrObject::String(s)) if s.is_empty() => Ok(None), Ok(StringOrObject::String(s)) if s.is_empty() => Ok(None),
Ok(StringOrObject::String(_)) => Err(Error::custom("Non-empty string not allowed here")), Ok(StringOrObject::String(_)) => Err(Error::custom("Non-empty string not allowed here")),
Ok(StringOrObject::Object(t)) => Ok(Some(t)), Ok(StringOrObject::Object(t)) => Ok(Some(t)),
Ok(StringOrObject::Value(j)) => Err(Error::custom(&format!(
"Undeserializable JSON object: {}",
j
))),
Err(err) => Err(err), Err(err) => Err(err),
} }
} }