From 919fd979679e0d61c4f65b3af60cd1b1105d13aa Mon Sep 17 00:00:00 2001 From: Philippe Schaaf Date: Tue, 12 Jul 2022 10:52:49 +0200 Subject: [PATCH 1/4] 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 | 78 ++++++++++++++++++++++++++++--------------- 2 files changed, 53 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..1c216420 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,7 +552,8 @@ 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, } From 25f99d51c31d83e75e0f58dcbbe984b5f7f2d4dc Mon Sep 17 00:00:00 2001 From: Simon Bechstedt Date: Wed, 13 Jul 2022 11:58:32 +0200 Subject: [PATCH 2/4] use module schemars::map_serde Signed-off-by: Simon Bechstedt --- okapi/src/openapi3.rs | 78 +++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 52 deletions(-) diff --git a/okapi/src/openapi3.rs b/okapi/src/openapi3.rs index 1c216420..63b3e16d 100644 --- a/okapi/src/openapi3.rs +++ b/okapi/src/openapi3.rs @@ -59,8 +59,7 @@ pub struct OpenApi { pub tags: Vec, #[serde(default, skip_serializing_if = "Option::is_none")] pub external_docs: Option, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -79,8 +78,7 @@ pub struct Info { #[serde(default, skip_serializing_if = "Option::is_none")] pub license: Option, pub version: String, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -94,8 +92,7 @@ pub struct Contact { pub url: Option, #[serde(skip_serializing_if = "Option::is_none")] pub email: Option, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -106,8 +103,7 @@ pub struct License { pub name: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub url: Option, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -120,8 +116,7 @@ pub struct Server { pub description: Option, #[serde(default, skip_serializing_if = "Map::is_empty")] pub variables: Map, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -134,8 +129,7 @@ pub struct ServerVariable { pub default: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -169,8 +163,7 @@ pub struct PathItem { pub servers: Option>, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub parameters: Vec>, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -201,8 +194,7 @@ pub struct Operation { pub security: Option>, #[serde(default, skip_serializing_if = "Option::is_none")] pub servers: Option>, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -214,8 +206,7 @@ pub struct Responses { pub default: Option>, #[serde(flatten)] pub responses: Map>, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -241,8 +232,7 @@ pub struct Components { pub links: Map>, #[serde(default, skip_serializing_if = "Map::is_empty")] pub callbacks: Map>, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -257,8 +247,7 @@ pub struct Response { pub content: Map, #[serde(default, skip_serializing_if = "Map::is_empty")] pub links: Map>, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -280,8 +269,7 @@ pub struct Parameter { pub allow_empty_value: bool, #[serde(flatten)] pub value: ParameterValue, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -332,8 +320,7 @@ pub struct Example { pub description: Option, #[serde(flatten)] pub value: ExampleValue, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -354,8 +341,7 @@ pub struct RequestBody { pub content: Map, #[serde(default, skip_serializing_if = "is_false")] pub required: bool, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -373,8 +359,7 @@ pub struct Header { pub allow_empty_value: bool, #[serde(flatten)] pub value: ParameterValue, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -387,8 +372,7 @@ pub struct SecurityScheme { // This also sets `type` #[serde(flatten)] pub data: SecuritySchemeData, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -425,8 +409,7 @@ pub enum OAuthFlows { #[serde(default, skip_serializing_if = "Option::is_none")] refresh_url: Option, scopes: Map, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] extensions: Object, }, #[serde(rename_all = "camelCase")] @@ -435,8 +418,7 @@ pub enum OAuthFlows { #[serde(default, skip_serializing_if = "Option::is_none")] refresh_url: Option, scopes: Map, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] extensions: Object, }, #[serde(rename_all = "camelCase")] @@ -445,8 +427,7 @@ pub enum OAuthFlows { #[serde(default, skip_serializing_if = "Option::is_none")] refresh_url: Option, scopes: Map, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] extensions: Object, }, #[serde(rename_all = "camelCase")] @@ -456,8 +437,7 @@ pub enum OAuthFlows { #[serde(default, skip_serializing_if = "Option::is_none")] refresh_url: Option, scopes: Map, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] extensions: Object, }, } @@ -479,8 +459,7 @@ pub struct Link { pub description: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub server: Option, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -490,8 +469,7 @@ pub struct Link { pub struct Callback { #[serde(flatten)] pub callbacks: Map, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -507,8 +485,7 @@ pub struct MediaType { pub examples: Option>, #[serde(skip_serializing_if = "Map::is_empty")] pub encoding: Map, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -521,8 +498,7 @@ pub struct Tag { pub description: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub external_docs: Option, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -533,8 +509,7 @@ pub struct ExternalDocs { #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, pub url: String, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } @@ -552,8 +527,7 @@ pub struct Encoding { pub explode: Option, #[serde(skip_serializing_if = "is_false")] pub allow_reserved: bool, - #[cfg_attr(feature = "preserve_order", serde(default, with = "indexmap::serde_seq"))] - #[cfg_attr(not(feature = "preserve_order"), serde(flatten))] + #[serde(default, with = "schemars::map_serde")] pub extensions: Object, } From 0237c8a4bd010be8ba1ed3f5d2b7175416304515 Mon Sep 17 00:00:00 2001 From: Simon Bechstedt Date: Wed, 13 Jul 2022 12:00:00 +0200 Subject: [PATCH 3/4] Use patched version of schemars Use patched version until PR https://github.com/GREsau/schemars/pull/161 is merged. Signed-off-by: Simon Bechstedt --- okapi/Cargo.toml | 2 +- rocket-okapi/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/okapi/Cargo.toml b/okapi/Cargo.toml index 7e0ff67f..5924272d 100644 --- a/okapi/Cargo.toml +++ b/okapi/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["rust", "openapi", "swagger"] categories = ["web-programming"] [dependencies] -schemars = { version = "0.8", features = ["uuid1"] } +schemars = { git = "https://github.com/snpschaaf/schemars.git", branch = "feature-aware-serde-for-map", features = ["uuid1"] } indexmap = { version = "1.2", features = ["serde-1"]} serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/rocket-okapi/Cargo.toml b/rocket-okapi/Cargo.toml index ef819fad..8c79aaa1 100644 --- a/rocket-okapi/Cargo.toml +++ b/rocket-okapi/Cargo.toml @@ -12,7 +12,7 @@ categories = ["web-programming"] [dependencies] rocket = { version = "=0.5.0-rc.2", default-features = false, features = ["json"] } -schemars = { version = "0.8.10" } +schemars = { git = "https://github.com/snpschaaf/schemars.git", branch = "feature-aware-serde-for-map" } okapi = { version = "0.7.0-rc.1", path = "../okapi" } rocket_okapi_codegen = { version = "=0.8.0-rc.2", path = "../rocket-okapi-codegen" } serde = "1.0" From ac0e8035823d16e5dbc92ba5bcdf43be722df6e6 Mon Sep 17 00:00:00 2001 From: Simon Bechstedt Date: Wed, 20 Jul 2022 09:43:50 +0200 Subject: [PATCH 4/4] add test to show failure of flatten Signed-off-by: Simon Bechstedt --- Cargo.toml | 1 + .../test-flatten-extension-field/Cargo.toml | 13 ++++ .../test-flatten-extension-field/src/main.rs | 71 +++++++++++++++++++ .../tests/expected/openapi.json | 30 ++++++++ 4 files changed, 115 insertions(+) create mode 100644 examples/test-flatten-extension-field/Cargo.toml create mode 100644 examples/test-flatten-extension-field/src/main.rs create mode 100644 examples/test-flatten-extension-field/tests/expected/openapi.json diff --git a/Cargo.toml b/Cargo.toml index 56fc0a40..ecf5e424 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,5 @@ members = [ "examples/secure_request_guard", "examples/streams", "examples/dyn_templates", + "examples/test-flatten-extension-field", ] diff --git a/examples/test-flatten-extension-field/Cargo.toml b/examples/test-flatten-extension-field/Cargo.toml new file mode 100644 index 00000000..e42cd79d --- /dev/null +++ b/examples/test-flatten-extension-field/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "test-flatten-extension-field" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rocket = { version = "=0.5.0-rc.2", default-features = false, features = ["json"] } +rocket_okapi = {path = "../../rocket-okapi", features = ["swagger"]} + +[dev-dependencies] +pretty_assertions = "1.2.1" \ No newline at end of file diff --git a/examples/test-flatten-extension-field/src/main.rs b/examples/test-flatten-extension-field/src/main.rs new file mode 100644 index 00000000..2174b6b8 --- /dev/null +++ b/examples/test-flatten-extension-field/src/main.rs @@ -0,0 +1,71 @@ +#[macro_use] extern crate rocket; + +use rocket::{Build, Config, Rocket}; +use rocket::config::LogLevel; +use rocket::http::Status; +use rocket_okapi::{openapi_get_routes, openapi}; +use rocket_okapi::swagger_ui::{make_swagger_ui, SwaggerUIConfig}; + + + +fn get_docs() -> SwaggerUIConfig { + SwaggerUIConfig { + url: "/openapi.json".to_string(), + ..Default::default() + } +} + + +#[openapi] +#[get("/")] +pub(crate) async fn test_index() -> Result { + Ok("I am here as a dummy route for the OpenAPI spec".to_string()) +} + + +#[launch] +fn rocket() -> Rocket { + let config = Config { + log_level : LogLevel::Normal, + ..Config::debug_default() + }; + + rocket::custom(&config) + .mount("/", openapi_get_routes![test_index]) + .mount("/swagger", make_swagger_ui(&get_docs())) +} + +#[cfg(test)] +mod expected_unit_test { + use rocket::serde::json::serde_json; + use rocket_okapi::okapi::openapi3::OpenApi; + use rocket_okapi::openapi_get_spec; + use pretty_assertions::{assert_eq}; + use crate::*; + + #[test] + fn openapi_cmp() { + let ref_data = std::fs::read_to_string("./tests/expected/openapi.json").unwrap(); + let expected_spec : OpenApi = serde_json::from_str(&ref_data).unwrap(); + let current_spec : OpenApi = openapi_get_spec![test_index]; + assert_eq!(expected_spec, current_spec); + } + + #[test] + fn string_cmp() { + // Expected to ALWAYS pass. Included to ensure the expected-file is correct. + + let ref_data = std::fs::read_to_string("./tests/expected/openapi.json").unwrap(); + let current_spec: OpenApi = openapi_get_spec![test_index]; + /* Note: + Depending on whether or not the reference file is pretty printed we have to use to_string_pretty or to_string. + + The "better" way would be to deserialize ref_data to type OpenApi, however currently the deserialization is not working as expected + due to an error with flattening some 'extensions' fields in structs of okapi::openapi3. + */ + let current_str = serde_json::to_string_pretty(¤t_spec).unwrap(); + // below: not-pretty-printed version + // let current_str = serde_json::to_string(¤t_spec).unwrap(); + assert_eq!(ref_data, current_str); + } +} \ No newline at end of file diff --git a/examples/test-flatten-extension-field/tests/expected/openapi.json b/examples/test-flatten-extension-field/tests/expected/openapi.json new file mode 100644 index 00000000..b9360393 --- /dev/null +++ b/examples/test-flatten-extension-field/tests/expected/openapi.json @@ -0,0 +1,30 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "test-flatten-extension-field", + "version": "0.1.0" + }, + "paths": { + "/": { + "get": { + "operationId": "test_index", + "responses": { + "200": { + "description": "", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "default": { + "description": "" + } + } + } + } + }, + "components": {} +} \ No newline at end of file