Handle headers correctly (#549)

We were previously relying on some incorrect behaviour of the old
swagger-codegen mustache engine.
This commit is contained in:
Benjamin Gill 2018-07-12 18:55:56 +01:00 committed by William Cheng
parent 19fd48e33b
commit 6c14b4271f
9 changed files with 109 additions and 23 deletions

View File

@ -42,7 +42,7 @@ 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}},
{{#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}}

View File

@ -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:

View File

@ -1 +1 @@
3.0.1-SNAPSHOT
3.1.1-SNAPSHOT

View File

@ -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:

View File

@ -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::<ResponseXRateLimit>() {
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<Future<Item=_, Error=_>>,
};
header! { (ResponseXExpiresAfter, "X-Expires-After") => [chrono::DateTime<chrono::Utc>] }
let response_x_expires_after = match response.headers().get::<ResponseXExpiresAfter>() {
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<Future<Item=_, Error=_>>,
};
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::<String>(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<Future<Item=_, Error=_>>
},
400 => {
let body = response.body();
Box::new(

View File

@ -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<chrono::Utc> } ,
/// Invalid username/password supplied
InvalidUsername ,
}

View File

@ -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();
}
}

View File

@ -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<models::OuterNumber>,
pub my_number: Option<f64>,
#[serde(rename = "my_string")]
#[serde(skip_serializing_if="Option::is_none")]
pub my_string: Option<models::OuterString>,
pub my_string: Option<String>,
#[serde(rename = "my_boolean")]
#[serde(skip_serializing_if="Option::is_none")]
pub my_boolean: Option<models::OuterBoolean>,
pub my_boolean: Option<bool>,
}

View File

@ -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<chrono::Utc>] }
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