From 6c14b4271fe4489dd5921f2a360f5b3db11fc2ce Mon Sep 17 00:00:00 2001 From: Benjamin Gill Date: Thu, 12 Jul 2018 18:55:56 +0100 Subject: [PATCH] Handle headers correctly (#549) We were previously relying on some incorrect behaviour of the old swagger-codegen mustache engine. --- .../main/resources/rust-server/lib.mustache | 4 +-- ...ith-fake-endpoints-models-for-testing.yaml | 26 +++++++-------- .../rust-server/.openapi-generator/VERSION | 2 +- .../petstore/rust-server/api/openapi.yaml | 32 ++++++++++++++++--- .../petstore/rust-server/src/client/mod.rs | 32 +++++++++++++++++++ .../server/petstore/rust-server/src/lib.rs | 2 ++ .../petstore/rust-server/src/mimetypes.rs | 4 +++ .../server/petstore/rust-server/src/models.rs | 6 ++-- .../petstore/rust-server/src/server/mod.rs | 24 ++++++++++++++ 9 files changed, 109 insertions(+), 23 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/rust-server/lib.mustache b/modules/openapi-generator/src/main/resources/rust-server/lib.mustache index 2929122ac20..7066a7b41ea 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/lib.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/lib.mustache @@ -42,8 +42,8 @@ pub const API_VERSION: &'static str = "{{appVersion}}"; pub enum {{operationId}}Response { {{#responses}} {{#message}} /// {{message}}{{/message}} - {{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}} {{#dataType}}{{^headers}}( {{{dataType}}} ) {{/headers}}{{#headers}}{{#-first}}{ body: {{{dataType}}}{{/-first}}{{/headers}}{{/dataType}}{{#headers}}{{#-first}}{{^dataType}} { {{/dataType}}{{#dataType}}, {{/dataType}}{{/-first}}{{^-first}}, {{/-first}}{{name}}: {{{dataType}}}{{#-last}} } {{/-last}}{{/headers}}, -{{/responses}} + {{#vendorExtensions}}{{{x-responseId}}}{{/vendorExtensions}} {{#dataType}}{{^hasHeaders}}( {{{dataType}}} ) {{/hasHeaders}}{{#hasHeaders}}{{#-first}}{ body: {{{dataType}}}{{/-first}}{{/hasHeaders}}{{/dataType}}{{#dataType}}{{#hasHeaders}}, {{/hasHeaders}}{{/dataType}}{{^dataType}}{{#hasHeaders}} { {{/hasHeaders}}{{/dataType}}{{#headers}}{{^-first}}, {{/-first}}{{{name}}}: {{{datatype}}}{{#-last}} } {{/-last}}{{/headers}}, + {{/responses}} } {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} diff --git a/modules/openapi-generator/src/test/resources/2_0/rust-server/petstore-with-fake-endpoints-models-for-testing.yaml b/modules/openapi-generator/src/test/resources/2_0/rust-server/petstore-with-fake-endpoints-models-for-testing.yaml index cf930089b97..0df5dc18cfa 100644 --- a/modules/openapi-generator/src/test/resources/2_0/rust-server/petstore-with-fake-endpoints-models-for-testing.yaml +++ b/modules/openapi-generator/src/test/resources/2_0/rust-server/petstore-with-fake-endpoints-models-for-testing.yaml @@ -450,19 +450,19 @@ paths: required: true type: string responses: - # '200': - # description: successful operation - # schema: - # type: string - # headers: - # X-Rate-Limit: - # type: integer - # format: int32 - # description: calls per hour allowed by the user - # X-Expires-After: - # type: string - # format: date-time - # description: date in UTC when token expires + '200': + description: successful operation + schema: + type: string + headers: + X-Rate-Limit: + type: integer + format: int32 + description: calls per hour allowed by the user + X-Expires-After: + type: string + format: date-time + description: date in UTC when token expires '400': description: Invalid username/password supplied /user/logout: diff --git a/samples/server/petstore/rust-server/.openapi-generator/VERSION b/samples/server/petstore/rust-server/.openapi-generator/VERSION index ad121e8340e..dde25ef08e8 100644 --- a/samples/server/petstore/rust-server/.openapi-generator/VERSION +++ b/samples/server/petstore/rust-server/.openapi-generator/VERSION @@ -1 +1 @@ -3.0.1-SNAPSHOT \ No newline at end of file +3.1.1-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/rust-server/api/openapi.yaml b/samples/server/petstore/rust-server/api/openapi.yaml index 37cff2cebd9..2747b636766 100644 --- a/samples/server/petstore/rust-server/api/openapi.yaml +++ b/samples/server/petstore/rust-server/api/openapi.yaml @@ -453,6 +453,26 @@ paths: schema: type: string responses: + 200: + content: + application/xml: + schema: + type: string + application/json: + schema: + type: string + description: successful operation + headers: + X-Rate-Limit: + description: calls per hour allowed by the user + schema: + format: int32 + type: integer + X-Expires-After: + description: date in UTC when token expires + schema: + format: date-time + type: string 400: content: {} description: Invalid username/password supplied @@ -1229,14 +1249,18 @@ components: type: array type: object OuterComposite: - example: {} + example: + my_string: my_string + my_number: 0.80082819046101150206595775671303272247314453125 + my_boolean: true properties: my_number: - $ref: '#/components/schemas/OuterNumber' + type: number my_string: - $ref: '#/components/schemas/OuterString' + type: string my_boolean: - $ref: '#/components/schemas/OuterBoolean' + type: boolean + x-codegen-body-parameter-name: boolean_post_body type: object format_test: properties: diff --git a/samples/server/petstore/rust-server/src/client/mod.rs b/samples/server/petstore/rust-server/src/client/mod.rs index 8ce1b41ce1c..798313d573d 100644 --- a/samples/server/petstore/rust-server/src/client/mod.rs +++ b/samples/server/petstore/rust-server/src/client/mod.rs @@ -2526,6 +2526,38 @@ if let Some(body) = body { .map_err(|e| ApiError(format!("No response received: {}", e))) .and_then(|mut response| { match response.status().as_u16() { + 200 => { + header! { (ResponseXRateLimit, "X-Rate-Limit") => [i32] } + let response_x_rate_limit = match response.headers().get::() { + Some(response_x_rate_limit) => response_x_rate_limit.0.clone(), + None => return Box::new(future::err(ApiError(String::from("Required response header X-Rate-Limit for response 200 was not found.")))) as Box>, + }; + header! { (ResponseXExpiresAfter, "X-Expires-After") => [chrono::DateTime] } + let response_x_expires_after = match response.headers().get::() { + Some(response_x_expires_after) => response_x_expires_after.0.clone(), + None => return Box::new(future::err(ApiError(String::from("Required response header X-Expires-After for response 200 was not found.")))) as Box>, + }; + let body = response.body(); + Box::new( + + body + .concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e))) + .and_then(|body| + + // ToDo: this will move to swagger-rs and become a standard From conversion trait + // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream + serde_xml_rs::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e))) + + )) + .map(move |body| + LoginUserResponse::SuccessfulOperation{ body: body, x_rate_limit: response_x_rate_limit, x_expires_after: response_x_expires_after } + ) + ) as Box> + }, 400 => { let body = response.body(); Box::new( diff --git a/samples/server/petstore/rust-server/src/lib.rs b/samples/server/petstore/rust-server/src/lib.rs index e0311e33321..d6534990ac3 100644 --- a/samples/server/petstore/rust-server/src/lib.rs +++ b/samples/server/petstore/rust-server/src/lib.rs @@ -242,6 +242,8 @@ pub enum GetUserByNameResponse { #[derive(Debug, PartialEq)] pub enum LoginUserResponse { + /// successful operation + SuccessfulOperation { body: String, x_rate_limit: i32, x_expires_after: chrono::DateTime } , /// Invalid username/password supplied InvalidUsername , } diff --git a/samples/server/petstore/rust-server/src/mimetypes.rs b/samples/server/petstore/rust-server/src/mimetypes.rs index 1aeb6ad47c8..9073c213ccb 100644 --- a/samples/server/petstore/rust-server/src/mimetypes.rs +++ b/samples/server/petstore/rust-server/src/mimetypes.rs @@ -64,6 +64,10 @@ pub mod responses { lazy_static! { pub static ref GET_USER_BY_NAME_SUCCESSFUL_OPERATION: Mime = "application/json".parse().unwrap(); } + /// Create Mime objects for the response content types for LoginUser + lazy_static! { + pub static ref LOGIN_USER_SUCCESSFUL_OPERATION: Mime = "application/json".parse().unwrap(); + } } diff --git a/samples/server/petstore/rust-server/src/models.rs b/samples/server/petstore/rust-server/src/models.rs index 05dfeb9f3b5..de88074b622 100644 --- a/samples/server/petstore/rust-server/src/models.rs +++ b/samples/server/petstore/rust-server/src/models.rs @@ -762,15 +762,15 @@ impl ::std::ops::DerefMut for OuterBoolean { pub struct OuterComposite { #[serde(rename = "my_number")] #[serde(skip_serializing_if="Option::is_none")] - pub my_number: Option, + pub my_number: Option, #[serde(rename = "my_string")] #[serde(skip_serializing_if="Option::is_none")] - pub my_string: Option, + pub my_string: Option, #[serde(rename = "my_boolean")] #[serde(skip_serializing_if="Option::is_none")] - pub my_boolean: Option, + pub my_boolean: Option, } diff --git a/samples/server/petstore/rust-server/src/server/mod.rs b/samples/server/petstore/rust-server/src/server/mod.rs index 0c246daad47..a71a4ded43d 100644 --- a/samples/server/petstore/rust-server/src/server/mod.rs +++ b/samples/server/petstore/rust-server/src/server/mod.rs @@ -2934,6 +2934,30 @@ where match result { Ok(rsp) => match rsp { + LoginUserResponse::SuccessfulOperation + + { + body, + x_rate_limit, + + x_expires_after + } + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + header! { (ResponseXRateLimit, "X-Rate-Limit") => [i32] } + response.headers_mut().set(ResponseXRateLimit(x_rate_limit)); + header! { (ResponseXExpiresAfter, "X-Expires-After") => [chrono::DateTime] } + response.headers_mut().set(ResponseXExpiresAfter(x_expires_after)); + + response.headers_mut().set(ContentType(mimetypes::responses::LOGIN_USER_SUCCESSFUL_OPERATION.clone())); + + + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, LoginUserResponse::InvalidUsername