From fa9f59ad70b125d9cbd6bf04a914fc584ccd90a2 Mon Sep 17 00:00:00 2001 From: Danilo Date: Wed, 8 Sep 2021 19:44:29 +0200 Subject: [PATCH 1/2] Serialize and deserialize detail as JSON string --- src/distribution/error.rs | 42 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/distribution/error.rs b/src/distribution/error.rs index 5fa5fb4174..5688390a19 100644 --- a/src/distribution/error.rs +++ b/src/distribution/error.rs @@ -90,13 +90,53 @@ pub struct ErrorInfo { /// MAY be empty. message: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(default, skip_serializing_if = "Option::is_none", with = "json_string")] #[builder(default = "None")] /// The detail field is OPTIONAL and MAY contain arbitrary JSON data providing information /// the client can use to resolve the issue. detail: Option, } +mod json_string { + use std::str::FromStr; + + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + use serde::de::Error; + + let opt = Option::::deserialize(deserializer)?; + + if let Some(data) = opt { + let data = serde_json::to_string(&data).map_err(Error::custom)?; + return Ok(Some(data)); + } + + Ok(None) + } + + pub fn serialize(target: &Option, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::Error; + + match target { + Some(data) => { + if let Ok(json_value) = serde_json::Value::from_str(data) { + json_value.serialize(serializer) + } else { + Err(Error::custom("invalid JSON")) + } + } + _ => unreachable!(), + } + } +} + #[cfg(test)] mod tests { use super::*; From abdffd50567ee8c3ca6cf5e969f0e81fc81842f8 Mon Sep 17 00:00:00 2001 From: Danilo Date: Wed, 8 Sep 2021 19:44:44 +0200 Subject: [PATCH 2/2] Add tests for detail serde --- src/distribution/error.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/distribution/error.rs b/src/distribution/error.rs index 5688390a19..30d4f93026 100644 --- a/src/distribution/error.rs +++ b/src/distribution/error.rs @@ -170,4 +170,43 @@ mod tests { fn error_info_failure() { assert!(ErrorInfoBuilder::default().build().is_err()); } + + #[test] + fn error_info_serialize_success() -> Result<()> { + let error_info = ErrorInfoBuilder::default() + .code(ErrorCode::Unauthorized) + .detail(String::from("{ \"key\": \"value\" }")) + .build()?; + + assert!(serde_json::to_string(&error_info).is_ok()); + Ok(()) + } + + #[test] + fn error_info_serialize_failure() -> Result<()> { + let error_info = ErrorInfoBuilder::default() + .code(ErrorCode::Unauthorized) + .detail(String::from("abcd")) + .build()?; + + assert!(serde_json::to_string(&error_info).is_err()); + Ok(()) + } + + #[test] + fn error_info_deserialize_success() -> Result<()> { + let error_info_str = r#" + { + "code": "MANIFEST_UNKNOWN", + "message": "manifest tagged by \"lates\" is not found", + "detail": { + "Tag": "lates" + } + }"#; + + let error_info: ErrorInfo = serde_json::from_str(&error_info_str)?; + assert_eq!(error_info.detail().as_ref().unwrap(), "{\"Tag\":\"lates\"}"); + + Ok(()) + } }