diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java index 7c21c824df6..a39033a4501 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java @@ -164,8 +164,8 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig { typeMapping.put("date", "chrono::DateTime"); typeMapping.put("DateTime", "chrono::DateTime"); typeMapping.put("password", "String"); - typeMapping.put("File", "Box, Error=Error> + Send>"); - typeMapping.put("file", "Box, 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 + 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 + Send>" : "None"); - } else { - param.vendorExtensions.put("example", (example != null) ? "Some(" + example + ")" : "None"); - } + param.vendorExtensions.put("example", (example != null) ? "Some(" + example + ")" : "None"); } } } diff --git a/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache b/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache index f3496ed3856..7f3190a4c7c 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache @@ -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. diff --git a/modules/openapi-generator/src/main/resources/rust-server/client-mod.mustache b/modules/openapi-generator/src/main/resources/rust-server/client-mod.mustache index 0e78e327394..5326545bf5f 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/client-mod.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/client-mod.mustache @@ -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 Api for Client where F: Future + 'static, C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}}{ {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} - fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, param_{{paramName}}: {{^required}}{{#isFile}}Box{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}, context: &C) -> Box> { + fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, param_{{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box> { {{#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 Api for Client 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, Error=Error> + Send>) -> Result { - - 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(¶m_{{paramName}}).expect("impossible to fail to serialize");{{/has_namespace}}{{#has_namespace}} @@ -340,11 +304,6 @@ impl Api for Client 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 Api for Client where None => return Box::new(future::err(ApiError(String::from("Required response header {{baseName}} for response {{code}} was not found.")))) as Box>, }; {{/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 Api for Client 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}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/example-server_server.mustache b/modules/openapi-generator/src/main/resources/rust-server/example-server_server.mustache index c5122fcefac..ec7bfcab484 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/example-server_server.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/example-server_server.mustache @@ -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 Server { impl Api for Server where C: Has{ {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} {{#summary}} /// {{{summary}}}{{/summary}} - fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}, context: &C) -> Box> { + fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box> { 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}} 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 7066a7b41ea..48318f52c6a 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/lib.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/lib.mustache @@ -51,7 +51,7 @@ pub enum {{operationId}}Response { pub trait Api { {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} {{#summary}} /// {{{summary}}}{{/summary}} - fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}, context: &C) -> Box>; + fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box>; {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} } @@ -59,7 +59,7 @@ pub trait Api { pub trait ApiNoContext { {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} {{#summary}} /// {{{summary}}}{{/summary}} - fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}) -> Box>; + fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}) -> Box>; {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} } @@ -78,7 +78,7 @@ impl<'a, T: Api + Sized, C> ContextWrapperExt<'a, C> for T { impl<'a, T: Api, 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{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}) -> Box> { + fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}) -> Box> { self.api().{{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}({{#allParams}}{{paramName}}, {{/allParams}}&self.context()) } {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/mimetypes.mustache b/modules/openapi-generator/src/main/resources/rust-server/mimetypes.mustache index 047c7c7fbbc..eae9743e2d4 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/mimetypes.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/mimetypes.mustache @@ -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}} } diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-mod.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-mod.mustache index a32d7031e0f..8d20ed82a6f 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/server-mod.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/server-mod.mustache @@ -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> { - 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, 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::, 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> -{{/hasFile}}{{#hasFile}} - as Box> - }, - 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::().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(()), - } - } -} 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 0df5dc18cfa..18ccb6b5d76 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 @@ -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: diff --git a/samples/server/petstore/rust-server/Cargo.toml b/samples/server/petstore/rust-server/Cargo.toml index ce79b9f32b6..5e6be7d7a41 100644 --- a/samples/server/petstore/rust-server/Cargo.toml +++ b/samples/server/petstore/rust-server/Cargo.toml @@ -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. diff --git a/samples/server/petstore/rust-server/api/openapi.yaml b/samples/server/petstore/rust-server/api/openapi.yaml index 2747b636766..4d996d5916a 100644 --- a/samples/server/petstore/rust-server/api/openapi.yaml +++ b/samples/server/petstore/rust-server/api/openapi.yaml @@ -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: diff --git a/samples/server/petstore/rust-server/examples/client.rs b/samples/server/petstore/rust-server/examples/client.rs index 3bd3a350970..d87dd25b87e 100644 --- a/samples/server/petstore/rust-server/examples/client.rs +++ b/samples/server/petstore/rust-server/examples/client.rs @@ -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 + Send>))) as Box + 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).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).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 + Send>))) as Box + 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).get().clone()); }, diff --git a/samples/server/petstore/rust-server/examples/server_lib/server.rs b/samples/server/petstore/rust-server/examples/server_lib/server.rs index 47b50031127..c470b7be109 100644 --- a/samples/server/petstore/rust-server/examples/server_lib/server.rs +++ b/samples/server/petstore/rust-server/examples/server_lib/server.rs @@ -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 Api for Server where C: Has{ } /// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트 - fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, integer: Option, int32: Option, int64: Option, float: Option, string: Option, binary: Box, Error=Error> + Send>>, Error=Error> + Send>, date: Option>, date_time: Option>, password: Option, callback: Option, context: &C) -> Box> { + fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, integer: Option, int32: Option, int64: Option, float: Option, string: Option, binary: Option, date: Option>, date_time: Option>, password: Option, callback: Option, context: &C) -> Box> { 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>, enum_header_string: Option, enum_query_string_array: Option<&Vec>, enum_query_string: Option, enum_query_integer: Option, enum_query_double: Option, context: &C) -> Box> { + fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec>, enum_header_string: Option, enum_query_string_array: Option<&Vec>, enum_query_string: Option, enum_query_integer: Option, enum_query_double: Option, enum_form_string: Option, context: &C) -> Box> { 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 Api for Server where C: Has{ } /// uploads an image - fn upload_file(&self, pet_id: i64, additional_metadata: Option, file: Box, Error=Error> + Send>>, Error=Error> + Send>, context: &C) -> Box> { + fn upload_file(&self, pet_id: i64, additional_metadata: Option, file: Option, context: &C) -> Box> { 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())) } diff --git a/samples/server/petstore/rust-server/src/client/mod.rs b/samples/server/petstore/rust-server/src/client/mod.rs index 587837a9bd1..42c2aac4b0c 100644 --- a/samples/server/petstore/rust-server/src/client/mod.rs +++ b/samples/server/petstore/rust-server/src/client/mod.rs @@ -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 Api for Client where request.headers_mut().set(XSpanId((context as &Has).get().0.clone())); - - Box::new(self.client_service.call(request) .map_err(|e| ApiError(format!("No response received: {}", e))) .and_then(|mut response| { @@ -307,7 +303,6 @@ impl Api for Client 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).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).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).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).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).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).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, param_int32: Option, param_int64: Option, param_float: Option, param_string: Option, param_binary: Box, Error=Error> + Send>>, Error=Error> + Send>, param_date: Option>, param_date_time: Option>, param_password: Option, param_callback: Option, context: &C) -> Box> { + fn test_endpoint_parameters(&self, param_number: f64, param_double: f64, param_pattern_without_delimiter: String, param_byte: swagger::ByteArray, param_integer: Option, param_int32: Option, param_int64: Option, param_float: Option, param_string: Option, param_binary: Option, param_date: Option>, param_date_time: Option>, param_password: Option, param_callback: Option, context: &C) -> Box> { 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, Error=Error> + Send>) -> Result { - - 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).get().0.clone())); (context as &Has>).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>, param_enum_header_string: Option, param_enum_query_string_array: Option<&Vec>, param_enum_query_string: Option, param_enum_query_integer: Option, param_enum_query_double: Option, context: &C) -> Box> { + fn test_enum_parameters(&self, param_enum_header_string_array: Option<&Vec>, param_enum_header_string: Option, param_enum_query_string_array: Option<&Vec>, param_enum_query_string: Option, param_enum_query_integer: Option, param_enum_query_double: Option, param_enum_form_string: Option, context: &C) -> Box> { // 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).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).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).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).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).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).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).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).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).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).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, param_file: Box, Error=Error> + Send>>, Error=Error> + Send>, context: &C) -> Box> { + fn upload_file(&self, param_pet_id: i64, param_additional_metadata: Option, param_file: Option, context: &C) -> Box> { 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, Error=Error> + Send>) -> Result { - - 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).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).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).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).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).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).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).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).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).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).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).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).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).get().0.clone())); - - Box::new(self.client_service.call(request) .map_err(|e| ApiError(format!("No response received: {}", e))) .and_then(|mut response| { diff --git a/samples/server/petstore/rust-server/src/lib.rs b/samples/server/petstore/rust-server/src/lib.rs index d6534990ac3..2e3dc8744bb 100644 --- a/samples/server/petstore/rust-server/src/lib.rs +++ b/samples/server/petstore/rust-server/src/lib.rs @@ -288,10 +288,10 @@ pub trait Api { fn test_client_model(&self, client: models::Client, context: &C) -> Box>; /// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트 - fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, integer: Option, int32: Option, int64: Option, float: Option, string: Option, binary: Box, Error=Error> + Send>>, Error=Error> + Send>, date: Option>, date_time: Option>, password: Option, callback: Option, context: &C) -> Box>; + fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, integer: Option, int32: Option, int64: Option, float: Option, string: Option, binary: Option, date: Option>, date_time: Option>, password: Option, callback: Option, context: &C) -> Box>; /// To test enum parameters - fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec>, enum_header_string: Option, enum_query_string_array: Option<&Vec>, enum_query_string: Option, enum_query_integer: Option, enum_query_double: Option, context: &C) -> Box>; + fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec>, enum_header_string: Option, enum_query_string_array: Option<&Vec>, enum_query_string: Option, enum_query_integer: Option, enum_query_double: Option, enum_form_string: Option, context: &C) -> Box>; /// test inline additionalProperties fn test_inline_additional_properties(&self, request_body: HashMap, context: &C) -> Box>; @@ -324,7 +324,7 @@ pub trait Api { fn update_pet_with_form(&self, pet_id: i64, name: Option, status: Option, context: &C) -> Box>; /// uploads an image - fn upload_file(&self, pet_id: i64, additional_metadata: Option, file: Box, Error=Error> + Send>>, Error=Error> + Send>, context: &C) -> Box>; + fn upload_file(&self, pet_id: i64, additional_metadata: Option, file: Option, context: &C) -> Box>; /// Delete purchase order by ID fn delete_order(&self, order_id: String, context: &C) -> Box>; @@ -389,10 +389,10 @@ pub trait ApiNoContext { fn test_client_model(&self, client: models::Client) -> Box>; /// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트 - fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, integer: Option, int32: Option, int64: Option, float: Option, string: Option, binary: Box, Error=Error> + Send>>, Error=Error> + Send>, date: Option>, date_time: Option>, password: Option, callback: Option) -> Box>; + fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, integer: Option, int32: Option, int64: Option, float: Option, string: Option, binary: Option, date: Option>, date_time: Option>, password: Option, callback: Option) -> Box>; /// To test enum parameters - fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec>, enum_header_string: Option, enum_query_string_array: Option<&Vec>, enum_query_string: Option, enum_query_integer: Option, enum_query_double: Option) -> Box>; + fn test_enum_parameters(&self, enum_header_string_array: Option<&Vec>, enum_header_string: Option, enum_query_string_array: Option<&Vec>, enum_query_string: Option, enum_query_integer: Option, enum_query_double: Option, enum_form_string: Option) -> Box>; /// test inline additionalProperties fn test_inline_additional_properties(&self, request_body: HashMap) -> Box>; @@ -425,7 +425,7 @@ pub trait ApiNoContext { fn update_pet_with_form(&self, pet_id: i64, name: Option, status: Option) -> Box>; /// uploads an image - fn upload_file(&self, pet_id: i64, additional_metadata: Option, file: Box, Error=Error> + Send>>, Error=Error> + Send>) -> Box>; + fn upload_file(&self, pet_id: i64, additional_metadata: Option, file: Option) -> Box>; /// Delete purchase order by ID fn delete_order(&self, order_id: String) -> Box>; @@ -515,13 +515,13 @@ impl<'a, T: Api, 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, int32: Option, int64: Option, float: Option, string: Option, binary: Box, Error=Error> + Send>>, Error=Error> + Send>, date: Option>, date_time: Option>, password: Option, callback: Option) -> Box> { - 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, int32: Option, int64: Option, float: Option, string: Option, binary: Option, date: Option>, date_time: Option>, password: Option, callback: Option) -> Box> { + 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>, enum_header_string: Option, enum_query_string_array: Option<&Vec>, enum_query_string: Option, enum_query_integer: Option, enum_query_double: Option) -> Box> { - 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>, enum_header_string: Option, enum_query_string_array: Option<&Vec>, enum_query_string: Option, enum_query_integer: Option, enum_query_double: Option, enum_form_string: Option) -> Box> { + 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> ApiNoContext for ContextWrapper<'a, T, C> { } /// uploads an image - fn upload_file(&self, pet_id: i64, additional_metadata: Option, file: Box, Error=Error> + Send>>, Error=Error> + Send>) -> Box> { + fn upload_file(&self, pet_id: i64, additional_metadata: Option, file: Option) -> Box> { self.api().upload_file(pet_id, additional_metadata, file, &self.context()) } diff --git a/samples/server/petstore/rust-server/src/mimetypes.rs b/samples/server/petstore/rust-server/src/mimetypes.rs index 9073c213ccb..afe949238ce 100644 --- a/samples/server/petstore/rust-server/src/mimetypes.rs +++ b/samples/server/petstore/rust-server/src/mimetypes.rs @@ -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(); diff --git a/samples/server/petstore/rust-server/src/models.rs b/samples/server/petstore/rust-server/src/models.rs index de88074b622..8e3d864a0a4 100644 --- a/samples/server/petstore/rust-server/src/models.rs +++ b/samples/server/petstore/rust-server/src/models.rs @@ -185,6 +185,11 @@ pub struct ArrayTest { #[serde(skip_serializing_if="Option::is_none")] pub array_array_of_model: Option>>, + // 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>, + } 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>, + // 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>>, + } 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, + #[serde(rename = "date")] pub date: chrono::DateTime, @@ -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>>, + // 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>>, + // 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, } } diff --git a/samples/server/petstore/rust-server/src/server/mod.rs b/samples/server/petstore/rust-server/src/server/mod.rs index a0142c41520..b035544d69f 100644 --- a/samples/server/petstore/rust-server/src/server/mod.rs +++ b/samples/server/petstore/rust-server/src/server/mod.rs @@ -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> { - 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::() { - 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::() { - 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::() { - 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::() { - 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::() { - 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::() { - 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::() { - 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::() { - 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, 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::>() { - 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::>() { - 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::() { - 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::() { - 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).get().0.to_string())); @@ -1044,12 +882,8 @@ where } )) - as Box> - }, - Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))), - } - }) - ) + }} + }) as Box> }, @@ -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).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> { - 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::() { - 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, 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> - }, - Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))), - } - }) - ) + }} + }) as Box> }, @@ -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::().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(()), - } - } -}