[rust-server] Drop file support (#547)

* [rust-server] drop 'file' support

In swagger v2, we had 'binary', 'byte', and 'file'. OpenAPI v3 only has
the former two. This commit drops the old 'file' handling. This has the
side-effect of removing a half-complete implementation of form parameter handling.

This removes the ability to send files as streams, so will make life
harder for those wishing to send large files without running out of
memory.

* Remove all remaining uses of `hasFile`
This commit is contained in:
Benjamin Gill 2018-07-23 11:46:35 +01:00 committed by William Cheng
parent af3ca293e4
commit a9961a062a
17 changed files with 238 additions and 788 deletions

View File

@ -164,8 +164,8 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
typeMapping.put("date", "chrono::DateTime<chrono::Utc>");
typeMapping.put("DateTime", "chrono::DateTime<chrono::Utc>");
typeMapping.put("password", "String");
typeMapping.put("File", "Box<Stream<Item=Vec<u8>, Error=Error> + Send>");
typeMapping.put("file", "Box<Stream<Item=Vec<u8>, Error=Error> + Send>");
typeMapping.put("File", "swagger::ByteArray");
typeMapping.put("file", "swagger::ByteArray");
typeMapping.put("array", "Vec");
typeMapping.put("map", "HashMap");
@ -710,8 +710,6 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
}
header.nameInCamelCase = toModelName(header.baseName);
}
additionalProperties.put("apiHasFile", true);
}
return objs;
@ -1069,22 +1067,11 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
private void processParam(CodegenParameter param, CodegenOperation op) {
String example = null;
if (param.isFile) {
param.vendorExtensions.put("formatString", "{:?}");
op.vendorExtensions.put("hasFile", true);
additionalProperties.put("apiHasFile", true);
example = "Box::new(stream::once(Ok(b\"hello\".to_vec()))) as Box<Stream<Item=_, Error=_> + Send>";
} else if (param.isString) {
if (param.dataFormat != null && param.dataFormat.equals("byte")) {
param.vendorExtensions.put("formatString", "\\\"{:?}\\\"");
example = "swagger::ByteArray(\"" + ((param.example != null) ? param.example : "") + "\".to_string().into_bytes())";
} else {
param.vendorExtensions.put("formatString", "\\\"{}\\\"");
example = "\"" + ((param.example != null) ? param.example : "") + "\".to_string()";
}
if (param.isString) {
param.vendorExtensions.put("formatString", "\\\"{}\\\"");
example = "\"" + ((param.example != null) ? param.example : "") + "\".to_string()";
} else if (param.isPrimitiveType) {
if ((param.isByteArray) ||
(param.isBinary)) {
if ((param.isByteArray) || (param.isBinary)) {
// Binary primitive types don't implement `Display`.
param.vendorExtensions.put("formatString", "{:?}");
example = "swagger::ByteArray(Vec::from(\"" + ((param.example != null) ? param.example : "") + "\"))";
@ -1119,12 +1106,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
} else {
// Not required, so override the format string and example
param.vendorExtensions.put("formatString", "{:?}");
if (param.isFile) {
// Optional file types are wrapped in a future
param.vendorExtensions.put("example", (example != null) ? "Box::new(future::ok(Some(" + example + "))) as Box<Future<Item=_, Error=_> + Send>" : "None");
} else {
param.vendorExtensions.put("example", (example != null) ? "Some(" + example + ")" : "None");
}
param.vendorExtensions.put("example", (example != null) ? "Some(" + example + ")" : "None");
}
}
}

View File

@ -9,8 +9,8 @@ license = "Unlicense"
[features]
default = ["client", "server"]
client = ["serde_json", {{#usesUrlEncodedForm}}"serde_urlencoded", {{/usesUrlEncodedForm}} {{#usesXml}}"serde-xml-rs", {{/usesXml}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"{{#apiHasFile}}, "multipart"{{/apiHasFile}}]
server = ["serde_json", {{#usesXml}}"serde-xml-rs", {{/usesXml}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"{{#apiHasFile}}, "multipart"{{/apiHasFile}}]
client = ["serde_json", {{#usesUrlEncodedForm}}"serde_urlencoded", {{/usesUrlEncodedForm}} {{#usesXml}}"serde-xml-rs", {{/usesXml}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"]
server = ["serde_json", {{#usesXml}}"serde-xml-rs", {{/usesXml}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"]
[dependencies]
# Required by example server.

View File

@ -6,11 +6,9 @@ extern crate openssl;
extern crate mime;
extern crate chrono;
extern crate url;
{{#apiHasFile}}extern crate multipart;{{/apiHasFile}}
{{#usesUrlEncodedForm}}extern crate serde_urlencoded;{{/usesUrlEncodedForm}}
{{#apiUsesUuid}}use uuid;{{/apiUsesUuid}}
{{#apiHasFile}}use self::multipart::client::lazy::Multipart;{{/apiHasFile}}
use hyper;
use hyper::header::{Headers, ContentType};
use hyper::Uri;
@ -239,7 +237,7 @@ impl<F, C> Api<C> for Client<F> where
F: Future<Item=hyper::Response, Error=hyper::Error> + 'static,
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<AuthData>>{{/hasAuthMethods}}{
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, param_{{paramName}}: {{^required}}{{#isFile}}Box<Future<Item={{/isFile}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, param_{{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
{{#queryParams}}{{#-first}}
// Query parameters
{{/-first}}{{#required}} let query_{{paramName}} = format!("{{baseName}}={{=<% %>=}}{<% paramName %>}<%={{ }}=%>&", {{paramName}}=param_{{paramName}}{{#isListContainer}}.join(","){{/isListContainer}}{{^isListContainer}}.to_string(){{/isListContainer}});
@ -259,47 +257,13 @@ impl<F, C> Api<C> for Client<F> where
let mut request = hyper::Request::new(hyper::Method::{{#vendorExtensions}}{{HttpMethod}}{{/vendorExtensions}}, uri);
{{#vendorExtensions}}{{#hasFile}} // Form data body
let mut multipart = Multipart::new();
// Helper function to convert a Stream into a String. The String can then be used to build the HTTP body.
fn convert_stream_to_string(stream: Box<Stream<Item=Vec<u8>, Error=Error> + Send>) -> Result<String, ApiError> {
stream.concat2()
.wait()
.map_err(|e| ApiError(format!("Unable to collect stream: {}", e)))
.and_then(|body| String::from_utf8(body)
.map_err(|e| ApiError(format!("Failed to convert utf8 stream to String: {}", e))))
}{{/hasFile}}{{/vendorExtensions}}{{#formParams}}{{#isFile}}
{{^required}} if let Ok(Some(param_{{paramName}})) = param_{{paramName}}.wait() { {{/required}}
{{^required}} {{/required}} match convert_stream_to_string(param_{{paramName}}) {
{{^required}} {{/required}} Ok(param_{{paramName}}) => {
// Add file to multipart form.
multipart.add_text("{{paramName}}", param_{{paramName}});
},
{{^required}} {{/required}} Err(err) => return Box::new(futures::done(Err(err))),
{{^required}} {{/required}} }
{{^required}}}{{/required}}{{/isFile}}{{/formParams}}{{#vendorExtensions}}{{#hasFile}}
let mut fields = match multipart.prepare() {
Ok(fields) => fields,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build request: {}", err))))),
};
let mut body_string = String::new();
let body = fields.to_body().read_to_string(&mut body_string);
let boundary = fields.boundary();
let multipart_header = match mime::Mime::from_str(&format!("multipart/form-data;boundary={}", boundary)) {
Ok(multipart_header) => multipart_header,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build multipart header: {:?}", err))))),
};{{/hasFile}}{{^hasFile}}{{#formParams}}{{#-first}} let params = &[{{/-first}}
{{#vendorExtensions}}{{#formParams}}{{#-first}} let params = &[{{/-first}}
("{{baseName}}", {{#vendorExtensions}}{{#required}}Some({{#isString}}param_{{paramName}}{{/isString}}{{^isString}}format!("{:?}", param_{{paramName}}){{/isString}}){{/required}}{{^required}}{{#isString}}param_{{paramName}}{{/isString}}{{^isString}}param_{{paramName}}.map(|param| format!("{:?}", param)){{/isString}}{{/required}}),{{/vendorExtensions}}{{#-last}}
];
let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize");
request.headers_mut().set(ContentType(mimetypes::requests::{{#vendorExtensions}}{{uppercase_operation_id}}{{/vendorExtensions}}.clone()));
request.set_body(body.into_bytes());{{/-last}}{{/formParams}}{{/hasFile}}{{/vendorExtensions}}{{#bodyParam}}{{#-first}}
request.set_body(body.into_bytes());{{/-last}}{{/formParams}}{{/vendorExtensions}}{{#bodyParam}}{{#-first}}
// Body parameter
{{/-first}}{{#vendorExtensions}}{{#required}}{{#consumesPlainText}} let body = param_{{paramName}};{{/consumesPlainText}}{{#consumesXml}}
{{^has_namespace}} let body = serde_xml_rs::to_string(&param_{{paramName}}).expect("impossible to fail to serialize");{{/has_namespace}}{{#has_namespace}}
@ -340,11 +304,6 @@ impl<F, C> Api<C> for Client<F> where
{{/required}}{{/isMapContainer}}{{#isMapContainer}} let param_{{paramName}}: Option<{{{dataType}}}> = None;
{{/isMapContainer}}{{/headerParams}}
{{#vendorExtensions}}{{#hasFile}}
request.headers_mut().set(ContentType(multipart_header));
request.set_body(body_string.into_bytes());
{{/hasFile}}{{/vendorExtensions}}
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -357,13 +316,9 @@ impl<F, C> Api<C> for Client<F> where
None => return Box::new(future::err(ApiError(String::from("Required response header {{baseName}} for response {{code}} was not found.")))) as Box<Future<Item=_, Error=_>>,
};
{{/headers}}
{{^isFile}}let body = response.body();{{/isFile}}{{#isFile}}let body = Box::new(response.body()
.map(|chunk| chunk.to_vec())
.map_err(|_|
Error::new(ErrorKind::Other, "Received error reading response.")
));{{/isFile}}
let body = response.body();
Box::new(
{{#dataType}}{{^isFile}}
{{#dataType}}
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -383,9 +338,6 @@ impl<F, C> Api<C> for Client<F> where
{{/producesPlainText}}{{/vendorExtensions}}
))
.map(move |body|
{{/isFile}}{{#isFile}}
future::ok(
{{/isFile}}
{{operationId}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}{{^headers}}(body){{/headers}}{{#headers}}{{#-first}}{ body: body, {{/-first}}{{name}}: response_{{name}}{{^-last}}, {{/-last}}{{#-last}} }{{/-last}}{{/headers}}
)
{{/dataType}}{{^dataType}}

View File

@ -4,9 +4,7 @@
use futures::{self, Future};
use chrono;
{{#apiHasFile}}use futures::Stream;{{/apiHasFile}}
use std::collections::HashMap;
{{#apiHasFile}}use std::io::Error;{{/apiHasFile}}
use std::marker::PhantomData;
{{#apiUsesUuid}}use uuid;{{/apiUsesUuid}}
use swagger;
@ -31,10 +29,9 @@ impl<C> Server<C> {
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box<Future<Item={{/isFile}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
let context = context.clone();
println!("{{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}({{#allParams}}{{^isFile}}{{#vendorExtensions}}{{{formatString}}}{{/vendorExtensions}}{{#hasMore}}, {{/hasMore}}{{/isFile}}{{/allParams}}) - X-Span-ID: {:?}"{{#allParams}}{{^isFile}}, {{paramName}}{{/isFile}}{{/allParams}}, context.get().0.clone());{{#allParams}}{{#isFile}}
let _ = {{paramName}}; //Suppresses unused param warning{{/isFile}}{{/allParams}}
println!("{{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}({{#allParams}}{{#vendorExtensions}}{{{formatString}}}{{/vendorExtensions}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) - X-Span-ID: {:?}"{{#allParams}}, {{paramName}}{{/allParams}}, context.get().0.clone());{{#allParams}}{{/allParams}}
Box::new(futures::failed("Generic failure".into()))
}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}

View File

@ -51,7 +51,7 @@ pub enum {{operationId}}Response {
pub trait Api<C> {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box<Future<Item={{/isFile}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>>;
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>>;
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
}
@ -59,7 +59,7 @@ pub trait Api<C> {
pub trait ApiNoContext {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box<Future<Item={{/isFile}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}) -> Box<Future<Item={{operationId}}Response, Error=ApiError>>;
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}) -> Box<Future<Item={{operationId}}Response, Error=ApiError>>;
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
}
@ -78,7 +78,7 @@ impl<'a, T: Api<C> + Sized, C> ContextWrapperExt<'a, C> for T {
impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box<Future<Item={{/isFile}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
self.api().{{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}({{#allParams}}{{paramName}}, {{/allParams}}&self.context())
}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}

View File

@ -17,9 +17,9 @@ pub mod requests {
lazy_static! {
pub static ref {{#vendorExtensions}}{{uppercase_operation_id}}{{/vendorExtensions}}: Mime = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/json{{/consumes}}".parse().unwrap();
}
{{/bodyParam}}{{^bodyParam}}{{#vendorExtensions}}{{#formParams}}{{#-first}}{{^hasFile}} /// Create Mime objects for the request content types for {{operationId}}
{{/bodyParam}}{{^bodyParam}}{{#vendorExtensions}}{{#formParams}}{{#-first}} /// Create Mime objects for the request content types for {{operationId}}
lazy_static! {
pub static ref {{#vendorExtensions}}{{uppercase_operation_id}}{{/vendorExtensions}}: Mime = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/x-www-form-urlencoded{{/consumes}}".parse().unwrap();
}
{{/hasFile}}{{/-first}}{{/formParams}}{{/vendorExtensions}}{{/bodyParam}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
{{/-first}}{{/formParams}}{{/vendorExtensions}}{{/bodyParam}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
}

View File

@ -7,7 +7,6 @@ extern crate openssl;
extern crate mime;
{{^apiUsesUuid}}extern crate uuid;{{/apiUsesUuid}}
extern crate chrono;
{{#apiHasFile}}extern crate multipart;{{/apiHasFile}}
extern crate percent_encoding;
extern crate url;
@ -20,8 +19,6 @@ use hyper::{Request, Response, Error, StatusCode};
use hyper::header::{Headers, ContentType};
use self::url::form_urlencoded;
use mimetypes;
{{#apiHasFile}}use self::multipart::server::Multipart;
use self::multipart::server::save::SaveResult;{{/apiHasFile}}
use serde_json;
{{#usesXml}}use serde_xml_rs;{{/usesXml}}
@ -277,51 +274,7 @@ where
};
{{/required}}
{{/-first}}{{/bodyParams}}
{{^bodyParams}}{{#vendorExtensions}}{{#hasFile}}
let boundary = match multipart_boundary(&headers) {
Some(boundary) => boundary.to_string(),
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Couldn't find valid multipart body"))),
};
Box::new(body.concat2()
.then(move |result| -> Box<Future<Item=Response, Error=Error>> {
match result {
Ok(body) => {
let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary).save().temp() {
SaveResult::Full(entries) => {
entries
},
_ => {
return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Unable to process all message parts"))))
},
};
{{#formParams}}{{#-first}}
// Form parameters
{{/-first}}
let param_{{paramName}} = entries.fields.remove("{{paramName}}");
let param_{{paramName}} = match param_{{paramName}} {
Some(entry) =>
{{#isFile}}
{{^required}}Some({{/required}}Box::new(stream::once(Ok(entry.as_bytes().to_vec()))) as Box<Stream<Item=Vec<u8>, Error=io::Error> + Send>{{^required}}){{/required}},
{{/isFile}}{{^isFile}}
match entry.parse::<{{{dataType}}}>() {
Ok(entry) => {{^required}}Some({{/required}}entry{{^required}}){{/required}},
{{#required}}
Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse form parameter {{baseName}} - doesn't match schema: {}", e)))),
{{/required}}{{^required}}
Err(_) => None,
{{/required}}
},
{{/isFile}}
{{#required}}
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Missing required form parameter {{paramName}}")))),
{{/required}}{{^required}}
None => None,
{{/required}}
};
{{^required}}{{#isFile}} let param_{{paramName}} = Box::new(future::ok(param_{{paramName}}));{{/isFile}}{{/required}}
{{/formParams}}
{{/hasFile}}{{^hasFile}}
{{^bodyParams}}{{#vendorExtensions}}
Box::new({
{{
{{#formParams}}{{#-first}}
@ -329,7 +282,7 @@ where
{{/-first}}
let param_{{paramName}} = {{^isContainer}}{{#vendorExtensions}}{{{example}}};{{/vendorExtensions}}{{/isContainer}}{{#isListContainer}}{{#required}}Vec::new();{{/required}}{{^required}}None;{{/required}}{{/isListContainer}}{{#isMapContainer}}None;{{/isMapContainer}}
{{/formParams}}
{{/hasFile}}{{/vendorExtensions}}{{/bodyParams}}
{{/vendorExtensions}}{{/bodyParams}}
Box::new(api_impl.{{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}({{#allParams}}param_{{paramName}}{{#isListContainer}}.as_ref(){{/isListContainer}}, {{/allParams}}&context)
.then(move |result| {
let mut response = Response::new();
@ -364,7 +317,7 @@ where
{{/-last}}
{{/headers}}{{/dataType}}
=> {
{{^isFile}} response.set_status(StatusCode::try_from({{code}}).unwrap());
response.set_status(StatusCode::try_from({{code}}).unwrap());
{{#headers}}
header! { (Response{{nameInCamelCase}}, "{{baseName}}") => [{{{dataType}}}] }
response.headers_mut().set(Response{{nameInCamelCase}}({{name}}));
@ -384,34 +337,7 @@ where
let body = serde_json::to_string(&body).expect("impossible to fail to serialize");
{{/producesJson}}{{/vendorExtensions}}
response.set_body(body);
{{/dataType}}{{/isFile}}{{#isFile}}
let body = body.fold(Vec::new(), | mut body, chunk| {
body.extend(chunk.iter());
future::ok::<Vec<u8>, io::Error>(body)
})
// Block whilst waiting for the stream to complete
.wait();
match body {
// If no error occurred then create successful hyper response
Ok(vec) => {
response.set_status(StatusCode::try_from({{code}}).unwrap());
{{#headers}}
header! { (Response{{nameInCamelCase}}, "{{baseName}}") => [{{{dataType}}}] }
response.headers_mut().set(Response{{nameInCamelCase}}({{name}}));
{{/headers}}{{#produces}}{{#-first}}{{#dataType}}
response.headers_mut().set(ContentType(mimetypes::responses::{{#vendorExtensions}}{{uppercase_operation_id}}_{{x-uppercaseResponseId}}{{/vendorExtensions}}.clone()));
{{/dataType}}{{/-first}}{{/produces}}
response.set_body(vec);
},
// It's possible that errors were received in the stream, if this is the case then we can't return a success response to the client and instead must return an internal error.
Err(e) => {
response.set_status(StatusCode::InternalServerError);
response.set_body("An internal error occurred");
}
}
{{/isFile}}
{{/dataType}}
},
{{/responses}}
},
@ -426,17 +352,10 @@ where
future::ok(response)
}
))
{{^bodyParams}}{{#vendorExtensions}}{{^hasFile}}
{{^bodyParams}}{{#vendorExtensions}}
}}
}) as Box<Future<Item=Response, Error=Error>>
{{/hasFile}}{{#hasFile}}
as Box<Future<Item=Response, Error=Error>>
},
Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))),
}
})
)
{{/hasFile}}{{/vendorExtensions}}{{/bodyParams}}
{{/vendorExtensions}}{{/bodyParams}}
{{#bodyParams}}{{#-first}}
},
Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter {{baseName}}: {}", e)))),
@ -451,32 +370,3 @@ where
}
}
}
{{#apiHasFile}}
/// Utility function to get the multipart boundary marker (if any) from the Headers.
fn multipart_boundary<'a>(headers: &'a Headers) -> Option<&'a str> {
headers.get::<ContentType>().and_then(|content_type| {
let ContentType(ref mime) = *content_type;
if mime.type_() == mime::MULTIPART && mime.subtype() == mime::FORM_DATA {
mime.get_param(mime::BOUNDARY).map(|x| x.as_str())
} else {
None
}
})
}
{{/apiHasFile}}
/// Request parser for `Api`.
pub struct ApiRequestParser;
impl RequestParser for ApiRequestParser {
fn parse_operation_id(request: &Request) -> Result<&'static str, ()> {
let path = paths::GLOBAL_REGEX_SET.matches(request.uri().path());
match request.method() {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
// {{operationId}} - {{httpMethod}} {{path}}
&hyper::Method::{{vendorExtensions.HttpMethod}} if path.matched(paths::ID_{{vendorExtensions.PATH_ID}}) => Ok("{{operationId}}"),
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} _ => Err(()),
}
}
}

View File

@ -608,6 +608,7 @@ paths:
consumes:
- "application/x-www-form-urlencoded"
parameters:
# See https://github.com/OpenAPITools/openapi-generator/issues/545
# - name: enum_form_string_array
# type: array
# items:
@ -618,15 +619,15 @@ paths:
# - '$'
# in: formData
# description: Form parameter enum test (string array)
# - name: enum_form_string
# type: string
# default: '-efg'
# enum:
# - _abc
# - '-efg'
# - (xyz)
# in: formData
# description: Form parameter enum test (string)
- name: enum_form_string
type: string
default: '-efg'
enum:
- _abc
- '-efg'
- (xyz)
in: formData
description: Form parameter enum test (string)
- name: enum_header_string_array
type: array
items:
@ -753,12 +754,12 @@ paths:
in: formData
description: None
required: true
# - name: byte
# type: string
# format: byte
# in: formData
# description: None
# required: true
- name: byte
type: string
format: byte
in: formData
description: None
required: true
- name: binary
type: string
format: binary
@ -1204,9 +1205,9 @@ definitions:
byte:
type: string
format: byte
# binary:
# type: string
# format: binary
binary:
type: string
format: binary
date:
type: string
format: date
@ -1338,16 +1339,15 @@ definitions:
type: object
additionalProperties:
type: string
# comment out the following (map of map of enum) as many language not yet support this
#map_map_of_enum:
# type: object
# additionalProperties:
# type: object
# additionalProperties:
# type: string
# enum:
# - UPPER
# - lower
map_map_of_enum:
type: object
additionalProperties:
type: object
additionalProperties:
type: string
enum:
- UPPER
- lower
map_of_enum_string:
type: object
additionalProperties:
@ -1375,15 +1375,13 @@ definitions:
type: array
items:
$ref: '#/definitions/ReadOnlyFirst'
# commented out the below test case for array of enum for the time being
# as not all language can handle it
#array_of_enum:
# type: array
# items:
# type: string
# enum:
# - UPPER
# - lower
array_of_enum:
type: array
items:
type: string
enum:
- UPPER
- lower
NumberOnly:
type: object
properties:
@ -1420,16 +1418,15 @@ definitions:
enum:
- fish
- crab
# comment out the following as 2d array of enum is not supported at the moment
#array_array_enum:
# type: array
# items:
# type: array
# items:
# type: string
# enum:
# - Cat
# - Dog
array_array_enum:
type: array
items:
type: array
items:
type: string
enum:
- Cat
- Dog
OuterEnum:
type: "string"
enum:

View File

@ -7,8 +7,8 @@ license = "Unlicense"
[features]
default = ["client", "server"]
client = ["serde_json", "serde_urlencoded", "serde-xml-rs", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid", "multipart"]
server = ["serde_json", "serde-xml-rs", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid", "multipart"]
client = ["serde_json", "serde_urlencoded", "serde-xml-rs", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"]
server = ["serde_json", "serde-xml-rs", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"]
[dependencies]
# Required by example server.

View File

@ -657,6 +657,19 @@ paths:
- -1.2
format: double
type: number
requestBody:
content:
application/x-www-form-urlencoded:
schema:
properties:
enum_form_string:
default: -efg
description: Form parameter enum test (string)
enum:
- _abc
- -efg
- (xyz)
type: string
responses:
400:
content: {}
@ -738,6 +751,10 @@ paths:
description: None
pattern: ^[A-Z].*
type: string
byte:
description: None
format: byte
type: string
binary:
description: None
format: binary
@ -760,6 +777,7 @@ paths:
description: None
type: string
required:
- byte
- double
- number
- pattern_without_delimiter
@ -1247,6 +1265,13 @@ components:
$ref: '#/components/schemas/ReadOnlyFirst'
type: array
type: array
array_of_enum:
items:
enum:
- UPPER
- lower
type: string
type: array
type: object
OuterComposite:
example:
@ -1297,6 +1322,9 @@ components:
format: byte
pattern: ^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$
type: string
binary:
format: binary
type: string
date:
format: date
type: string
@ -1331,6 +1359,15 @@ components:
- crab
type: string
type: array
array_array_enum:
items:
items:
enum:
- Cat
- Dog
type: string
type: array
type: array
type: object
OuterString:
type: string
@ -1370,6 +1407,15 @@ components:
type: string
type: object
type: object
map_map_of_enum:
additionalProperties:
additionalProperties:
enum:
- UPPER
- lower
type: string
type: object
type: object
map_of_enum_string:
additionalProperties:
enum:

View File

@ -160,12 +160,12 @@ fn main() {
// },
Some("TestEndpointParameters") => {
let result = core.run(client.test_endpoint_parameters(8.14, 1.2, "pattern_without_delimiter_example".to_string(), Some(56), Some(56), Some(789), Some(3.4), Some("string_example".to_string()), Box::new(future::ok(Some(Box::new(stream::once(Ok(b"hello".to_vec()))) as Box<Stream<Item=_, Error=_> + Send>))) as Box<Future<Item=_, Error=_> + Send>, None, None, Some("password_example".to_string()), Some("callback_example".to_string())));
let result = core.run(client.test_endpoint_parameters(8.14, 1.2, "pattern_without_delimiter_example".to_string(), swagger::ByteArray(Vec::from("BYTE_ARRAY_DATA_HERE")), Some(56), Some(56), Some(789), Some(3.4), Some("string_example".to_string()), Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE"))), None, None, Some("password_example".to_string()), Some("callback_example".to_string())));
println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has<XSpanIdString>).get().clone());
},
Some("TestEnumParameters") => {
let result = core.run(client.test_enum_parameters(Some(&Vec::new()), Some("enum_header_string_example".to_string()), Some(&Vec::new()), Some("enum_query_string_example".to_string()), Some(56), Some(1.2)));
let result = core.run(client.test_enum_parameters(Some(&Vec::new()), Some("enum_header_string_example".to_string()), Some(&Vec::new()), Some("enum_query_string_example".to_string()), Some(56), Some(1.2), Some("enum_form_string_example".to_string())));
println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has<XSpanIdString>).get().clone());
},
@ -224,7 +224,7 @@ fn main() {
},
Some("UploadFile") => {
let result = core.run(client.upload_file(789, Some("additional_metadata_example".to_string()), Box::new(future::ok(Some(Box::new(stream::once(Ok(b"hello".to_vec()))) as Box<Stream<Item=_, Error=_> + Send>))) as Box<Future<Item=_, Error=_> + Send>));
let result = core.run(client.upload_file(789, Some("additional_metadata_example".to_string()), Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE")))));
println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has<XSpanIdString>).get().clone());
},

View File

@ -4,9 +4,7 @@
use futures::{self, Future};
use chrono;
use futures::Stream;
use std::collections::HashMap;
use std::io::Error;
use std::marker::PhantomData;
use swagger;
@ -111,17 +109,16 @@ impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
}
/// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트
fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, integer: Option<i32>, int32: Option<i32>, int64: Option<i64>, float: Option<f32>, string: Option<String>, binary: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>, date: Option<chrono::DateTime<chrono::Utc>>, date_time: Option<chrono::DateTime<chrono::Utc>>, password: Option<String>, callback: Option<String>, context: &C) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>> {
fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, integer: Option<i32>, int32: Option<i32>, int64: Option<i64>, float: Option<f32>, string: Option<String>, binary: Option<swagger::ByteArray>, date: Option<chrono::DateTime<chrono::Utc>>, date_time: Option<chrono::DateTime<chrono::Utc>>, password: Option<String>, callback: Option<String>, context: &C) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>> {
let context = context.clone();
println!("test_endpoint_parameters({}, {}, \"{}\", {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", number, double, pattern_without_delimiter, integer, int32, int64, float, string, date, date_time, password, callback, context.get().0.clone());
let _ = binary; //Suppresses unused param warning
println!("test_endpoint_parameters({}, {}, \"{}\", {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", number, double, pattern_without_delimiter, byte, integer, int32, int64, float, string, binary, date, date_time, password, callback, context.get().0.clone());
Box::new(futures::failed("Generic failure".into()))
}
/// To test enum parameters
fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec<String>>, enum_header_string: Option<String>, enum_query_string_array: Option<&Vec<String>>, enum_query_string: Option<String>, enum_query_integer: Option<i32>, enum_query_double: Option<f64>, context: &C) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>> {
fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec<String>>, enum_header_string: Option<String>, enum_query_string_array: Option<&Vec<String>>, enum_query_string: Option<String>, enum_query_integer: Option<i32>, enum_query_double: Option<f64>, enum_form_string: Option<String>, context: &C) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>> {
let context = context.clone();
println!("test_enum_parameters({:?}, {:?}, {:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", enum_header_string_array, enum_header_string, enum_query_string_array, enum_query_string, enum_query_integer, enum_query_double, context.get().0.clone());
println!("test_enum_parameters({:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", enum_header_string_array, enum_header_string, enum_query_string_array, enum_query_string, enum_query_integer, enum_query_double, enum_form_string, context.get().0.clone());
Box::new(futures::failed("Generic failure".into()))
}
@ -196,10 +193,9 @@ impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
}
/// uploads an image
fn upload_file(&self, pet_id: i64, additional_metadata: Option<String>, file: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>, context: &C) -> Box<Future<Item=UploadFileResponse, Error=ApiError>> {
fn upload_file(&self, pet_id: i64, additional_metadata: Option<String>, file: Option<swagger::ByteArray>, context: &C) -> Box<Future<Item=UploadFileResponse, Error=ApiError>> {
let context = context.clone();
println!("upload_file({}, {:?}, ) - X-Span-ID: {:?}", pet_id, additional_metadata, context.get().0.clone());
let _ = file; //Suppresses unused param warning
println!("upload_file({}, {:?}, {:?}) - X-Span-ID: {:?}", pet_id, additional_metadata, file, context.get().0.clone());
Box::new(futures::failed("Generic failure".into()))
}

View File

@ -6,11 +6,9 @@ extern crate openssl;
extern crate mime;
extern crate chrono;
extern crate url;
extern crate multipart;
extern crate serde_urlencoded;
use self::multipart::client::lazy::Multipart;
use hyper;
use hyper::header::{Headers, ContentType};
use hyper::Uri;
@ -298,8 +296,6 @@ impl<F, C> Api<C> for Client<F> where
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -307,7 +303,6 @@ impl<F, C> Api<C> for Client<F> where
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -378,8 +373,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -387,7 +380,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -456,8 +448,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -465,7 +455,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -534,8 +523,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -543,7 +530,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -612,8 +598,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -621,7 +605,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -692,8 +675,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -757,8 +738,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -766,7 +745,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -807,7 +785,7 @@ if let Some(body) = body {
}
fn test_endpoint_parameters(&self, param_number: f64, param_double: f64, param_pattern_without_delimiter: String, param_integer: Option<i32>, param_int32: Option<i32>, param_int64: Option<i64>, param_float: Option<f32>, param_string: Option<String>, param_binary: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>, param_date: Option<chrono::DateTime<chrono::Utc>>, param_date_time: Option<chrono::DateTime<chrono::Utc>>, param_password: Option<String>, param_callback: Option<String>, context: &C) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>> {
fn test_endpoint_parameters(&self, param_number: f64, param_double: f64, param_pattern_without_delimiter: String, param_byte: swagger::ByteArray, param_integer: Option<i32>, param_int32: Option<i32>, param_int64: Option<i64>, param_float: Option<f32>, param_string: Option<String>, param_binary: Option<swagger::ByteArray>, param_date: Option<chrono::DateTime<chrono::Utc>>, param_date_time: Option<chrono::DateTime<chrono::Utc>>, param_password: Option<String>, param_callback: Option<String>, context: &C) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>> {
let uri = format!(
@ -822,41 +800,26 @@ if let Some(body) = body {
let mut request = hyper::Request::new(hyper::Method::Post, uri);
// Form data body
let mut multipart = Multipart::new();
let params = &[
("integer", param_integer.map(|param| format!("{:?}", param))),
("int32", param_int32.map(|param| format!("{:?}", param))),
("int64", param_int64.map(|param| format!("{:?}", param))),
("number", Some(format!("{:?}", param_number))),
("float", param_float.map(|param| format!("{:?}", param))),
("double", Some(format!("{:?}", param_double))),
("string", param_string),
("pattern_without_delimiter", Some(param_pattern_without_delimiter)),
("byte", Some(format!("{:?}", param_byte))),
("binary", param_binary.map(|param| format!("{:?}", param))),
("date", param_date.map(|param| format!("{:?}", param))),
("dateTime", param_date_time.map(|param| format!("{:?}", param))),
("password", param_password),
("callback", param_callback),
];
let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize");
// Helper function to convert a Stream into a String. The String can then be used to build the HTTP body.
fn convert_stream_to_string(stream: Box<Stream<Item=Vec<u8>, Error=Error> + Send>) -> Result<String, ApiError> {
stream.concat2()
.wait()
.map_err(|e| ApiError(format!("Unable to collect stream: {}", e)))
.and_then(|body| String::from_utf8(body)
.map_err(|e| ApiError(format!("Failed to convert utf8 stream to String: {}", e))))
}
if let Ok(Some(param_binary)) = param_binary.wait() {
match convert_stream_to_string(param_binary) {
Ok(param_binary) => {
// Add file to multipart form.
multipart.add_text("binary", param_binary);
},
Err(err) => return Box::new(futures::done(Err(err))),
}
}
let mut fields = match multipart.prepare() {
Ok(fields) => fields,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build request: {}", err))))),
};
let mut body_string = String::new();
let body = fields.to_body().read_to_string(&mut body_string);
let boundary = fields.boundary();
let multipart_header = match mime::Mime::from_str(&format!("multipart/form-data;boundary={}", boundary)) {
Ok(multipart_header) => multipart_header,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build multipart header: {:?}", err))))),
};
request.headers_mut().set(ContentType(mimetypes::requests::TEST_ENDPOINT_PARAMETERS.clone()));
request.set_body(body.into_bytes());
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
(context as &Has<Option<AuthData>>).get().as_ref().map(|auth_data| {
@ -867,11 +830,6 @@ if let Some(body) = body {
}
});
request.headers_mut().set(ContentType(multipart_header));
request.set_body(body_string.into_bytes());
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -918,7 +876,7 @@ if let Some(body) = body {
}
fn test_enum_parameters(&self, param_enum_header_string_array: Option<&Vec<String>>, param_enum_header_string: Option<String>, param_enum_query_string_array: Option<&Vec<String>>, param_enum_query_string: Option<String>, param_enum_query_integer: Option<i32>, param_enum_query_double: Option<f64>, context: &C) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>> {
fn test_enum_parameters(&self, param_enum_header_string_array: Option<&Vec<String>>, param_enum_header_string: Option<String>, param_enum_query_string_array: Option<&Vec<String>>, param_enum_query_string: Option<String>, param_enum_query_integer: Option<i32>, param_enum_query_double: Option<f64>, param_enum_form_string: Option<String>, context: &C) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>> {
// Query parameters
let query_enum_query_string_array = param_enum_query_string_array.map_or_else(String::new, |query| format!("enum_query_string_array={enum_query_string_array}&", enum_query_string_array=query.join(",")));
@ -943,7 +901,13 @@ if let Some(body) = body {
let mut request = hyper::Request::new(hyper::Method::Get, uri);
let params = &[
("enum_form_string", param_enum_form_string),
];
let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize");
request.headers_mut().set(ContentType(mimetypes::requests::TEST_ENUM_PARAMETERS.clone()));
request.set_body(body.into_bytes());
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
@ -954,8 +918,6 @@ if let Some(body) = body {
param_enum_header_string.map(|header| request.headers_mut().set(RequestEnumHeaderString(header)));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1028,8 +990,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1094,8 +1054,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1161,8 +1119,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1170,7 +1126,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -1239,8 +1194,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1302,8 +1255,6 @@ if let Some(body) = body {
param_api_key.map(|header| request.headers_mut().set(RequestApiKey(header)));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1365,8 +1316,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1374,7 +1323,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -1450,8 +1398,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1459,7 +1405,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -1531,8 +1476,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1540,7 +1483,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -1627,8 +1569,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1711,8 +1651,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1750,7 +1688,7 @@ if let Some(body) = body {
}
fn upload_file(&self, param_pet_id: i64, param_additional_metadata: Option<String>, param_file: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>, context: &C) -> Box<Future<Item=UploadFileResponse, Error=ApiError>> {
fn upload_file(&self, param_pet_id: i64, param_additional_metadata: Option<String>, param_file: Option<swagger::ByteArray>, context: &C) -> Box<Future<Item=UploadFileResponse, Error=ApiError>> {
let uri = format!(
@ -1765,50 +1703,18 @@ if let Some(body) = body {
let mut request = hyper::Request::new(hyper::Method::Post, uri);
// Form data body
let mut multipart = Multipart::new();
let params = &[
("additionalMetadata", param_additional_metadata),
("file", param_file.map(|param| format!("{:?}", param))),
];
let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize");
// Helper function to convert a Stream into a String. The String can then be used to build the HTTP body.
fn convert_stream_to_string(stream: Box<Stream<Item=Vec<u8>, Error=Error> + Send>) -> Result<String, ApiError> {
stream.concat2()
.wait()
.map_err(|e| ApiError(format!("Unable to collect stream: {}", e)))
.and_then(|body| String::from_utf8(body)
.map_err(|e| ApiError(format!("Failed to convert utf8 stream to String: {}", e))))
}
if let Ok(Some(param_file)) = param_file.wait() {
match convert_stream_to_string(param_file) {
Ok(param_file) => {
// Add file to multipart form.
multipart.add_text("file", param_file);
},
Err(err) => return Box::new(futures::done(Err(err))),
}
}
let mut fields = match multipart.prepare() {
Ok(fields) => fields,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build request: {}", err))))),
};
let mut body_string = String::new();
let body = fields.to_body().read_to_string(&mut body_string);
let boundary = fields.boundary();
let multipart_header = match mime::Mime::from_str(&format!("multipart/form-data;boundary={}", boundary)) {
Ok(multipart_header) => multipart_header,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build multipart header: {:?}", err))))),
};
request.headers_mut().set(ContentType(mimetypes::requests::UPLOAD_FILE.clone()));
request.set_body(body.into_bytes());
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
request.headers_mut().set(ContentType(multipart_header));
request.set_body(body_string.into_bytes());
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1816,7 +1722,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -1877,8 +1782,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1945,8 +1848,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -1954,7 +1855,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -2015,8 +1915,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -2024,7 +1922,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -2111,8 +2008,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -2120,7 +2015,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -2200,8 +2094,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -2265,8 +2157,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -2330,8 +2220,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -2389,8 +2277,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -2457,8 +2343,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -2466,7 +2350,6 @@ if let Some(body) = body {
200 => {
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -2553,8 +2436,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -2572,7 +2453,6 @@ if let Some(body) = body {
};
let body = response.body();
Box::new(
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
@ -2644,8 +2524,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
@ -2709,8 +2587,6 @@ if let Some(body) = body {
request.headers_mut().set(XSpanId((context as &Has<XSpanIdString>).get().0.clone()));
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {

View File

@ -288,10 +288,10 @@ pub trait Api<C> {
fn test_client_model(&self, client: models::Client, context: &C) -> Box<Future<Item=TestClientModelResponse, Error=ApiError>>;
/// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트
fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, integer: Option<i32>, int32: Option<i32>, int64: Option<i64>, float: Option<f32>, string: Option<String>, binary: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>, date: Option<chrono::DateTime<chrono::Utc>>, date_time: Option<chrono::DateTime<chrono::Utc>>, password: Option<String>, callback: Option<String>, context: &C) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>>;
fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, integer: Option<i32>, int32: Option<i32>, int64: Option<i64>, float: Option<f32>, string: Option<String>, binary: Option<swagger::ByteArray>, date: Option<chrono::DateTime<chrono::Utc>>, date_time: Option<chrono::DateTime<chrono::Utc>>, password: Option<String>, callback: Option<String>, context: &C) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>>;
/// To test enum parameters
fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec<String>>, enum_header_string: Option<String>, enum_query_string_array: Option<&Vec<String>>, enum_query_string: Option<String>, enum_query_integer: Option<i32>, enum_query_double: Option<f64>, context: &C) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>>;
fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec<String>>, enum_header_string: Option<String>, enum_query_string_array: Option<&Vec<String>>, enum_query_string: Option<String>, enum_query_integer: Option<i32>, enum_query_double: Option<f64>, enum_form_string: Option<String>, context: &C) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>>;
/// test inline additionalProperties
fn test_inline_additional_properties(&self, request_body: HashMap<String, String>, context: &C) -> Box<Future<Item=TestInlineAdditionalPropertiesResponse, Error=ApiError>>;
@ -324,7 +324,7 @@ pub trait Api<C> {
fn update_pet_with_form(&self, pet_id: i64, name: Option<String>, status: Option<String>, context: &C) -> Box<Future<Item=UpdatePetWithFormResponse, Error=ApiError>>;
/// uploads an image
fn upload_file(&self, pet_id: i64, additional_metadata: Option<String>, file: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>, context: &C) -> Box<Future<Item=UploadFileResponse, Error=ApiError>>;
fn upload_file(&self, pet_id: i64, additional_metadata: Option<String>, file: Option<swagger::ByteArray>, context: &C) -> Box<Future<Item=UploadFileResponse, Error=ApiError>>;
/// Delete purchase order by ID
fn delete_order(&self, order_id: String, context: &C) -> Box<Future<Item=DeleteOrderResponse, Error=ApiError>>;
@ -389,10 +389,10 @@ pub trait ApiNoContext {
fn test_client_model(&self, client: models::Client) -> Box<Future<Item=TestClientModelResponse, Error=ApiError>>;
/// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트
fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, integer: Option<i32>, int32: Option<i32>, int64: Option<i64>, float: Option<f32>, string: Option<String>, binary: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>, date: Option<chrono::DateTime<chrono::Utc>>, date_time: Option<chrono::DateTime<chrono::Utc>>, password: Option<String>, callback: Option<String>) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>>;
fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, integer: Option<i32>, int32: Option<i32>, int64: Option<i64>, float: Option<f32>, string: Option<String>, binary: Option<swagger::ByteArray>, date: Option<chrono::DateTime<chrono::Utc>>, date_time: Option<chrono::DateTime<chrono::Utc>>, password: Option<String>, callback: Option<String>) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>>;
/// To test enum parameters
fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec<String>>, enum_header_string: Option<String>, enum_query_string_array: Option<&Vec<String>>, enum_query_string: Option<String>, enum_query_integer: Option<i32>, enum_query_double: Option<f64>) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>>;
fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec<String>>, enum_header_string: Option<String>, enum_query_string_array: Option<&Vec<String>>, enum_query_string: Option<String>, enum_query_integer: Option<i32>, enum_query_double: Option<f64>, enum_form_string: Option<String>) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>>;
/// test inline additionalProperties
fn test_inline_additional_properties(&self, request_body: HashMap<String, String>) -> Box<Future<Item=TestInlineAdditionalPropertiesResponse, Error=ApiError>>;
@ -425,7 +425,7 @@ pub trait ApiNoContext {
fn update_pet_with_form(&self, pet_id: i64, name: Option<String>, status: Option<String>) -> Box<Future<Item=UpdatePetWithFormResponse, Error=ApiError>>;
/// uploads an image
fn upload_file(&self, pet_id: i64, additional_metadata: Option<String>, file: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>) -> Box<Future<Item=UploadFileResponse, Error=ApiError>>;
fn upload_file(&self, pet_id: i64, additional_metadata: Option<String>, file: Option<swagger::ByteArray>) -> Box<Future<Item=UploadFileResponse, Error=ApiError>>;
/// Delete purchase order by ID
fn delete_order(&self, order_id: String) -> Box<Future<Item=DeleteOrderResponse, Error=ApiError>>;
@ -515,13 +515,13 @@ impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
}
/// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트
fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, integer: Option<i32>, int32: Option<i32>, int64: Option<i64>, float: Option<f32>, string: Option<String>, binary: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>, date: Option<chrono::DateTime<chrono::Utc>>, date_time: Option<chrono::DateTime<chrono::Utc>>, password: Option<String>, callback: Option<String>) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>> {
self.api().test_endpoint_parameters(number, double, pattern_without_delimiter, integer, int32, int64, float, string, binary, date, date_time, password, callback, &self.context())
fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, integer: Option<i32>, int32: Option<i32>, int64: Option<i64>, float: Option<f32>, string: Option<String>, binary: Option<swagger::ByteArray>, date: Option<chrono::DateTime<chrono::Utc>>, date_time: Option<chrono::DateTime<chrono::Utc>>, password: Option<String>, callback: Option<String>) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>> {
self.api().test_endpoint_parameters(number, double, pattern_without_delimiter, byte, integer, int32, int64, float, string, binary, date, date_time, password, callback, &self.context())
}
/// To test enum parameters
fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec<String>>, enum_header_string: Option<String>, enum_query_string_array: Option<&Vec<String>>, enum_query_string: Option<String>, enum_query_integer: Option<i32>, enum_query_double: Option<f64>) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>> {
self.api().test_enum_parameters(enum_header_string_array, enum_header_string, enum_query_string_array, enum_query_string, enum_query_integer, enum_query_double, &self.context())
fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec<String>>, enum_header_string: Option<String>, enum_query_string_array: Option<&Vec<String>>, enum_query_string: Option<String>, enum_query_integer: Option<i32>, enum_query_double: Option<f64>, enum_form_string: Option<String>) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>> {
self.api().test_enum_parameters(enum_header_string_array, enum_header_string, enum_query_string_array, enum_query_string, enum_query_integer, enum_query_double, enum_form_string, &self.context())
}
/// test inline additionalProperties
@ -575,7 +575,7 @@ impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
}
/// uploads an image
fn upload_file(&self, pet_id: i64, additional_metadata: Option<String>, file: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>) -> Box<Future<Item=UploadFileResponse, Error=ApiError>> {
fn upload_file(&self, pet_id: i64, additional_metadata: Option<String>, file: Option<swagger::ByteArray>) -> Box<Future<Item=UploadFileResponse, Error=ApiError>> {
self.api().upload_file(pet_id, additional_metadata, file, &self.context())
}

View File

@ -101,6 +101,14 @@ pub mod requests {
lazy_static! {
pub static ref TEST_CLIENT_MODEL: Mime = "application/json".parse().unwrap();
}
/// Create Mime objects for the request content types for TestEndpointParameters
lazy_static! {
pub static ref TEST_ENDPOINT_PARAMETERS: Mime = "application/x-www-form-urlencoded".parse().unwrap();
}
/// Create Mime objects for the request content types for TestEnumParameters
lazy_static! {
pub static ref TEST_ENUM_PARAMETERS: Mime = "application/x-www-form-urlencoded".parse().unwrap();
}
/// Create Mime objects for the request content types for TestInlineAdditionalProperties
lazy_static! {
pub static ref TEST_INLINE_ADDITIONAL_PROPERTIES: Mime = "application/json".parse().unwrap();
@ -125,6 +133,10 @@ pub mod requests {
lazy_static! {
pub static ref UPDATE_PET_WITH_FORM: Mime = "application/x-www-form-urlencoded".parse().unwrap();
}
/// Create Mime objects for the request content types for UploadFile
lazy_static! {
pub static ref UPLOAD_FILE: Mime = "multipart/form-data".parse().unwrap();
}
/// Create Mime objects for the request content types for PlaceOrder
lazy_static! {
pub static ref PLACE_ORDER: Mime = "application/json".parse().unwrap();

View File

@ -185,6 +185,11 @@ pub struct ArrayTest {
#[serde(skip_serializing_if="Option::is_none")]
pub array_array_of_model: Option<Vec<Vec<models::ReadOnlyFirst>>>,
// Note: inline enums are not fully supported by openapi-generator
#[serde(rename = "array_of_enum")]
#[serde(skip_serializing_if="Option::is_none")]
pub array_of_enum: Option<Vec<String>>,
}
impl ArrayTest {
@ -193,6 +198,7 @@ impl ArrayTest {
array_of_string: None,
array_array_of_integer: None,
array_array_of_model: None,
array_of_enum: None,
}
}
}
@ -356,6 +362,11 @@ pub struct EnumArrays {
#[serde(skip_serializing_if="Option::is_none")]
pub array_enum: Option<Vec<String>>,
// Note: inline enums are not fully supported by openapi-generator
#[serde(rename = "array_array_enum")]
#[serde(skip_serializing_if="Option::is_none")]
pub array_array_enum: Option<Vec<Vec<String>>>,
}
impl EnumArrays {
@ -363,6 +374,7 @@ impl EnumArrays {
EnumArrays {
just_symbol: None,
array_enum: None,
array_array_enum: None,
}
}
}
@ -475,6 +487,10 @@ pub struct FormatTest {
#[serde(rename = "byte")]
pub byte: swagger::ByteArray,
#[serde(rename = "binary")]
#[serde(skip_serializing_if="Option::is_none")]
pub binary: Option<swagger::ByteArray>,
#[serde(rename = "date")]
pub date: chrono::DateTime<chrono::Utc>,
@ -502,6 +518,7 @@ impl FormatTest {
double: None,
string: None,
byte: byte,
binary: None,
date: date,
date_time: None,
uuid: None,
@ -553,6 +570,11 @@ pub struct MapTest {
#[serde(skip_serializing_if="Option::is_none")]
pub map_map_of_string: Option<HashMap<String, HashMap<String, String>>>,
// Note: inline enums are not fully supported by openapi-generator
#[serde(rename = "map_map_of_enum")]
#[serde(skip_serializing_if="Option::is_none")]
pub map_map_of_enum: Option<HashMap<String, HashMap<String, String>>>,
// Note: inline enums are not fully supported by openapi-generator
#[serde(rename = "map_of_enum_string")]
#[serde(skip_serializing_if="Option::is_none")]
@ -564,6 +586,7 @@ impl MapTest {
pub fn new() -> MapTest {
MapTest {
map_map_of_string: None,
map_map_of_enum: None,
map_of_enum_string: None,
}
}

View File

@ -7,7 +7,6 @@ extern crate openssl;
extern crate mime;
extern crate uuid;
extern crate chrono;
extern crate multipart;
extern crate percent_encoding;
extern crate url;
@ -20,8 +19,6 @@ use hyper::{Request, Response, Error, StatusCode};
use hyper::header::{Headers, ContentType};
use self::url::form_urlencoded;
use mimetypes;
use self::multipart::server::Multipart;
use self::multipart::server::save::SaveResult;
use serde_json;
use serde_xml_rs;
@ -832,185 +829,26 @@ where
let boundary = match multipart_boundary(&headers) {
Some(boundary) => boundary.to_string(),
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Couldn't find valid multipart body"))),
};
Box::new(body.concat2()
.then(move |result| -> Box<Future<Item=Response, Error=Error>> {
match result {
Ok(body) => {
let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary).save().temp() {
SaveResult::Full(entries) => {
entries
},
_ => {
return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Unable to process all message parts"))))
},
};
Box::new({
{{
// Form parameters
let param_integer = entries.fields.remove("integer");
let param_integer = match param_integer {
Some(entry) =>
let param_integer = Some(56);
let param_int32 = Some(56);
let param_int64 = Some(789);
let param_number = 8.14;
let param_float = Some(3.4);
let param_double = 1.2;
let param_string = Some("string_example".to_string());
let param_pattern_without_delimiter = "pattern_without_delimiter_example".to_string();
let param_byte = swagger::ByteArray(Vec::from("BYTE_ARRAY_DATA_HERE"));
let param_binary = Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE")));
let param_date = None;
let param_date_time = None;
let param_password = Some("password_example".to_string());
let param_callback = Some("callback_example".to_string());
match entry.parse::<i32>() {
Ok(entry) => Some(entry),
Err(_) => None,
},
None => None,
};
let param_int32 = entries.fields.remove("int32");
let param_int32 = match param_int32 {
Some(entry) =>
match entry.parse::<i32>() {
Ok(entry) => Some(entry),
Err(_) => None,
},
None => None,
};
let param_int64 = entries.fields.remove("int64");
let param_int64 = match param_int64 {
Some(entry) =>
match entry.parse::<i64>() {
Ok(entry) => Some(entry),
Err(_) => None,
},
None => None,
};
let param_number = entries.fields.remove("number");
let param_number = match param_number {
Some(entry) =>
match entry.parse::<f64>() {
Ok(entry) => entry,
Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse form parameter number - doesn't match schema: {}", e)))),
},
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Missing required form parameter number")))),
};
let param_float = entries.fields.remove("float");
let param_float = match param_float {
Some(entry) =>
match entry.parse::<f32>() {
Ok(entry) => Some(entry),
Err(_) => None,
},
None => None,
};
let param_double = entries.fields.remove("double");
let param_double = match param_double {
Some(entry) =>
match entry.parse::<f64>() {
Ok(entry) => entry,
Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse form parameter double - doesn't match schema: {}", e)))),
},
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Missing required form parameter double")))),
};
let param_string = entries.fields.remove("string");
let param_string = match param_string {
Some(entry) =>
match entry.parse::<String>() {
Ok(entry) => Some(entry),
Err(_) => None,
},
None => None,
};
let param_pattern_without_delimiter = entries.fields.remove("pattern_without_delimiter");
let param_pattern_without_delimiter = match param_pattern_without_delimiter {
Some(entry) =>
match entry.parse::<String>() {
Ok(entry) => entry,
Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse form parameter pattern_without_delimiter - doesn't match schema: {}", e)))),
},
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Missing required form parameter pattern_without_delimiter")))),
};
let param_binary = entries.fields.remove("binary");
let param_binary = match param_binary {
Some(entry) =>
Some(Box::new(stream::once(Ok(entry.as_bytes().to_vec()))) as Box<Stream<Item=Vec<u8>, Error=io::Error> + Send>),
None => None,
};
let param_binary = Box::new(future::ok(param_binary));
let param_date = entries.fields.remove("date");
let param_date = match param_date {
Some(entry) =>
match entry.parse::<chrono::DateTime<chrono::Utc>>() {
Ok(entry) => Some(entry),
Err(_) => None,
},
None => None,
};
let param_date_time = entries.fields.remove("date_time");
let param_date_time = match param_date_time {
Some(entry) =>
match entry.parse::<chrono::DateTime<chrono::Utc>>() {
Ok(entry) => Some(entry),
Err(_) => None,
},
None => None,
};
let param_password = entries.fields.remove("password");
let param_password = match param_password {
Some(entry) =>
match entry.parse::<String>() {
Ok(entry) => Some(entry),
Err(_) => None,
},
None => None,
};
let param_callback = entries.fields.remove("callback");
let param_callback = match param_callback {
Some(entry) =>
match entry.parse::<String>() {
Ok(entry) => Some(entry),
Err(_) => None,
},
None => None,
};
Box::new(api_impl.test_endpoint_parameters(param_number, param_double, param_pattern_without_delimiter, param_integer, param_int32, param_int64, param_float, param_string, param_binary, param_date, param_date_time, param_password, param_callback, &context)
Box::new(api_impl.test_endpoint_parameters(param_number, param_double, param_pattern_without_delimiter, param_byte, param_integer, param_int32, param_int64, param_float, param_string, param_binary, param_date, param_date_time, param_password, param_callback, &context)
.then(move |result| {
let mut response = Response::new();
response.headers_mut().set(XSpanId((&context as &Has<XSpanIdString>).get().0.to_string()));
@ -1044,12 +882,8 @@ where
}
))
as Box<Future<Item=Response, Error=Error>>
},
Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))),
}
})
)
}}
}) as Box<Future<Item=Response, Error=Error>>
},
@ -1099,7 +933,10 @@ where
Box::new({
{{
Box::new(api_impl.test_enum_parameters(param_enum_header_string_array.as_ref(), param_enum_header_string, param_enum_query_string_array.as_ref(), param_enum_query_string, param_enum_query_integer, param_enum_query_double, &context)
// Form parameters
let param_enum_form_string = Some("enum_form_string_example".to_string());
Box::new(api_impl.test_enum_parameters(param_enum_header_string_array.as_ref(), param_enum_header_string, param_enum_query_string_array.as_ref(), param_enum_query_string, param_enum_query_integer, param_enum_query_double, param_enum_form_string, &context)
.then(move |result| {
let mut response = Response::new();
response.headers_mut().set(XSpanId((&context as &Has<XSpanIdString>).get().0.to_string()));
@ -2108,46 +1945,12 @@ where
let boundary = match multipart_boundary(&headers) {
Some(boundary) => boundary.to_string(),
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Couldn't find valid multipart body"))),
};
Box::new(body.concat2()
.then(move |result| -> Box<Future<Item=Response, Error=Error>> {
match result {
Ok(body) => {
let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary).save().temp() {
SaveResult::Full(entries) => {
entries
},
_ => {
return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Unable to process all message parts"))))
},
};
Box::new({
{{
// Form parameters
let param_additional_metadata = entries.fields.remove("additional_metadata");
let param_additional_metadata = match param_additional_metadata {
Some(entry) =>
match entry.parse::<String>() {
Ok(entry) => Some(entry),
Err(_) => None,
},
None => None,
};
let param_file = entries.fields.remove("file");
let param_file = match param_file {
Some(entry) =>
Some(Box::new(stream::once(Ok(entry.as_bytes().to_vec()))) as Box<Stream<Item=Vec<u8>, Error=io::Error> + Send>),
None => None,
};
let param_file = Box::new(future::ok(param_file));
let param_additional_metadata = Some("additional_metadata_example".to_string());
let param_file = Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE")));
Box::new(api_impl.upload_file(param_pet_id, param_additional_metadata, param_file, &context)
.then(move |result| {
@ -2184,12 +1987,8 @@ where
}
))
as Box<Future<Item=Response, Error=Error>>
},
Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))),
}
})
)
}}
}) as Box<Future<Item=Response, Error=Error>>
},
@ -3140,123 +2939,3 @@ where
}
}
}
/// Utility function to get the multipart boundary marker (if any) from the Headers.
fn multipart_boundary<'a>(headers: &'a Headers) -> Option<&'a str> {
headers.get::<ContentType>().and_then(|content_type| {
let ContentType(ref mime) = *content_type;
if mime.type_() == mime::MULTIPART && mime.subtype() == mime::FORM_DATA {
mime.get_param(mime::BOUNDARY).map(|x| x.as_str())
} else {
None
}
})
}
/// Request parser for `Api`.
pub struct ApiRequestParser;
impl RequestParser for ApiRequestParser {
fn parse_operation_id(request: &Request) -> Result<&'static str, ()> {
let path = paths::GLOBAL_REGEX_SET.matches(request.uri().path());
match request.method() {
// TestSpecialTags - PATCH /another-fake/dummy
&hyper::Method::Patch if path.matched(paths::ID_ANOTHER_FAKE_DUMMY) => Ok("TestSpecialTags"),
// FakeOuterBooleanSerialize - POST /fake/outer/boolean
&hyper::Method::Post if path.matched(paths::ID_FAKE_OUTER_BOOLEAN) => Ok("FakeOuterBooleanSerialize"),
// FakeOuterCompositeSerialize - POST /fake/outer/composite
&hyper::Method::Post if path.matched(paths::ID_FAKE_OUTER_COMPOSITE) => Ok("FakeOuterCompositeSerialize"),
// FakeOuterNumberSerialize - POST /fake/outer/number
&hyper::Method::Post if path.matched(paths::ID_FAKE_OUTER_NUMBER) => Ok("FakeOuterNumberSerialize"),
// FakeOuterStringSerialize - POST /fake/outer/string
&hyper::Method::Post if path.matched(paths::ID_FAKE_OUTER_STRING) => Ok("FakeOuterStringSerialize"),
// TestBodyWithQueryParams - PUT /fake/body-with-query-params
&hyper::Method::Put if path.matched(paths::ID_FAKE_BODY_WITH_QUERY_PARAMS) => Ok("TestBodyWithQueryParams"),
// TestClientModel - PATCH /fake
&hyper::Method::Patch if path.matched(paths::ID_FAKE) => Ok("TestClientModel"),
// TestEndpointParameters - POST /fake
&hyper::Method::Post if path.matched(paths::ID_FAKE) => Ok("TestEndpointParameters"),
// TestEnumParameters - GET /fake
&hyper::Method::Get if path.matched(paths::ID_FAKE) => Ok("TestEnumParameters"),
// TestInlineAdditionalProperties - POST /fake/inline-additionalProperties
&hyper::Method::Post if path.matched(paths::ID_FAKE_INLINE_ADDITIONALPROPERTIES) => Ok("TestInlineAdditionalProperties"),
// TestJsonFormData - GET /fake/jsonFormData
&hyper::Method::Get if path.matched(paths::ID_FAKE_JSONFORMDATA) => Ok("TestJsonFormData"),
// TestClassname - PATCH /fake_classname_test
&hyper::Method::Patch if path.matched(paths::ID_FAKE_CLASSNAME_TEST) => Ok("TestClassname"),
// AddPet - POST /pet
&hyper::Method::Post if path.matched(paths::ID_PET) => Ok("AddPet"),
// DeletePet - DELETE /pet/{petId}
&hyper::Method::Delete if path.matched(paths::ID_PET_PETID) => Ok("DeletePet"),
// FindPetsByStatus - GET /pet/findByStatus
&hyper::Method::Get if path.matched(paths::ID_PET_FINDBYSTATUS) => Ok("FindPetsByStatus"),
// FindPetsByTags - GET /pet/findByTags
&hyper::Method::Get if path.matched(paths::ID_PET_FINDBYTAGS) => Ok("FindPetsByTags"),
// GetPetById - GET /pet/{petId}
&hyper::Method::Get if path.matched(paths::ID_PET_PETID) => Ok("GetPetById"),
// UpdatePet - PUT /pet
&hyper::Method::Put if path.matched(paths::ID_PET) => Ok("UpdatePet"),
// UpdatePetWithForm - POST /pet/{petId}
&hyper::Method::Post if path.matched(paths::ID_PET_PETID) => Ok("UpdatePetWithForm"),
// UploadFile - POST /pet/{petId}/uploadImage
&hyper::Method::Post if path.matched(paths::ID_PET_PETID_UPLOADIMAGE) => Ok("UploadFile"),
// DeleteOrder - DELETE /store/order/{order_id}
&hyper::Method::Delete if path.matched(paths::ID_STORE_ORDER_ORDER_ID) => Ok("DeleteOrder"),
// GetInventory - GET /store/inventory
&hyper::Method::Get if path.matched(paths::ID_STORE_INVENTORY) => Ok("GetInventory"),
// GetOrderById - GET /store/order/{order_id}
&hyper::Method::Get if path.matched(paths::ID_STORE_ORDER_ORDER_ID) => Ok("GetOrderById"),
// PlaceOrder - POST /store/order
&hyper::Method::Post if path.matched(paths::ID_STORE_ORDER) => Ok("PlaceOrder"),
// CreateUser - POST /user
&hyper::Method::Post if path.matched(paths::ID_USER) => Ok("CreateUser"),
// CreateUsersWithArrayInput - POST /user/createWithArray
&hyper::Method::Post if path.matched(paths::ID_USER_CREATEWITHARRAY) => Ok("CreateUsersWithArrayInput"),
// CreateUsersWithListInput - POST /user/createWithList
&hyper::Method::Post if path.matched(paths::ID_USER_CREATEWITHLIST) => Ok("CreateUsersWithListInput"),
// DeleteUser - DELETE /user/{username}
&hyper::Method::Delete if path.matched(paths::ID_USER_USERNAME) => Ok("DeleteUser"),
// GetUserByName - GET /user/{username}
&hyper::Method::Get if path.matched(paths::ID_USER_USERNAME) => Ok("GetUserByName"),
// LoginUser - GET /user/login
&hyper::Method::Get if path.matched(paths::ID_USER_LOGIN) => Ok("LoginUser"),
// LogoutUser - GET /user/logout
&hyper::Method::Get if path.matched(paths::ID_USER_LOGOUT) => Ok("LogoutUser"),
// UpdateUser - PUT /user/{username}
&hyper::Method::Put if path.matched(paths::ID_USER_USERNAME) => Ok("UpdateUser"),
_ => Err(()),
}
}
}