Skip to content

Commit

Permalink
Fix schema serde reserialization (#239)
Browse files Browse the repository at this point in the history
Currently there was an issue where Object component properties where not
deserialized correctly from openapi spec json. The issue surfaced because
serde will try to deserialize Object component as Property component for 
some reason and succesfully does it breaking the schema definition. 
This PR makes the Object as first item to try to deserialize. According 
to the tests now when Object is the first one the deserializing already 
serialized openapi json will deserialize Object properties correctly.

fixes #175
  • Loading branch information
juhaku authored Jul 31, 2022
1 parent 84f9298 commit 45e3eb4
Showing 1 changed file with 65 additions and 7 deletions.
72 changes: 65 additions & 7 deletions src/openapi/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,16 +172,16 @@ impl ComponentsBuilder {
#[cfg_attr(feature = "debug", derive(Debug))]
#[serde(untagged, rename_all = "camelCase")]
pub enum Component {
/// Defines object component. This is formed from structs holding [`Property`] components
/// created from it's fields.
Object(Object),
/// Defines property component typically used together with
/// [`Component::Object`] or [`Component::Array`]. It is used to map
/// field types to OpenAPI documentation.
Property(Property),
/// Creates a reference component _`$ref=#/components/schemas/ComponentName`_. Which
/// can be used to reference a other reusable component in [`Components`].
Ref(Ref),
/// Defines object component. This is formed from structs holding [`Property`] components
/// created from it's fields.
Object(Object),
/// Defines array component from another component. Typically used with
/// [`Component::Property`] or [`Component::Object`] component. Slice and Vec
/// types are translated to [`Component::Array`] types.
Expand Down Expand Up @@ -504,10 +504,7 @@ pub struct Object {
pub properties: BTreeMap<String, Component>,

/// Additional [`Component`] for non specified fields (Useful for typed maps).
#[serde(
skip_serializing_if = "Option::is_none",
rename = "additionalProperties"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub additional_properties: Option<Box<Component>>,

/// Description of the [`Object`]. Markdown syntax is supported.
Expand Down Expand Up @@ -1074,4 +1071,65 @@ mod tests {

assert!(matches!(array.component_type, ComponentType::Array));
}

#[test]
fn reserialize_deserialized_schema_components() {
let components = ComponentsBuilder::new()
.components_from_iter(vec![(
"Comp",
ObjectBuilder::new()
.property(
"name",
PropertyBuilder::new().component_type(ComponentType::String),
)
.required("name"),
)])
.security_scheme("TLS", SecurityScheme::MutualTls { description: None })
.build();

let serialized_components = serde_json::to_string(&components).unwrap();
let deserialized_components: Components =
serde_json::from_str(serialized_components.as_str()).unwrap();

assert_eq!(
serialized_components,
serde_json::to_string(&deserialized_components).unwrap()
)
}

#[test]
fn reserialize_deserialized_object_component() {
let prop = ObjectBuilder::new()
.property(
"name",
PropertyBuilder::new().component_type(ComponentType::String),
)
.required("name")
.build();

let serialized_components = serde_json::to_string(&prop).unwrap();
let deserialized_components: Object =
serde_json::from_str(serialized_components.as_str()).unwrap();

assert_eq!(
serialized_components,
serde_json::to_string(&deserialized_components).unwrap()
)
}

#[test]
fn reserialize_deserialized_property() {
let prop = PropertyBuilder::new()
.component_type(ComponentType::String)
.build();

let serialized_components = serde_json::to_string(&prop).unwrap();
let deserialized_components: Property =
serde_json::from_str(serialized_components.as_str()).unwrap();

assert_eq!(
serialized_components,
serde_json::to_string(&deserialized_components).unwrap()
)
}
}

0 comments on commit 45e3eb4

Please sign in to comment.