From a9961a062a46ffc62d3310c3278345adc6623716 Mon Sep 17 00:00:00 2001 From: Benjamin Gill Date: Mon, 23 Jul 2018 11:46:35 +0100 Subject: [PATCH] [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` --- .../codegen/languages/RustServerCodegen.java | 32 +- .../main/resources/rust-server/Cargo.mustache | 4 +- .../resources/rust-server/client-mod.mustache | 58 +-- .../example-server_server.mustache | 7 +- .../main/resources/rust-server/lib.mustache | 6 +- .../resources/rust-server/mimetypes.mustache | 4 +- .../resources/rust-server/server-mod.mustache | 122 +----- ...ith-fake-endpoints-models-for-testing.yaml | 91 ++--- .../server/petstore/rust-server/Cargo.toml | 4 +- .../petstore/rust-server/api/openapi.yaml | 46 +++ .../petstore/rust-server/examples/client.rs | 6 +- .../rust-server/examples/server_lib/server.rs | 16 +- .../petstore/rust-server/src/client/mod.rs | 194 ++------- .../server/petstore/rust-server/src/lib.rs | 22 +- .../petstore/rust-server/src/mimetypes.rs | 12 + .../server/petstore/rust-server/src/models.rs | 23 ++ .../petstore/rust-server/src/server/mod.rs | 379 ++---------------- 17 files changed, 238 insertions(+), 788 deletions(-) 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(()), - } - } -}