Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ members = [
"examples/secure_request_guard",
"examples/streams",
"examples/dyn_templates",
"examples/test-flatten-extension-field",
]
13 changes: 13 additions & 0 deletions examples/test-flatten-extension-field/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
71 changes: 71 additions & 0 deletions examples/test-flatten-extension-field/src/main.rs
Original file line number Diff line number Diff line change
@@ -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<String, Status> {
Ok("I am here as a dummy route for the OpenAPI spec".to_string())
}


#[launch]
fn rocket() -> Rocket<Build> {
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(&current_spec).unwrap();
// below: not-pretty-printed version
// let current_str = serde_json::to_string(&current_spec).unwrap();
assert_eq!(ref_data, current_str);
}
}
30 changes: 30 additions & 0 deletions examples/test-flatten-extension-field/tests/expected/openapi.json
Original file line number Diff line number Diff line change
@@ -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": {}
}
3 changes: 2 additions & 1 deletion okapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ 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"
log = "0.4"
Expand Down
52 changes: 26 additions & 26 deletions okapi/src/openapi3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub struct OpenApi {
pub tags: Vec<Tag>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub external_docs: Option<ExternalDocs>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -78,7 +78,7 @@ pub struct Info {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub license: Option<License>,
pub version: String,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -92,7 +92,7 @@ pub struct Contact {
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -103,7 +103,7 @@ pub struct License {
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -116,7 +116,7 @@ pub struct Server {
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Map::is_empty")]
pub variables: Map<String, ServerVariable>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -129,7 +129,7 @@ pub struct ServerVariable {
pub default: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand Down Expand Up @@ -163,7 +163,7 @@ pub struct PathItem {
pub servers: Option<Vec<Server>>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub parameters: Vec<RefOr<Parameter>>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand Down Expand Up @@ -194,7 +194,7 @@ pub struct Operation {
pub security: Option<Vec<SecurityRequirement>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub servers: Option<Vec<Server>>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -206,7 +206,7 @@ pub struct Responses {
pub default: Option<RefOr<Response>>,
#[serde(flatten)]
pub responses: Map<String, RefOr<Response>>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -232,7 +232,7 @@ pub struct Components {
pub links: Map<String, RefOr<Link>>,
#[serde(default, skip_serializing_if = "Map::is_empty")]
pub callbacks: Map<String, RefOr<Callback>>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -247,7 +247,7 @@ pub struct Response {
pub content: Map<String, MediaType>,
#[serde(default, skip_serializing_if = "Map::is_empty")]
pub links: Map<String, RefOr<Link>>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -269,7 +269,7 @@ pub struct Parameter {
pub allow_empty_value: bool,
#[serde(flatten)]
pub value: ParameterValue,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand Down Expand Up @@ -320,7 +320,7 @@ pub struct Example {
pub description: Option<String>,
#[serde(flatten)]
pub value: ExampleValue,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -341,7 +341,7 @@ pub struct RequestBody {
pub content: Map<String, MediaType>,
#[serde(default, skip_serializing_if = "is_false")]
pub required: bool,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -359,7 +359,7 @@ pub struct Header {
pub allow_empty_value: bool,
#[serde(flatten)]
pub value: ParameterValue,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -372,7 +372,7 @@ pub struct SecurityScheme {
// This also sets `type`
#[serde(flatten)]
pub data: SecuritySchemeData,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand Down Expand Up @@ -409,7 +409,7 @@ pub enum OAuthFlows {
#[serde(default, skip_serializing_if = "Option::is_none")]
refresh_url: Option<String>,
scopes: Map<String, String>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
extensions: Object,
},
#[serde(rename_all = "camelCase")]
Expand All @@ -418,7 +418,7 @@ pub enum OAuthFlows {
#[serde(default, skip_serializing_if = "Option::is_none")]
refresh_url: Option<String>,
scopes: Map<String, String>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
extensions: Object,
},
#[serde(rename_all = "camelCase")]
Expand All @@ -427,7 +427,7 @@ pub enum OAuthFlows {
#[serde(default, skip_serializing_if = "Option::is_none")]
refresh_url: Option<String>,
scopes: Map<String, String>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
extensions: Object,
},
#[serde(rename_all = "camelCase")]
Expand All @@ -437,7 +437,7 @@ pub enum OAuthFlows {
#[serde(default, skip_serializing_if = "Option::is_none")]
refresh_url: Option<String>,
scopes: Map<String, String>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
extensions: Object,
},
}
Expand All @@ -459,7 +459,7 @@ pub struct Link {
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub server: Option<Server>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -469,7 +469,7 @@ pub struct Link {
pub struct Callback {
#[serde(flatten)]
pub callbacks: Map<String, PathItem>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -485,7 +485,7 @@ pub struct MediaType {
pub examples: Option<Map<String, Example>>,
#[serde(skip_serializing_if = "Map::is_empty")]
pub encoding: Map<String, Encoding>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -498,7 +498,7 @@ pub struct Tag {
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub external_docs: Option<ExternalDocs>,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -509,7 +509,7 @@ pub struct ExternalDocs {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub url: String,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand All @@ -527,7 +527,7 @@ pub struct Encoding {
pub explode: Option<bool>,
#[serde(skip_serializing_if = "is_false")]
pub allow_reserved: bool,
#[serde(flatten)]
#[serde(default, with = "schemars::map_serde")]
pub extensions: Object,
}

Expand Down
2 changes: 1 addition & 1 deletion rocket-okapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down