From 46ec2a2d3ea7eae36b145ee4ad4af214bc1484e1 Mon Sep 17 00:00:00 2001 From: Philippe Schaaf Date: Tue, 12 Jul 2022 10:35:02 +0200 Subject: [PATCH] fix deserialisation for indexmap case The 'extensions' fields of various structs within okapi/src/openapi3.rs was not deserialized correctly. This commit fixes the behavior if the Object is an indexmap. Using rocket_okapi enables the feature 'preserve_order' by default and hence an indexmap is used. If the feature 'preserve_order' is disables, this commit should not change the behavior. Belongs to https://github.com/GREsau/okapi/issues/67 Signed-off-by: Philippe Schaaf --- okapi/Cargo.toml | 1 + okapi/src/openapi3.rs | 126 +++++++++++++++++++++++++++++++++--------- 2 files changed, 101 insertions(+), 26 deletions(-) diff --git a/okapi/Cargo.toml b/okapi/Cargo.toml index d923eff5..7e0ff67f 100644 --- a/okapi/Cargo.toml +++ b/okapi/Cargo.toml @@ -12,6 +12,7 @@ categories = ["web-programming"] [dependencies] schemars = { version = "0.8", features = ["uuid1"] } +indexmap = { version = "1.2", features = ["serde-1"]} serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" log = "0.4" diff --git a/okapi/src/openapi3.rs b/okapi/src/openapi3.rs index a82c1817..760ff815 100644 --- a/okapi/src/openapi3.rs +++ b/okapi/src/openapi3.rs @@ -59,7 +59,8 @@ pub struct OpenApi { pub tags: Vec, #[serde(default, skip_serializing_if = "Option::is_none")] pub external_docs: Option, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -78,7 +79,8 @@ pub struct Info { #[serde(default, skip_serializing_if = "Option::is_none")] pub license: Option, pub version: String, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -92,7 +94,8 @@ pub struct Contact { pub url: Option, #[serde(skip_serializing_if = "Option::is_none")] pub email: Option, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -103,7 +106,8 @@ pub struct License { pub name: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub url: Option, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -116,7 +120,8 @@ pub struct Server { pub description: Option, #[serde(default, skip_serializing_if = "Map::is_empty")] pub variables: Map, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -129,7 +134,8 @@ pub struct ServerVariable { pub default: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -163,7 +169,8 @@ pub struct PathItem { pub servers: Option>, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub parameters: Vec>, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -194,7 +201,8 @@ pub struct Operation { pub security: Option>, #[serde(default, skip_serializing_if = "Option::is_none")] pub servers: Option>, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -206,7 +214,8 @@ pub struct Responses { pub default: Option>, #[serde(flatten)] pub responses: Map>, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -232,7 +241,8 @@ pub struct Components { pub links: Map>, #[serde(default, skip_serializing_if = "Map::is_empty")] pub callbacks: Map>, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -247,7 +257,8 @@ pub struct Response { pub content: Map, #[serde(default, skip_serializing_if = "Map::is_empty")] pub links: Map>, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -269,7 +280,8 @@ pub struct Parameter { pub allow_empty_value: bool, #[serde(flatten)] pub value: ParameterValue, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -320,7 +332,8 @@ pub struct Example { pub description: Option, #[serde(flatten)] pub value: ExampleValue, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -341,7 +354,8 @@ pub struct RequestBody { pub content: Map, #[serde(default, skip_serializing_if = "is_false")] pub required: bool, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -359,7 +373,8 @@ pub struct Header { pub allow_empty_value: bool, #[serde(flatten)] pub value: ParameterValue, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -372,7 +387,8 @@ pub struct SecurityScheme { // This also sets `type` #[serde(flatten)] pub data: SecuritySchemeData, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -409,7 +425,8 @@ pub enum OAuthFlows { #[serde(default, skip_serializing_if = "Option::is_none")] refresh_url: Option, scopes: Map, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] extensions: Object, }, #[serde(rename_all = "camelCase")] @@ -418,7 +435,8 @@ pub enum OAuthFlows { #[serde(default, skip_serializing_if = "Option::is_none")] refresh_url: Option, scopes: Map, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] extensions: Object, }, #[serde(rename_all = "camelCase")] @@ -427,7 +445,8 @@ pub enum OAuthFlows { #[serde(default, skip_serializing_if = "Option::is_none")] refresh_url: Option, scopes: Map, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] extensions: Object, }, #[serde(rename_all = "camelCase")] @@ -437,7 +456,8 @@ pub enum OAuthFlows { #[serde(default, skip_serializing_if = "Option::is_none")] refresh_url: Option, scopes: Map, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] extensions: Object, }, } @@ -459,7 +479,8 @@ pub struct Link { pub description: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub server: Option, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -469,7 +490,8 @@ pub struct Link { pub struct Callback { #[serde(flatten)] pub callbacks: Map, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -485,7 +507,8 @@ pub struct MediaType { pub examples: Option>, #[serde(skip_serializing_if = "Map::is_empty")] pub encoding: Map, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -498,7 +521,8 @@ pub struct Tag { pub description: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub external_docs: Option, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -509,7 +533,8 @@ pub struct ExternalDocs { #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, pub url: String, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } @@ -527,10 +552,59 @@ pub struct Encoding { pub explode: Option, #[serde(skip_serializing_if = "is_false")] pub allow_reserved: bool, - #[serde(flatten)] + #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] + #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] pub extensions: Object, } fn is_false(b: impl std::borrow::Borrow) -> bool { !b.borrow() } + +#[cfg(test)] +mod test { + use crate::*; + + #[test] + fn test_openapi3_extension(){ + + Object( + Parameter { + name: "switch_id", + location: "path", + description: None, + required: true, + deprecated: false, + allow_empty_value: false, + value: Schema { + style: None, + explode: None, + allow_reserved: false, + schema: SchemaObject { + metadata: None, + instance_type: Some( + Single( + String, + ), + ), + format: None, + enum_values: None, + const_value: None, + subschemas: None, + number: None, + string: None, + array: None, + object: None, + reference: None, + extensions: {}, + }, + example: None, + examples: None, + }, + extensions: {}, + }, + ); + + + } +} \ No newline at end of file