diff --git a/modules/openapi-generator/src/test/resources/2_0/rust-server/rust-server-test.yaml b/modules/openapi-generator/src/test/resources/2_0/rust-server/rust-server-test.yaml index 75f693b7207..884c55e1113 100644 --- a/modules/openapi-generator/src/test/resources/2_0/rust-server/rust-server-test.yaml +++ b/modules/openapi-generator/src/test/resources/2_0/rust-server/rust-server-test.yaml @@ -1,7 +1,7 @@ swagger: '2.0' info: description: "This spec is for testing rust-server-specific things" - version: 2.0.0 + version: 2.3.4 title: rust-server-test schemes: - http @@ -12,6 +12,12 @@ paths: responses: '200': description: Success + put: + parameters: + - $ref: '#/parameters/nested_response' + responses: + '200': + description: Success /html: post: summary: Test HTML handling @@ -28,6 +34,20 @@ paths: description: Success schema: type: string +parameters: + nested_response: + name: nested_response + in: body + required: true + schema: + # Erroneously ends up as `Option` + properties: + id: + type: string + password: + type: string + required: + - id definitions: additionalPropertiesObject: description: An additionalPropertiesObject @@ -46,3 +66,31 @@ definitions: x-nullable: true required: - RequiredNullableThing + ObjectOfObjects: + description: An object of objects + type: object + properties: + inner: + type: object + required: + - required_thing + properties: + required_thing: + type: string + optional_thing: + type: integer + # Currently broken - see https://github.com/OpenAPITools/openapi-generator/issues/8 + # ArrayOfObjects: + # description: An array of objects + # type: array + # items: + # properties: + # filename: + # description: A non-required property + # type: string + # contents: + # description: A required property + # type: string + # required: + # - contents + # type: object diff --git a/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml b/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml index 5cdbcb00d64..b2ce2b37fc7 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml +++ b/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust-server-test" -version = "2.0.0" +version = "2.3.4" authors = [] description = "This spec is for testing rust-server-specific things" license = "Unlicense" diff --git a/samples/server/petstore/rust-server/output/rust-server-test/README.md b/samples/server/petstore/rust-server/output/rust-server-test/README.md index daaa9194d4c..e73332bb06f 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/README.md +++ b/samples/server/petstore/rust-server/output/rust-server-test/README.md @@ -12,7 +12,7 @@ To see how to make this your own, look here: [README]((https://openapi-generator.tech)) -- API version: 2.0.0 +- API version: 2.3.4 This autogenerated project defines an API crate `rust-server-test` which contains: * An `Api` trait defining the API in Rust. @@ -56,6 +56,7 @@ To run a client, follow one of the following simple steps: ``` cargo run --example client DummyGet +cargo run --example client DummyPut cargo run --example client HtmlPost ``` @@ -76,7 +77,7 @@ The server example is designed to form the basis for implementing your own serve * Set up a new Rust project, e.g., with `cargo init --bin`. * Insert `rust-server-test` into the `members` array under [workspace] in the root `Cargo.toml`, e.g., `members = [ "rust-server-test" ]`. -* Add `rust-server-test = {version = "2.0.0", path = "rust-server-test"}` under `[dependencies]` in the root `Cargo.toml`. +* Add `rust-server-test = {version = "2.3.4", path = "rust-server-test"}` under `[dependencies]` in the root `Cargo.toml`. * Copy the `[dependencies]` and `[dev-dependencies]` from `rust-server-test/Cargo.toml` into the root `Cargo.toml`'s `[dependencies]` section. * Copy all of the `[dev-dependencies]`, but only the `[dependencies]` that are required by the example server. These should be clearly indicated by comments. * Remove `"optional = true"` from each of these lines if present. diff --git a/samples/server/petstore/rust-server/output/rust-server-test/api/openapi.yaml b/samples/server/petstore/rust-server/output/rust-server-test/api/openapi.yaml index 468311e05a0..a52f6a1d23a 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/api/openapi.yaml +++ b/samples/server/petstore/rust-server/output/rust-server-test/api/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.0.1 info: description: This spec is for testing rust-server-specific things title: rust-server-test - version: 2.0.0 + version: 2.3.4 servers: - url: / paths: @@ -13,6 +13,25 @@ paths: content: {} description: Success summary: A dummy endpoint to make the spec valid. + put: + requestBody: + $ref: '#/components/requestBodies/inline_object' + content: + '*/*': + schema: + properties: + id: + type: string + password: + type: string + required: + - id + type: object + required: true + responses: + 200: + content: {} + description: Success /html: post: requestBody: @@ -30,6 +49,25 @@ paths: description: Success summary: Test HTML handling components: + requestBodies: + nested_response: + content: + '*/*': + schema: + properties: + id: + type: string + password: + type: string + required: + - id + type: object + required: true + inline_object: + content: + '*/*': + schema: + $ref: '#/components/schemas/inline_object' schemas: additionalPropertiesObject: additionalProperties: @@ -37,6 +75,29 @@ components: description: An additionalPropertiesObject example: foo type: object + ObjectOfObjects: + description: An object of objects + properties: + inner: + $ref: '#/components/schemas/ObjectOfObjects_inner' + type: object + inline_object: + properties: + id: + type: string + password: + type: string + required: + - id + type: object + ObjectOfObjects_inner: + properties: + optional_thing: + type: integer + required_thing: + type: string + required: + - required_thing aNullableContainer: properties: NullableThing: diff --git a/samples/server/petstore/rust-server/output/rust-server-test/examples/client.rs b/samples/server/petstore/rust-server/output/rust-server-test/examples/client.rs index 7fa86019340..f3b871666d5 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/examples/client.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/examples/client.rs @@ -20,6 +20,7 @@ use tokio_core::reactor; use rust_server_test::{ApiNoContext, ContextWrapperExt, ApiError, DummyGetResponse, + DummyPutResponse, HtmlPostResponse }; use clap::{App, Arg}; @@ -30,6 +31,7 @@ fn main() { .help("Sets the operation to run") .possible_values(&[ "DummyGet", + "DummyPut", "HtmlPost", ]) .required(true) @@ -76,6 +78,11 @@ fn main() { println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has).get().clone()); }, + Some("DummyPut") => { + let result = core.run(client.dummy_put(None)); + println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has).get().clone()); + }, + Some("HtmlPost") => { let result = core.run(client.html_post("body_example".to_string())); println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has).get().clone()); diff --git a/samples/server/petstore/rust-server/output/rust-server-test/examples/server_lib/server.rs b/samples/server/petstore/rust-server/output/rust-server-test/examples/server_lib/server.rs index e94645b0945..a5355d4862c 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/examples/server_lib/server.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/examples/server_lib/server.rs @@ -12,6 +12,7 @@ use swagger::{Has, XSpanIdString}; use rust_server_test::{Api, ApiError, DummyGetResponse, + DummyPutResponse, HtmlPostResponse }; use rust_server_test::models; @@ -36,6 +37,13 @@ impl Api for Server where C: Has{ Box::new(futures::failed("Generic failure".into())) } + + fn dummy_put(&self, inline_object: Option, context: &C) -> Box> { + let context = context.clone(); + println!("dummy_put({:?}) - X-Span-ID: {:?}", inline_object, context.get().0.clone()); + Box::new(futures::failed("Generic failure".into())) + } + /// Test HTML handling fn html_post(&self, body: String, context: &C) -> Box> { let context = context.clone(); diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs index 5b771a2040a..a3b62184eed 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs @@ -40,6 +40,7 @@ use swagger::{ApiError, XSpanId, XSpanIdString, Has, AuthData}; use {Api, DummyGetResponse, + DummyPutResponse, HtmlPostResponse }; use models; @@ -303,6 +304,71 @@ impl Api for Client where } + fn dummy_put(&self, param_inline_object: Option, context: &C) -> Box> { + + + let uri = format!( + "{}/dummy", + self.base_path + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build URI: {}", err))))), + }; + + let mut request = hyper::Request::new(hyper::Method::Put, uri); + + let body = param_inline_object.map(|ref body| { + + serde_json::to_string(body).expect("impossible to fail to serialize") + }); + +if let Some(body) = body { + request.set_body(body.into_bytes()); + } + + request.headers_mut().set(ContentType(mimetypes::requests::DUMMY_PUT.clone())); + request.headers_mut().set(XSpanId((context as &Has).get().0.clone())); + + + Box::new(self.client_service.call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| { + match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + + future::ok( + DummyPutResponse::Success + ) + ) as Box> + }, + code => { + let headers = response.headers().clone(); + Box::new(response.body() + .take(100) + .concat2() + .then(move |body| + future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => Cow::from(format!("", e)), + }, + Err(e) => Cow::from(format!("", e)), + }))) + ) + ) as Box> + } + } + })) + + } + fn html_post(&self, param_body: String, context: &C) -> Box> { diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs index 1cefa9c8278..d10d7aa2e43 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs @@ -36,7 +36,7 @@ mod mimetypes; pub use swagger::{ApiError, ContextWrapper}; pub const BASE_PATH: &'static str = ""; -pub const API_VERSION: &'static str = "2.0.0"; +pub const API_VERSION: &'static str = "2.3.4"; #[derive(Debug, PartialEq)] @@ -45,6 +45,12 @@ pub enum DummyGetResponse { Success , } +#[derive(Debug, PartialEq)] +pub enum DummyPutResponse { + /// Success + Success , +} + #[derive(Debug, PartialEq)] pub enum HtmlPostResponse { /// Success @@ -58,6 +64,9 @@ pub trait Api { /// A dummy endpoint to make the spec valid. fn dummy_get(&self, context: &C) -> Box>; + + fn dummy_put(&self, inline_object: Option, context: &C) -> Box>; + /// Test HTML handling fn html_post(&self, body: String, context: &C) -> Box>; @@ -69,6 +78,9 @@ pub trait ApiNoContext { /// A dummy endpoint to make the spec valid. fn dummy_get(&self) -> Box>; + + fn dummy_put(&self, inline_object: Option) -> Box>; + /// Test HTML handling fn html_post(&self, body: String) -> Box>; @@ -93,6 +105,11 @@ impl<'a, T: Api, C> ApiNoContext for ContextWrapper<'a, T, C> { self.api().dummy_get(&self.context()) } + + fn dummy_put(&self, inline_object: Option) -> Box> { + self.api().dummy_put(inline_object, &self.context()) + } + /// Test HTML handling fn html_post(&self, body: String) -> Box> { self.api().html_post(body, &self.context()) diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/mimetypes.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/mimetypes.rs index f2c9ff91715..e7dd9bc1076 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/mimetypes.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/mimetypes.rs @@ -13,6 +13,10 @@ pub mod responses { pub mod requests { use hyper::mime::*; + /// Create Mime objects for the request content types for DummyPut + lazy_static! { + pub static ref DUMMY_PUT: Mime = "application/json".parse().unwrap(); + } /// Create Mime objects for the request content types for HtmlPost lazy_static! { pub static ref HTML_POST: Mime = "text/html".parse().unwrap(); diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs index f4c3e1b36a3..03a3b955945 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs @@ -43,3 +43,60 @@ impl AdditionalPropertiesObject { } } } + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct InlineObject { + #[serde(rename = "id")] + pub id: String, + + #[serde(rename = "password")] + #[serde(skip_serializing_if="Option::is_none")] + pub password: Option, + +} + +impl InlineObject { + pub fn new(id: String, ) -> InlineObject { + InlineObject { + id: id, + password: None, + } + } +} + +/// An object of objects +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ObjectOfObjects { + #[serde(rename = "inner")] + #[serde(skip_serializing_if="Option::is_none")] + pub inner: Option, + +} + +impl ObjectOfObjects { + pub fn new() -> ObjectOfObjects { + ObjectOfObjects { + inner: None, + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ObjectOfObjectsInner { + #[serde(rename = "optional_thing")] + #[serde(skip_serializing_if="Option::is_none")] + pub optional_thing: Option, + + #[serde(rename = "required_thing")] + pub required_thing: String, + +} + +impl ObjectOfObjectsInner { + pub fn new(required_thing: String, ) -> ObjectOfObjectsInner { + ObjectOfObjectsInner { + optional_thing: None, + required_thing: required_thing, + } + } +} diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs index 2f796e35655..cec0ed8e38f 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs @@ -38,6 +38,7 @@ use swagger::auth::Scopes; use {Api, DummyGetResponse, + DummyPutResponse, HtmlPostResponse }; #[allow(unused_imports)] @@ -169,6 +170,82 @@ where }, + // DummyPut - PUT /dummy + &hyper::Method::Put if path.matched(paths::ID_DUMMY) => { + + + + + + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + Box::new(body.concat2() + .then(move |result| -> Box> { + match result { + Ok(body) => { + + let mut unused_elements = Vec::new(); + let param_inline_object: Option = if !body.is_empty() { + + let deserializer = &mut serde_json::Deserializer::from_slice(&*body); + + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_inline_object) => param_inline_object, + + Err(_) => None, + } + + } else { + None + }; + + + Box::new(api_impl.dummy_put(param_inline_object, &context) + .then(move |result| { + let mut response = Response::new(); + response.headers_mut().set(XSpanId((&context as &Has).get().0.to_string())); + + if !unused_elements.is_empty() { + response.headers_mut().set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + + match result { + Ok(rsp) => match rsp { + DummyPutResponse::Success + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + } + )) + + + }, + Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter InlineObject: {}", e)))), + } + }) + ) as Box> + + }, + + // HtmlPost - POST /html &hyper::Method::Post if path.matched(paths::ID_HTML) => {