From 6963e5eeb0a441cdeea5d4750903a8ac11861a7f Mon Sep 17 00:00:00 2001 From: Richard Whitehouse Date: Sun, 4 Aug 2019 12:54:24 +0100 Subject: [PATCH] [Rust Server] Support multipart/form_data request bodies (#2846) [Rust Server] Support multipart/form_data - Support multipart/form_data in the Rust Server - Add a new test API to test the change. - Update the examples to match --- .../codegen/languages/RustServerCodegen.java | 7 +- .../main/resources/rust-server/Cargo.mustache | 4 +- .../resources/rust-server/client-mod.mustache | 145 ++++- .../main/resources/rust-server/lib.mustache | 1 + .../resources/rust-server/server-mod.mustache | 248 ++++++-- .../3_0/rust-server/multipart-v3.yaml | 51 ++ .../resources/3_0/rust-server/openapi-v3.yaml | 17 +- .../output/multipart-v3/.cargo/config | 18 + .../output/multipart-v3/.gitignore | 2 + .../multipart-v3/.openapi-generator-ignore | 23 + .../multipart-v3/.openapi-generator/VERSION | 1 + .../output/multipart-v3/Cargo.toml | 48 ++ .../rust-server/output/multipart-v3/README.md | 128 ++++ .../output/multipart-v3/api/openapi.yaml | 47 ++ .../multipart-v3/docs/MultipartRequest.md | 13 + .../docs/MultipartRequestObjectField.md | 11 + .../output/multipart-v3/docs/default_api.md | 46 ++ .../output/multipart-v3/examples/ca.pem | 17 + .../output/multipart-v3/examples/client.rs | 82 +++ .../multipart-v3/examples/server-chain.pem | 66 +++ .../multipart-v3/examples/server-key.pem | 28 + .../output/multipart-v3/examples/server.rs | 75 +++ .../multipart-v3/examples/server_lib/mod.rs | 37 ++ .../examples/server_lib/server.rs | 38 ++ .../output/multipart-v3/src/client/mod.rs | 417 +++++++++++++ .../output/multipart-v3/src/lib.rs | 101 ++++ .../output/multipart-v3/src/mimetypes.rs | 17 + .../output/multipart-v3/src/models.rs | 63 ++ .../output/multipart-v3/src/server/context.rs | 91 +++ .../output/multipart-v3/src/server/mod.rs | 277 +++++++++ .../rust-server/output/openapi-v3/Cargo.toml | 4 +- .../rust-server/output/openapi-v3/README.md | 2 + .../output/openapi-v3/api/openapi.yaml | 9 + .../output/openapi-v3/docs/default_api.md | 23 + .../output/openapi-v3/examples/client.rs | 7 + .../openapi-v3/examples/server_lib/server.rs | 8 + .../output/openapi-v3/src/client/mod.rs | 120 +++- .../rust-server/output/openapi-v3/src/lib.rs | 18 + .../output/openapi-v3/src/mimetypes.rs | 4 + .../output/openapi-v3/src/server/mod.rs | 151 ++--- .../Cargo.toml | 4 +- .../src/client/mod.rs | 191 +++--- .../src/lib.rs | 1 + .../src/server/mod.rs | 554 +++--------------- .../output/rust-server-test/Cargo.toml | 4 +- .../output/rust-server-test/src/client/mod.rs | 21 +- .../output/rust-server-test/src/lib.rs | 1 + .../output/rust-server-test/src/server/mod.rs | 72 +-- 48 files changed, 2421 insertions(+), 892 deletions(-) create mode 100644 modules/openapi-generator/src/test/resources/3_0/rust-server/multipart-v3.yaml create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/.cargo/config create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/.gitignore create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator-ignore create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/VERSION create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/README.md create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/api/openapi.yaml create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRequest.md create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRequestObjectField.md create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/docs/default_api.md create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/examples/ca.pem create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/examples/client.rs create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/examples/server-chain.pem create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/examples/server-key.pem create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/examples/server.rs create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/examples/server_lib/mod.rs create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/examples/server_lib/server.rs create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/src/client/mod.rs create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/src/mimetypes.rs create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/src/models.rs create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/src/server/context.rs create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/src/server/mod.rs 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 dfbb7eab35de..9f8e61ead37f 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 @@ -709,6 +709,9 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig { consumesPlainText = true; } else if (isMimetypeWwwFormUrlEncoded(mediaType)) { additionalProperties.put("usesUrlEncodedForm", true); + } else if (isMimetypeMultipartFormData(mediaType)) { + op.vendorExtensions.put("consumesMultipart", true); + additionalProperties.put("apiUsesMultipart", true); } } } @@ -724,8 +727,8 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig { } else { op.bodyParam.vendorExtensions.put("consumesJson", true); } - } + for (CodegenParameter param : op.bodyParams) { processParam(param, op); @@ -789,6 +792,8 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig { codegenParameter.isPrimitiveType = false; codegenParameter.isListContainer = false; codegenParameter.isString = false; + codegenParameter.isByteArray = ModelUtils.isByteArraySchema(original_schema); + // This is a model, so should only have an example if explicitly // defined. 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 bf43a520c29c..2bd053e1b699 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache @@ -25,8 +25,8 @@ swagger = "2" # lazy_static = "0.2" log = "0.3.0" -mime = "0.3.3" -multipart = {version = "0.13.3", optional = true} +mime = "0.2.6" +multipart = {version = "0.13.3"} native-tls = {version = "0.1.4", optional = true} openssl = {version = "0.9.14", optional = true} percent-encoding = {version = "1.0.0", optional = true} 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 aea03b15c6d4..f09a9c09a6e9 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,9 +6,16 @@ extern crate openssl; extern crate mime; extern crate chrono; extern crate url; -{{#usesUrlEncodedForm}}extern crate serde_urlencoded;{{/usesUrlEncodedForm}} +{{#usesUrlEncodedForm}} +extern crate serde_urlencoded; +{{/usesUrlEncodedForm}} +{{#apiUsesMultipart}} +extern crate multipart; +{{/apiUsesMultipart}} -{{#apiUsesUuid}}use uuid;{{/apiUsesUuid}} +{{#apiUsesUuid}} +use uuid; +{{/apiUsesUuid}} use hyper; use hyper::header::{Headers, ContentType}; use hyper::Uri; @@ -26,11 +33,16 @@ use std::sync::Arc; use std::str; use std::str::FromStr; use std::string::ToString; - +{{#apiUsesMultipart}} +use hyper::mime::Mime; +use std::io::Cursor; +use client::multipart::client::lazy::Multipart; +{{/apiUsesMultipart}} use mimetypes; - use serde_json; -{{#usesXml}}use serde_xml_rs;{{/usesXml}} +{{#usesXml}} +use serde_xml_rs; +{{/usesXml}} #[allow(unused_imports)] use std::collections::{HashMap, BTreeMap}; @@ -275,15 +287,93 @@ impl Api for Client where let mut request = hyper::Request::new(hyper::Method::{{#vendorExtensions}}{{{HttpMethod}}}{{/vendorExtensions}}, uri); -{{#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}} +{{#vendorExtensions}} + {{#consumesMultipart}} + let mut multipart = Multipart::new(); + + {{#vendorExtensions}} + {{#formParams}} + {{#-first}} + // For each parameter, encode as appropriate and add to the multipart body as a stream. + {{/-first}} + {{^isByteArray}} + {{#jsonSchema}} + + let {{{paramName}}}_str = match serde_json::to_string(¶m_{{{paramName}}}) { + Ok(str) => str, + Err(e) => return Box::new(futures::done(Err(ApiError(format!("Unable to parse {{{paramName}}} to string: {}", e))))), + }; + + let {{{paramName}}}_vec = {{{paramName}}}_str.as_bytes().to_vec(); + + let {{{paramName}}}_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); + + let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec); + + multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, None as Option<&str>, Some({{{paramName}}}_mime)); + + {{/jsonSchema}} + {{/isByteArray}} + {{#isByteArray}} + + let {{{paramName}}}_vec = param_{{{paramName}}}.to_vec(); + + let {{{paramName}}}_mime = match mime::Mime::from_str("application/octet-stream") { + Ok(mime) => mime, + Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to get mime type: {:?}", err))))), + }; + + let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec); + + let filename = None as Option<&str> ; + multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, filename, Some({{{paramName}}}_mime)); + + {{/isByteArray}} + {{#-last}} + {{/-last}} + {{/formParams}} + {{/vendorExtensions}} + + 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(); + fields.to_body().read_to_string(&mut body_string).unwrap(); + let boundary = fields.boundary(); + + let multipart_header = match 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.set_body(body_string.into_bytes()); + request.headers_mut().set(ContentType(multipart_header)); + + {{/consumesMultipart}} +{{/vendorExtensions}} +{{#vendorExtensions}} + {{^consumesMultipart}} + {{#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}}{{/vendorExtensions}}{{#bodyParam}}{{#-first}} + request.set_body(body.into_bytes()); + {{/-last}} + {{/formParams}} + {{/vendorExtensions}} + {{#bodyParam}} + {{#-first}} // Body parameter - {{/-first}} + {{/-first}} {{#vendorExtensions}} {{#consumesPlainText}} {{#isByteArray}} @@ -312,34 +402,51 @@ impl Api for Client where }); {{/required}} {{/vendorExtensions}} - {{/bodyParam}} + {{^required}} -{{#bodyParam}}{{^required}}if let Some(body) = body { - {{/required}} request.set_body(body); -{{^required}} }{{/required}} + if let Some(body) = body { +{{/required}} + request.set_body(body); +{{^required}} + } +{{/required}} request.headers_mut().set(ContentType(mimetypes::requests::{{#vendorExtensions}}{{{uppercase_operation_id}}}{{/vendorExtensions}}.clone())); -{{/bodyParam}} + {{/bodyParam}} + {{/consumesMultipart}} +{{/vendorExtensions}} + request.headers_mut().set(XSpanId((context as &Has).get().0.clone())); -{{#authMethods}}{{#isBasic}} if let Some(auth_data) = (context as &Has>).get().as_ref() { +{{#authMethods}} + {{#isBasic}} + if let Some(auth_data) = (context as &Has>).get().as_ref() { if let AuthData::Basic(ref basic_header) = *auth_data { request.headers_mut().set(hyper::header::Authorization( basic_header.clone(), )) } - }{{/isBasic}}{{#isApiKey}}{{#isKeyInHeader}} header! { ({{#vendorExtensions}}{{x-apiKeyName}}{{/vendorExtensions}}, "{{keyParamName}}") => [String] } + } + {{/isBasic}} + {{#isApiKey}} + {{#isKeyInHeader}} + header! { ({{#vendorExtensions}}{{x-apiKeyName}}{{/vendorExtensions}}, "{{keyParamName}}") => [String] } if let Some(auth_data) = (context as &Has>).get().as_ref() { if let AuthData::ApiKey(ref api_key) = *auth_data { request.headers_mut().set({{#vendorExtensions}}{{x-apiKeyName}}{{/vendorExtensions}}(api_key.to_string())); } - }{{/isKeyInHeader}}{{/isApiKey}}{{/authMethods}}{{#headerParams}}{{#-first}} + } + {{/isKeyInHeader}} + {{/isApiKey}} +{{/authMethods}} +{{#headerParams}} +{{#-first}} // Header parameters {{/-first}}{{^isMapContainer}} header! { (Request{{vendorExtensions.typeName}}, "{{{baseName}}}") => {{#isListContainer}}({{{baseType}}})*{{/isListContainer}}{{^isListContainer}}[{{{dataType}}}]{{/isListContainer}} } {{#required}} request.headers_mut().set(Request{{vendorExtensions.typeName}}(param_{{{paramName}}}{{#isListContainer}}.clone(){{/isListContainer}})); {{/required}}{{^required}} param_{{{paramName}}}.map(|header| request.headers_mut().set(Request{{vendorExtensions.typeName}}(header{{#isListContainer}}.clone(){{/isListContainer}}))); {{/required}}{{/isMapContainer}}{{#isMapContainer}} let param_{{{paramName}}}: Option<{{{dataType}}}> = None; -{{/isMapContainer}}{{/headerParams}} - +{{/isMapContainer}} +{{/headerParams}} Box::new(self.client_service.call(request) .map_err(|e| ApiError(format!("No response received: {}", e))) .and_then(|mut response| { 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 c163280799e0..b1c055176ff3 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/lib.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/lib.mustache @@ -11,6 +11,7 @@ extern crate chrono; extern crate lazy_static; #[macro_use] extern crate log; +extern crate mime; // Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module. #[cfg(any(feature = "client", feature = "server"))] 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 2aea9c00ae8f..2c6ea131ba36 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 @@ -5,12 +5,16 @@ extern crate native_tls; extern crate hyper_tls; extern crate openssl; extern crate mime; -{{^apiUsesUuid}}extern crate uuid;{{/apiUsesUuid}} extern crate chrono; extern crate percent_encoding; extern crate url; +{{^apiUsesUuid}} +extern crate uuid; +{{/apiUsesUuid}} +{{#apiUsesMultipart}} +extern crate multipart; +{{/apiUsesMultipart}} -{{#apiUsesUuid}}use uuid;{{/apiUsesUuid}} use std::sync::Arc; use std::marker::PhantomData; use futures::{Future, future, Stream, stream}; @@ -19,9 +23,18 @@ use hyper::{Request, Response, Error, StatusCode}; use hyper::header::{Headers, ContentType}; use self::url::form_urlencoded; use mimetypes; - +{{#apiUsesMultipart}} +use self::multipart::server::Multipart; +use self::multipart::server::save::SaveResult; +use std::fs; +{{/apiUsesMultipart}} use serde_json; -{{#usesXml}}use serde_xml_rs;{{/usesXml}} +{{#usesXml}} +use serde_xml_rs; +{{/usesXml}} +{{#apiUsesUuid}} +use uuid; +{{/apiUsesUuid}} #[allow(unused_imports)] use std::collections::{HashMap, BTreeMap}; @@ -165,8 +178,14 @@ where {{/authMethods}} } {{/hasAuthMethods}} - -{{#vendorExtensions}}{{#hasPathParams}} +{{#vendorExtensions}} + {{#consumesMultipart}} + 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"))), + }; + {{/consumesMultipart}} + {{#hasPathParams}} // Path parameters let path = uri.path().to_string(); let path_params = @@ -175,7 +194,8 @@ where .unwrap_or_else(|| panic!("Path {} matched RE {{{PATH_ID}}} in set but failed match against \"{}\"", path, paths::REGEX_{{{PATH_ID}}}.as_str()) ); -{{/hasPathParams}}{{/vendorExtensions}} + {{/hasPathParams}} +{{/vendorExtensions}} {{#pathParams}} let param_{{{paramName}}} = match percent_encoding::percent_decode(path_params["{{{baseName}}}"].as_bytes()).decode_utf8() { Ok(param_{{{paramName}}}) => match param_{{{paramName}}}.parse::<{{{dataType}}}>() { @@ -185,36 +205,39 @@ where Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["{{{baseName}}}"])))) }; {{/pathParams}} -{{#headerParams}}{{#-first}} +{{#headerParams}} + {{#-first}} // Header parameters -{{/-first}} + {{/-first}} header! { (Request{{vendorExtensions.typeName}}, "{{{baseName}}}") => {{#isListContainer}}({{{baseType}}})*{{/isListContainer}}{{^isListContainer}}[{{{dataType}}}]{{/isListContainer}} } -{{#required}} + {{#required}} let param_{{{paramName}}} = match headers.get::() { Some(param_{{{paramName}}}) => param_{{{paramName}}}.0.clone(), None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing or invalid required header {{{baseName}}}"))), }; -{{/required}} -{{^required}} + {{/required}} + {{^required}} let param_{{{paramName}}} = headers.get::().map(|header| header.0.clone()); -{{/required}}{{/headerParams}} - -{{#queryParams}}{{#-first}} + {{/required}} +{{/headerParams}} +{{#queryParams}} + {{#-first}} // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect::>(); -{{/-first}} + {{/-first}} let param_{{{paramName}}} = query_params.iter().filter(|e| e.0 == "{{{baseName}}}").map(|e| e.1.to_owned()) -{{#isListContainer}} + {{#isListContainer}} .filter_map(|param_{{{paramName}}}| param_{{{paramName}}}.parse::<{{{baseType}}}>().ok()) .collect::>(); -{{^required}} + {{^required}} let param_{{{paramName}}} = if !param_{{{paramName}}}.is_empty() { Some(param_{{{paramName}}}) } else { None }; -{{/required}} -{{/isListContainer}}{{^isListContainer}} + {{/required}} +{{/isListContainer}} +{{^isListContainer}} .nth(0); {{#required}} let param_{{{paramName}}} = match param_{{{paramName}}} { @@ -229,8 +252,10 @@ where {{/required}} {{/isListContainer}} {{/queryParams}} - -{{#bodyParams}}{{#-first}} +{{#vendorExtensions}} + {{^consumesMultipart}} + {{#bodyParams}} + {{#-first}} // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -238,53 +263,147 @@ where .then(move |result| -> Box> { match result { Ok(body) => { -{{#vendorExtensions}}{{^consumesPlainText}} + {{#vendorExtensions}} + {{^consumesPlainText}} let mut unused_elements = Vec::new(); -{{/consumesPlainText}} + {{/consumesPlainText}} let param_{{{paramName}}}: Option<{{{dataType}}}> = if !body.is_empty() { -{{#consumesXml}} + {{#consumesXml}} let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); -{{/consumesXml}}{{#consumesJson}} + {{/consumesXml}} + {{#consumesJson}} let deserializer = &mut serde_json::Deserializer::from_slice(&*body); -{{/consumesJson}}{{^consumesPlainText}} + {{/consumesJson}} + {{^consumesPlainText}} match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) { Ok(param_{{{paramName}}}) => param_{{{paramName}}}, -{{#required}} + {{#required}} Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter {{{baseName}}} - doesn't match schema: {}", e)))), -{{/required}}{{^required}} + {{/required}} + {{^required}} Err(_) => None, -{{/required}} + {{/required}} } -{{/consumesPlainText}}{{#consumesPlainText}} -{{#isByteArray}} + {{/consumesPlainText}} + {{#consumesPlainText}} + {{#isByteArray}} Some(swagger::ByteArray(body.to_vec())) -{{/isByteArray}} -{{#isString}} + {{/isByteArray}} + {{#isString}} Some(String::from_utf8(body.to_vec()).unwrap()) -{{/isString}} -{{/consumesPlainText}}{{/vendorExtensions}} + {{/isString}} + {{/consumesPlainText}} + {{/vendorExtensions}} } else { None }; -{{#required}} + {{#required}} let param_{{{paramName}}} = match param_{{{paramName}}} { Some(param_{{{paramName}}}) => param_{{{paramName}}}, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter {{{baseName}}}"))), }; -{{/required}} -{{/-first}}{{/bodyParams}} -{{^bodyParams}}{{#vendorExtensions}} + {{/required}} + {{/-first}} + {{/bodyParams}} + {{/consumesMultipart}} + {{#consumesMultipart}} + {{^bodyParams}} + {{#vendorExtensions}} + // Form Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + Box::new(body.concat2() + .then(move |result| -> Box> { + match result { + Ok(body) => { + // Read Form Parameters from 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}}{{/-first}} + {{#isByteArray}} + let file_{{{paramName}}} = entries.files.remove("{{{paramName}}}"); + {{#required}} + let param_{{{paramName}}} = match file_{{{paramName}}} { + Some(file) => { + let path = &file[0].path; + let {{{paramName}}}_str = fs::read_to_string(path).unwrap(); + swagger::ByteArray({{{paramName}}}_str.as_bytes().to_vec()) + } + None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Missing required form parameter {{{paramName}}}")))), + }; + {{/required}} + {{^required}} + let param_{{{paramName}}} = match file_{{{paramName}}} { + Some(file) => { + let path = &file[0].path; + let {{{paramName}}}_str = fs::read_to_string(path).unwrap(); + Some(swagger::ByteArray({{{paramName}}}_str.as_bytes().to_vec())) + } + None => None, + }; + {{/required}} + {{/isByteArray}} + {{^isByteArray}}{{#jsonSchema}} + let file_{{{paramName}}} = entries.files.remove("{{{paramName}}}"); + {{#required}} + let param_{{{paramName}}} = match file_{{{paramName}}} { + Some(file) => { + let path = &file[0].path; + let {{{paramName}}}_str = fs::read_to_string(path).expect("Reading saved String should never fail"); + let {{{paramName}}}_model: {{{dataType}}} = match serde_json::from_str(&{{{paramName}}}_str) { + Ok(model) => model, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("{{{paramName}}} data does not match API definition: {}", e)))) + } + }; + {{{paramName}}}_model + } + None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Missing required form parameter {{{paramName}}}")))), + }; + {{/required}} + {{^required}} + let param_{{{paramName}}} = match file_{{{paramName}}} { + Some(file) => { + let path = &file[0].path; + let {{{paramName}}}_str = fs::read_to_string(path).unwrap(); + let {{{paramName}}}_model: {{{dataType}}} = serde_json::from_str(&{{{paramName}}}_str).expect("Impossible to fail to serialise"); + Some({{{paramName}}}_model) + } + None => None, + }; + {{/required}} + {{/jsonSchema}}{{/isByteArray}} + {{/formParams}} + {{/vendorExtensions}} + {{/bodyParams}} + {{/consumesMultipart}} + {{^consumesMultipart}} + {{^bodyParams}} + {{#vendorExtensions}} Box::new({ {{ -{{#formParams}}{{#-first}} + {{#formParams}} + {{#-first}} // Form parameters -{{/-first}} + {{/-first}} let param_{{{paramName}}} = {{^isContainer}}{{#vendorExtensions}}{{{example}}};{{/vendorExtensions}}{{/isContainer}}{{#isListContainer}}{{#required}}Vec::new();{{/required}}{{^required}}None;{{/required}}{{/isListContainer}}{{#isMapContainer}}None;{{/isMapContainer}} -{{/formParams}} -{{/vendorExtensions}}{{/bodyParams}} + {{/formParams}} + {{/vendorExtensions}} + {{/bodyParams}} + {{/consumesMultipart}} +{{/vendorExtensions}} 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(); @@ -356,19 +475,36 @@ where future::ok(response) } )) -{{^bodyParams}}{{#vendorExtensions}} +{{#vendorExtensions}} + {{^consumesMultipart}} + {{^bodyParams}} }} }) as Box> -{{/vendorExtensions}}{{/bodyParams}} -{{#bodyParams}}{{#-first}} + {{/bodyParams}} + {{/consumesMultipart}} +{{/vendorExtensions}} +{{#bodyParams}} + {{#-first}} }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter {{{baseName}}}: {}", e)))), } }) ) as Box> -{{/-first}}{{/bodyParams}} + {{/-first}} +{{/bodyParams}} +{{#vendorExtensions}} + {{#consumesMultipart}} + {{^bodyParams}} + as Box> + }, + Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))), + } + }) + ) + {{/bodyParams}} + {{/consumesMultipart}} +{{/vendorExtensions}} }, - {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} _ => Box::new(future::ok(Response::new().with_status(StatusCode::NotFound))) as Box>, } @@ -385,6 +521,20 @@ impl Clone for Service } } +{{#apiUsesMultipart}} +/// 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_() == hyper::mime::MULTIPART && mime.subtype() == hyper::mime::FORM_DATA { + mime.get_param(hyper::mime::BOUNDARY).map(|x| x.as_str()) + } else { + None + } + }) +} +{{/apiUsesMultipart}} + /// Request parser for `Api`. pub struct ApiRequestParser; impl RequestParser for ApiRequestParser { diff --git a/modules/openapi-generator/src/test/resources/3_0/rust-server/multipart-v3.yaml b/modules/openapi-generator/src/test/resources/3_0/rust-server/multipart-v3.yaml new file mode 100644 index 000000000000..70c4e5d46020 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/rust-server/multipart-v3.yaml @@ -0,0 +1,51 @@ +# Test the multipart function of the OpenAPI specification +# +# Specifically, these tests include +# - multipart/form data including +# - binary data +# - string data +# - objects + +openapi: 3.0.1 +info: + title: Multipart OpenAPI V3 Rust Server Test + description: API under test + version: 1.0.7 +paths: + /multipart_request: + post: + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/multipart_request' + responses: + '201': + description: 'OK' +components: + schemas: + multipart_request: + type: object + required: + - string_field + - binary_field + properties: + string_field: + type: string + optional_string_field: + type: string + object_field: + type: object + required: + - field_a + properties: + field_a: + type: string + field_b: + type: array + items: + type: string + binary_field: + type: string + format: byte diff --git a/modules/openapi-generator/src/test/resources/3_0/rust-server/openapi-v3.yaml b/modules/openapi-generator/src/test/resources/3_0/rust-server/openapi-v3.yaml index 677a439f0412..cef3e746ba0c 100644 --- a/modules/openapi-generator/src/test/resources/3_0/rust-server/openapi-v3.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/rust-server/openapi-v3.yaml @@ -1,5 +1,7 @@ -# Test the mainline function of the XML part of the OpenAPI specification, -# as found here : https://swagger.io/docs/specification/data-models/representing-xml/ +# Test the mainline function of OpenAPI v3 specification. +# +# This includes the XML part of the OpenAPI specification, as found at +# https://swagger.io/docs/specification/data-models/representing-xml/ # # Specifically, these tests are intended to include: # - namespaces @@ -9,6 +11,8 @@ # - wrapping and renaming to and from camelCase and snake_case # - objects # - renaming to and from camelCase and snake_case +# - UUIDs +# - Octet Streams openapi: 3.0.1 info: @@ -76,6 +80,15 @@ paths: description: 'OK' '400': description: Bad Request + /uuid: + get: + responses: + 200: + description: Duplicate Response long text. One. + content: + application/json: + schema: + $ref: "#/components/schemas/UuidObject" /required_octet_stream: put: requestBody: diff --git a/samples/server/petstore/rust-server/output/multipart-v3/.cargo/config b/samples/server/petstore/rust-server/output/multipart-v3/.cargo/config new file mode 100644 index 000000000000..b8acc9c00c8c --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/.cargo/config @@ -0,0 +1,18 @@ +[build] +rustflags = [ + "-W", "missing_docs", # detects missing documentation for public members + + "-W", "trivial_casts", # detects trivial casts which could be removed + + "-W", "trivial_numeric_casts", # detects trivial casts of numeric types which could be removed + + "-W", "unsafe_code", # usage of `unsafe` code + + "-W", "unused_qualifications", # detects unnecessarily qualified names + + "-W", "unused_extern_crates", # extern crates that are never used + + "-W", "unused_import_braces", # unnecessary braces around an imported item + + "-D", "warnings", # all warnings should be denied +] diff --git a/samples/server/petstore/rust-server/output/multipart-v3/.gitignore b/samples/server/petstore/rust-server/output/multipart-v3/.gitignore new file mode 100644 index 000000000000..a9d37c560c6a --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator-ignore b/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/VERSION b/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/VERSION new file mode 100644 index 000000000000..83a328a9227e --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/VERSION @@ -0,0 +1 @@ +4.1.0-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml b/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml new file mode 100644 index 000000000000..8f4afb08ae79 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "multipart-v3" +version = "1.0.7" +authors = [] +description = "API under test" +license = "Unlicense" + +[features] +default = ["client", "server"] +client = ["serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"] +server = ["serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"] + +[dependencies] +# Required by example server. +# +chrono = { version = "0.4", features = ["serde"] } +futures = "0.1" +hyper = {version = "0.11", optional = true} +hyper-tls = {version = "0.1.2", optional = true} +swagger = "2" + +# Not required by example server. +# +lazy_static = "0.2" +log = "0.3.0" +mime = "0.2.6" +multipart = {version = "0.13.3"} +native-tls = {version = "0.1.4", optional = true} +openssl = {version = "0.9.14", optional = true} +percent-encoding = {version = "1.0.0", optional = true} +regex = {version = "0.2", optional = true} +serde = "1.0" +serde_derive = "1.0" +serde_ignored = {version = "0.0.4", optional = true} +serde_json = {version = "1.0", optional = true} +serde_urlencoded = {version = "0.5.1", optional = true} +tokio-core = {version = "0.1.6", optional = true} +tokio-proto = {version = "0.1.1", optional = true} +tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]} +url = {version = "1.5", optional = true} +uuid = {version = "0.5", optional = true, features = ["serde", "v4"]} +# ToDo: this should be updated to point at the official crate once +# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream + + +[dev-dependencies] +clap = "2.25" +error-chain = "0.12" diff --git a/samples/server/petstore/rust-server/output/multipart-v3/README.md b/samples/server/petstore/rust-server/output/multipart-v3/README.md new file mode 100644 index 000000000000..d9a4abd69a5e --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/README.md @@ -0,0 +1,128 @@ +# Rust API for multipart-v3 + +API under test + +## Overview +This client/server was generated by the [openapi-generator] +(https://openapi-generator.tech) project. +By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. +- + +To see how to make this your own, look here: + +[README]((https://openapi-generator.tech)) + +- API version: 1.0.7 + +This autogenerated project defines an API crate `multipart-v3` which contains: +* An `Api` trait defining the API in Rust. +* Data types representing the underlying data model. +* A `Client` type which implements `Api` and issues HTTP requests for each operation. +* A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. + +It also contains an example server and client which make use of `multipart-v3`: +* The example server starts up a web server using the `multipart-v3` router, + and supplies a trivial implementation of `Api` which returns failure for every operation. +* The example client provides a CLI which lets you invoke any single operation on the + `multipart-v3` client by passing appropriate arguments on the command line. + +You can use the example server and client as a basis for your own code. +See below for [more detail on implementing a server](#writing-a-server). + + +## Examples + +Run examples with: + +``` +cargo run --example +``` + +To pass in arguments to the examples, put them after `--`, for example: + +``` +cargo run --example client -- --help +``` + +### Running the server +To run the server, follow these simple steps: + +``` +cargo run --example server +``` + +### Running a client +To run a client, follow one of the following simple steps: + +``` +cargo run --example client MultipartRequestPost +``` + +### HTTPS +The examples can be run in HTTPS mode by passing in the flag `--https`, for example: + +``` +cargo run --example server -- --https +``` + +This will use the keys/certificates from the examples directory. Note that the server chain is signed with +`CN=localhost`. + + +## Writing a server + +The server example is designed to form the basis for implementing your own server. Simply follow these steps. + +* Set up a new Rust project, e.g., with `cargo init --bin`. +* Insert `multipart-v3` into the `members` array under [workspace] in the root `Cargo.toml`, e.g., `members = [ "multipart-v3" ]`. +* Add `multipart-v3 = {version = "1.0.7", path = "multipart-v3"}` under `[dependencies]` in the root `Cargo.toml`. +* Copy the `[dependencies]` and `[dev-dependencies]` from `multipart-v3/Cargo.toml` into the root `Cargo.toml`'s `[dependencies]` section. + * Copy all of the `[dev-dependencies]`, but only the `[dependencies]` that are required by the example server. These should be clearly indicated by comments. + * Remove `"optional = true"` from each of these lines if present. + +Each autogenerated API will contain an implementation stub and main entry point, which should be copied into your project the first time: +``` +cp multipart-v3/examples/server.rs src/main.rs +cp multipart-v3/examples/server_lib/mod.rs src/lib.rs +cp multipart-v3/examples/server_lib/server.rs src/server.rs +``` + +Now + +* From `src/main.rs`, remove the `mod server_lib;` line, and uncomment and fill in the `extern crate` line with the name of this server crate. +* Move the block of imports "required by the service library" from `src/main.rs` to `src/lib.rs` and uncomment. +* Change the `let server = server::Server {};` line to `let server = SERVICE_NAME::server().unwrap();` where `SERVICE_NAME` is the name of the server crate. +* Run `cargo build` to check it builds. +* Run `cargo fmt` to reformat the code. +* Commit the result before making any further changes (lest format changes get confused with your own updates). + +Now replace the implementations in `src/server.rs` with your own code as required. + +## Updating your server to track API changes + +Later, if the API changes, you can copy new sections from the autogenerated API stub into your implementation. +Alternatively, implement the now-missing methods based on the compiler's error messages. + +## Documentation for API Endpoints + +All URIs are relative to *http://localhost* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[****](docs/default_api.md#) | **POST** /multipart_request | + + +## Documentation For Models + + - [MultipartRequest](docs/MultipartRequest.md) + - [MultipartRequestObjectField](docs/MultipartRequestObjectField.md) + + +## Documentation For Authorization + Endpoints do not require authorization. + + +## Author + + + diff --git a/samples/server/petstore/rust-server/output/multipart-v3/api/openapi.yaml b/samples/server/petstore/rust-server/output/multipart-v3/api/openapi.yaml new file mode 100644 index 000000000000..654962a5eba2 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/api/openapi.yaml @@ -0,0 +1,47 @@ +openapi: 3.0.1 +info: + description: API under test + title: Multipart OpenAPI V3 Rust Server Test + version: 1.0.7 +servers: +- url: / +paths: + /multipart_request: + post: + requestBody: + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/multipart_request' + required: true + responses: + 201: + description: OK +components: + schemas: + multipart_request: + properties: + string_field: + type: string + optional_string_field: + type: string + object_field: + $ref: '#/components/schemas/multipart_request_object_field' + binary_field: + format: byte + type: string + required: + - binary_field + - string_field + type: object + multipart_request_object_field: + properties: + field_a: + type: string + field_b: + items: + type: string + type: array + required: + - field_a + diff --git a/samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRequest.md b/samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRequest.md new file mode 100644 index 000000000000..dc52f53832a0 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRequest.md @@ -0,0 +1,13 @@ +# MultipartRequest + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**string_field** | **String** | | +**optional_string_field** | **String** | | [optional] [default to None] +**object_field** | [***models::MultipartRequestObjectField**](multipart_request_object_field.md) | | [optional] [default to None] +**binary_field** | [***swagger::ByteArray**](ByteArray.md) | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRequestObjectField.md b/samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRequestObjectField.md new file mode 100644 index 000000000000..bfbf176ad75e --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRequestObjectField.md @@ -0,0 +1,11 @@ +# MultipartRequestObjectField + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**field_a** | **String** | | +**field_b** | **Vec** | | [optional] [default to None] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/multipart-v3/docs/default_api.md b/samples/server/petstore/rust-server/output/multipart-v3/docs/default_api.md new file mode 100644 index 000000000000..b88fe084c35a --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/docs/default_api.md @@ -0,0 +1,46 @@ +# default_api + +All URIs are relative to *http://localhost* + +Method | HTTP request | Description +------------- | ------------- | ------------- +****](default_api.md#) | **POST** /multipart_request | + + +# **** +> (string_field, binary_field, optional) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **string_field** | **String**| | + **binary_field** | **swagger::ByteArray**| | + **optional** | **map[string]interface{}** | optional parameters | nil if no parameters + +### Optional Parameters +Optional parameters are passed through a map[string]interface{}. + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **string_field** | **String**| | + **binary_field** | **swagger::ByteArray**| | + **optional_string_field** | **String**| | + **object_field** | [**multipart_request_object_field**](multipart_request_object_field.md)| | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: multipart/form-data + - **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/ca.pem b/samples/server/petstore/rust-server/output/multipart-v3/examples/ca.pem new file mode 100644 index 000000000000..d2317fb5db7d --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/ca.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICtjCCAZ4CCQDpKecRERZ0xDANBgkqhkiG9w0BAQsFADAdMQswCQYDVQQGEwJV +UzEOMAwGA1UEAxMFTXkgQ0EwHhcNMTcwNTIzMTYwMDIzWhcNMTcwNjIyMTYwMDIz +WjAdMQswCQYDVQQGEwJVUzEOMAwGA1UEAxMFTXkgQ0EwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCt66py3x7sCSASRF2D05L5wkNDxAUjQKYx23W8Gbwv +GMGykk89BIdU5LX1JB1cKiUOkoIxfwAYuWc2V/wzTvVV7+11besnk3uX1c9KiqUF +LIX7kn/z5hzS4aelhKvH+MJlSZCSlp1ytpZbwo5GB5Pi2SGH56jDBiBoDRNBVdWL +z4wH7TdrQjqWwNxIZumD5OGMtcfJyuX08iPiEOaslOeoMqzObhvjc9aUgjVjhqyA +FkJGTXsi0oaD7oml+NE+mTNfEeZvEJQpLSjBY0OvQHzuHkyGBShBnfu/9x7/NRwd +WaqsLiF7/re9KDGYdJwP7Cu6uxYfKAyWarp6h2mG/GIdAgMBAAEwDQYJKoZIhvcN +AQELBQADggEBAGIl/VVIafeq/AJOQ9r7TzzB2ABJYr7NZa6bTu5O1jSp1Fonac15 +SZ8gvRxODgH22ZYSqghPG4xzq4J3hkytlQqm57ZEt2I2M3OqIp17Ndcc1xDYzpLl +tA0FrVn6crQTM8vQkTDtGesaCWX+7Fir5dK7HnYWzfpSmsOpST07PfbNisEXKOxG +Dj4lBL1OnhTjsJeymVS1pFvkKkrcEJO+IxFiHL3CDsWjcXB0Z+E1zBtPoYyYsNsO +rBrjUxcZewF4xqWZhpW90Mt61fY2nRgU0uUwHcvDQUqvmzKcsqYa4mPKzfBI5mxo +01Ta96cDD6pS5Y1hOflZ0g84f2g/7xBLLDA= +-----END CERTIFICATE----- diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/client.rs b/samples/server/petstore/rust-server/output/multipart-v3/examples/client.rs new file mode 100644 index 000000000000..0421908af77e --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/client.rs @@ -0,0 +1,82 @@ +#![allow(missing_docs, unused_variables, trivial_casts)] + +extern crate multipart_v3; +#[allow(unused_extern_crates)] +extern crate futures; +#[allow(unused_extern_crates)] +#[macro_use] +extern crate swagger; +#[allow(unused_extern_crates)] +extern crate uuid; +extern crate clap; +extern crate tokio_core; + +use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData}; + +#[allow(unused_imports)] +use futures::{Future, future, Stream, stream}; +use tokio_core::reactor; +#[allow(unused_imports)] +use multipart_v3::{ApiNoContext, ContextWrapperExt, + ApiError, + MultipartRequestPostResponse + }; +use clap::{App, Arg}; + +fn main() { + let matches = App::new("client") + .arg(Arg::with_name("operation") + .help("Sets the operation to run") + .possible_values(&[ + "MultipartRequestPost", +]) + .required(true) + .index(1)) + .arg(Arg::with_name("https") + .long("https") + .help("Whether to use HTTPS or not")) + .arg(Arg::with_name("host") + .long("host") + .takes_value(true) + .default_value("localhost") + .help("Hostname to contact")) + .arg(Arg::with_name("port") + .long("port") + .takes_value(true) + .default_value("80") + .help("Port to contact")) + .get_matches(); + + let mut core = reactor::Core::new().unwrap(); + let is_https = matches.is_present("https"); + let base_url = format!("{}://{}:{}", + if is_https { "https" } else { "http" }, + matches.value_of("host").unwrap(), + matches.value_of("port").unwrap()); + let client = if matches.is_present("https") { + // Using Simple HTTPS + multipart_v3::Client::try_new_https(core.handle(), &base_url, "examples/ca.pem") + .expect("Failed to create HTTPS client") + } else { + // Using HTTP + multipart_v3::Client::try_new_http(core.handle(), &base_url) + .expect("Failed to create HTTP client") + }; + + let context: make_context_ty!(ContextBuilder, EmptyContext, Option, XSpanIdString) = + make_context!(ContextBuilder, EmptyContext, None as Option, XSpanIdString(self::uuid::Uuid::new_v4().to_string())); + let client = client.with_context(context); + + match matches.value_of("operation") { + + Some("MultipartRequestPost") => { + let result = core.run(client.multipart_request_post("string_field_example".to_string(), swagger::ByteArray(Vec::from("BYTE_ARRAY_DATA_HERE")), Some("optional_string_field_example".to_string()), None)); + println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has).get().clone()); + }, + + _ => { + panic!("Invalid operation provided") + } + } +} + diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/server-chain.pem b/samples/server/petstore/rust-server/output/multipart-v3/examples/server-chain.pem new file mode 100644 index 000000000000..47d7e2014046 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/server-chain.pem @@ -0,0 +1,66 @@ +Certificate: + Data: + Version: 1 (0x0) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, CN=My CA + Validity + Not Before: May 23 16:00:23 2017 GMT + Not After : Apr 29 16:00:23 2117 GMT + Subject: CN=localhost, C=US + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c9:d4:43:60:50:fc:d6:0f:38:4d:5d:5e:aa:7c: + c0:5e:a9:ec:d9:93:78:d3:93:72:28:41:f5:08:a5: + ea:ac:67:07:d7:1f:f7:7d:74:69:7e:46:89:20:4b: + 7a:2d:9b:02:08:e7:6f:0f:1d:0c:0f:c7:60:69:19: + 4b:df:7e:ca:75:94:0b:49:71:e3:6d:f2:e8:79:fd: + ed:0a:94:67:55:f3:ca:6b:61:ba:58:b7:2e:dd:7b: + ca:b9:02:9f:24:36:ac:26:8f:04:8f:81:c8:35:10: + f4:aa:33:b2:24:16:f8:f7:1e:ea:f7:16:fe:fa:34: + c3:dd:bb:2c:ba:7a:df:4d:e2:da:1e:e5:d2:28:44: + 6e:c8:96:e0:fd:09:0c:14:0c:31:dc:e0:ca:c1:a7: + 9b:bf:16:8c:f7:36:3f:1b:2e:dd:90:eb:45:78:51: + bf:59:22:1e:c6:8c:0a:69:88:e5:03:5e:73:b7:fc: + 93:7f:1b:46:1b:97:68:c5:c0:8b:35:1f:bb:1e:67: + 7f:55:b7:3b:55:3f:ea:f2:ca:db:cc:52:cd:16:89: + db:15:47:bd:f2:cd:6c:7a:d7:b4:1a:ac:c8:15:6c: + 6a:fb:77:c4:e9:f2:30:e0:14:24:66:65:6f:2a:e5: + 2d:cc:f6:81:ae:57:c8:d1:9b:38:90:dc:60:93:02: + 5e:cb + Exponent: 65537 (0x10001) + Signature Algorithm: sha256WithRSAEncryption + 1c:7c:39:e8:3d:49:b2:09:1e:68:5a:2f:74:18:f4:63:b5:8c: + f6:e6:a1:e3:4d:95:90:99:ef:32:5c:34:40:e8:55:13:0e:e0: + 1c:be:cd:ab:3f:64:38:99:5e:2b:c1:81:53:a0:18:a8:f6:ee: + 6a:33:73:6c:9a:73:9d:86:08:5d:c7:11:38:46:4c:cd:a0:47: + 37:8f:fe:a6:50:a9:02:21:99:42:86:5e:47:fe:65:56:60:1d: + 16:53:86:bd:e4:63:c5:69:cf:fa:30:51:ab:a1:c3:50:53:cc: + 66:1c:4c:ff:3f:2a:39:4d:a2:8f:9d:d1:a7:8b:22:e4:78:69: + 24:06:83:4d:cc:0a:c0:87:69:9b:bc:80:a9:d2:b7:a5:23:84: + 7e:a2:32:26:7c:78:0e:bd:db:cd:3b:69:18:33:b8:44:ef:96: + b4:99:86:ee:06:bd:51:1c:c7:a1:a4:0c:c4:4c:51:a0:df:ac: + 14:07:88:8e:d7:39:45:fe:52:e0:a3:4c:db:5d:7a:ab:4d:e4: + ca:06:e8:bd:74:6f:46:e7:93:4a:4f:1b:67:e7:a5:9f:ef:9c: + 02:49:d1:f2:d5:e9:53:ee:09:21:ac:08:c8:15:f7:af:35:b9: + 4f:11:0f:43:ae:46:8e:fd:5b:8d:a3:4e:a7:2c:b7:25:ed:e4: + e5:94:1d:e3 +-----BEGIN CERTIFICATE----- +MIICtTCCAZ0CAhAAMA0GCSqGSIb3DQEBCwUAMB0xCzAJBgNVBAYTAlVTMQ4wDAYD +VQQDEwVNeSBDQTAgFw0xNzA1MjMxNjAwMjNaGA8yMTE3MDQyOTE2MDAyM1owITES +MBAGA1UEAxMJbG9jYWxob3N0MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAMnUQ2BQ/NYPOE1dXqp8wF6p7NmTeNOTcihB9Qil6qxn +B9cf9310aX5GiSBLei2bAgjnbw8dDA/HYGkZS99+ynWUC0lx423y6Hn97QqUZ1Xz +ymthuli3Lt17yrkCnyQ2rCaPBI+ByDUQ9KozsiQW+Pce6vcW/vo0w927LLp6303i +2h7l0ihEbsiW4P0JDBQMMdzgysGnm78WjPc2Pxsu3ZDrRXhRv1kiHsaMCmmI5QNe +c7f8k38bRhuXaMXAizUfux5nf1W3O1U/6vLK28xSzRaJ2xVHvfLNbHrXtBqsyBVs +avt3xOnyMOAUJGZlbyrlLcz2ga5XyNGbOJDcYJMCXssCAwEAATANBgkqhkiG9w0B +AQsFAAOCAQEAHHw56D1JsgkeaFovdBj0Y7WM9uah402VkJnvMlw0QOhVEw7gHL7N +qz9kOJleK8GBU6AYqPbuajNzbJpznYYIXccROEZMzaBHN4/+plCpAiGZQoZeR/5l +VmAdFlOGveRjxWnP+jBRq6HDUFPMZhxM/z8qOU2ij53Rp4si5HhpJAaDTcwKwIdp +m7yAqdK3pSOEfqIyJnx4Dr3bzTtpGDO4RO+WtJmG7ga9URzHoaQMxExRoN+sFAeI +jtc5Rf5S4KNM2116q03kygbovXRvRueTSk8bZ+eln++cAknR8tXpU+4JIawIyBX3 +rzW5TxEPQ65Gjv1bjaNOpyy3Je3k5ZQd4w== +-----END CERTIFICATE----- diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/server-key.pem b/samples/server/petstore/rust-server/output/multipart-v3/examples/server-key.pem new file mode 100644 index 000000000000..29c006829229 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/server-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJ1ENgUPzWDzhN +XV6qfMBeqezZk3jTk3IoQfUIpeqsZwfXH/d9dGl+RokgS3otmwII528PHQwPx2Bp +GUvffsp1lAtJceNt8uh5/e0KlGdV88prYbpYty7de8q5Ap8kNqwmjwSPgcg1EPSq +M7IkFvj3Hur3Fv76NMPduyy6et9N4toe5dIoRG7IluD9CQwUDDHc4MrBp5u/Foz3 +Nj8bLt2Q60V4Ub9ZIh7GjAppiOUDXnO3/JN/G0Ybl2jFwIs1H7seZ39VtztVP+ry +ytvMUs0WidsVR73yzWx617QarMgVbGr7d8Tp8jDgFCRmZW8q5S3M9oGuV8jRmziQ +3GCTAl7LAgMBAAECggEBAKEd1q9j14KWYc64s6KLthGbutyxsinMMbxbct11fdIk +6YhdF3fJ35ETg9IJDr6rWEN9ZRX+jStncNpVfFEs6ThVd3Eo/nI+EEGaaIkikR93 +X2a7fEPn7/yVHu70XdBN6L1bPDvHUeiy4W2hmRrgT90OjGm1rNRWHOm7yugOwIZu +HclzbR9Ca7EInFnotUiDQm9sw9VKHbJHqWx6OORdZrxR2ytYs0Qkq0XpGMvti2HW +7WAmKTg5QM8myXW7+/4iqb/u68wVBR2BBalShKmIf7lim9O3W2a1RjDdsvm/wNe9 +I+D+Iq825vpqkKXcrxYlpVg7hYiaQaW/MNsEb7lQRjECgYEA/RJYby0POW+/k0Jn +jO8UmJVEMiuGa8WIUu/JJWMOmzRCukjSRNQOkt7niQrZPJYE8W6clM6RJTolWf9L +IL6mIb+mRaoudUk8SHGDq7ho1iMg9GK8lhYxvKh1Q6uv8EyVSkgLknAEY0NANKC1 +zNdU5Dhven9aRX2gq9vP4XwMz2MCgYEAzCogQ7IFk+gkp3k491dOZnrGRoRCfuzo +4CJtyKFgOSd7BjmpcKkj0IPfVBjw6GjMIxfQRMTQmxAjjWevH45vG8l0Iiwz/gSp +81b5nsDEX5uv2Olcmcz5zxRFy36jOZ9ihMWinxcIlT2oDbyCdbruDKZq9ieJ9S8g +4qGx0OkwE3kCgYEA7CmAiU89U9YqqttfEq/RQoqY91CSwmO10d+ej9seuEtOsdRf +FIfnibulycdr7hP5TOxyBpO1802NqayJiWcgVYIpQf2MGTtcnCYCP+95NcvWZvj1 +EAJqK6nwtFO1fcOZ1ZXh5qfOEGujsPkAbsXLnKXlsiTCMvMHSxl3pu5Cbg0CgYBf +JjbZNctRrjv+7Qj2hPLd4dQsIxGWc7ToWENP4J2mpVa5hQAJqFovoHXhjKohtk2F +AWEn243Y5oGbMjo0e74edhmwn2cvuF64MM2vBem/ISCn98IXT6cQskMA3qkVfsl8 +VVs/x41ReGWs2TD3y0GMFbb9t1mdMfSiincDhNnKCQKBgGfeT4jKyYeCoCw4OLI1 +G75Gd0METt/IkppwODPpNwj3Rp9I5jctWZFA/3wCX/zk0HgBeou5AFNS4nQZ/X/L +L9axbSdR7UJTGkT1r4gu3rLkPV4Tk+8XM03/JT2cofMlzQBuhvl1Pn4SgKowz7hl +lS76ECw4Av3T0S34VW9Z5oye +-----END PRIVATE KEY----- diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/server.rs b/samples/server/petstore/rust-server/output/multipart-v3/examples/server.rs new file mode 100644 index 000000000000..2bd095f7a96f --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/server.rs @@ -0,0 +1,75 @@ +//! Main binary entry point for multipart_v3 implementation. + +#![allow(missing_docs)] + +// Imports required by this file. +// extern crate ; +extern crate multipart_v3; +extern crate swagger; +extern crate hyper; +extern crate openssl; +extern crate native_tls; +extern crate tokio_proto; +extern crate tokio_tls; +extern crate clap; + +// Imports required by server library. +// extern crate multipart_v3; +// extern crate swagger; +extern crate futures; +extern crate chrono; +#[macro_use] +extern crate error_chain; + + +use openssl::x509::X509_FILETYPE_PEM; +use openssl::ssl::{SslAcceptorBuilder, SslMethod}; +use openssl::error::ErrorStack; +use hyper::server::Http; +use tokio_proto::TcpServer; +use clap::{App, Arg}; +use swagger::auth::AllowAllAuthenticator; +use swagger::EmptyContext; + +mod server_lib; + +// Builds an SSL implementation for Simple HTTPS from some hard-coded file names +fn ssl() -> Result { + let mut ssl = SslAcceptorBuilder::mozilla_intermediate_raw(SslMethod::tls())?; + + // Server authentication + ssl.set_private_key_file("examples/server-key.pem", X509_FILETYPE_PEM)?; + ssl.set_certificate_chain_file("examples/server-chain.pem")?; + ssl.check_private_key()?; + + Ok(ssl) +} + +/// Create custom server, wire it to the autogenerated router, +/// and pass it to the web server. +fn main() { + let matches = App::new("server") + .arg(Arg::with_name("https") + .long("https") + .help("Whether to use HTTPS or not")) + .get_matches(); + + let service_fn = + multipart_v3::server::context::NewAddContext::<_, EmptyContext>::new( + AllowAllAuthenticator::new( + server_lib::NewService::new(), + "cosmo" + ) + ); + + let addr = "127.0.0.1:80".parse().expect("Failed to parse bind address"); + if matches.is_present("https") { + let ssl = ssl().expect("Failed to load SSL keys"); + let builder: native_tls::TlsAcceptorBuilder = native_tls::backend::openssl::TlsAcceptorBuilderExt::from_openssl(ssl); + let tls_acceptor = builder.build().expect("Failed to build TLS acceptor"); + TcpServer::new(tokio_tls::proto::Server::new(Http::new(), tls_acceptor), addr).serve(service_fn); + } else { + // Using HTTP + TcpServer::new(Http::new(), addr).serve(service_fn); + } +} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/server_lib/mod.rs b/samples/server/petstore/rust-server/output/multipart-v3/examples/server_lib/mod.rs new file mode 100644 index 000000000000..ae07201663ce --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/server_lib/mod.rs @@ -0,0 +1,37 @@ +//! Main library entry point for multipart_v3 implementation. + +mod server; + +mod errors { + error_chain!{} +} + +pub use self::errors::*; +use std::io; +use std::clone::Clone; +use std::marker::PhantomData; +use hyper; +use multipart_v3; +use swagger::{Has, XSpanIdString}; + +pub struct NewService{ + marker: PhantomData +} + +impl NewService{ + pub fn new() -> Self { + NewService{marker:PhantomData} + } +} + +impl hyper::server::NewService for NewService where C: Has + Clone + 'static { + type Request = (hyper::Request, C); + type Response = hyper::Response; + type Error = hyper::Error; + type Instance = multipart_v3::server::Service, C>; + + /// Instantiate a new server. + fn new_service(&self) -> io::Result { + Ok(multipart_v3::server::Service::new(server::Server::new())) + } +} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/server_lib/server.rs b/samples/server/petstore/rust-server/output/multipart-v3/examples/server_lib/server.rs new file mode 100644 index 000000000000..b9488562ed3a --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/server_lib/server.rs @@ -0,0 +1,38 @@ +//! Server implementation of multipart_v3. + +#![allow(unused_imports)] + +use futures::{self, Future}; +use chrono; +use std::collections::HashMap; +use std::marker::PhantomData; + +use swagger; +use swagger::{Has, XSpanIdString}; + +use multipart_v3::{Api, ApiError, + MultipartRequestPostResponse +}; +use multipart_v3::models; + +#[derive(Copy, Clone)] +pub struct Server { + marker: PhantomData, +} + +impl Server { + pub fn new() -> Self { + Server{marker: PhantomData} + } +} + +impl Api for Server where C: Has{ + + + fn multipart_request_post(&self, string_field: String, binary_field: swagger::ByteArray, optional_string_field: Option, object_field: Option, context: &C) -> Box> { + let context = context.clone(); + println!("multipart_request_post(\"{}\", {:?}, {:?}, {:?}) - X-Span-ID: {:?}", string_field, binary_field, optional_string_field, object_field, context.get().0.clone()); + Box::new(futures::failed("Generic failure".into())) + } + +} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/client/mod.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/client/mod.rs new file mode 100644 index 000000000000..42e60bdf2007 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/client/mod.rs @@ -0,0 +1,417 @@ +#![allow(unused_extern_crates)] +extern crate tokio_core; +extern crate native_tls; +extern crate hyper_tls; +extern crate openssl; +extern crate mime; +extern crate chrono; +extern crate url; +extern crate multipart; + +use hyper; +use hyper::header::{Headers, ContentType}; +use hyper::Uri; +use self::url::percent_encoding::{utf8_percent_encode, PATH_SEGMENT_ENCODE_SET, QUERY_ENCODE_SET}; +use futures; +use futures::{Future, Stream}; +use futures::{future, stream}; +use self::tokio_core::reactor::Handle; +use std::borrow::Cow; +use std::io::{Read, Error, ErrorKind}; +use std::error; +use std::fmt; +use std::path::Path; +use std::sync::Arc; +use std::str; +use std::str::FromStr; +use std::string::ToString; +use hyper::mime::Mime; +use std::io::Cursor; +use client::multipart::client::lazy::Multipart; +use mimetypes; +use serde_json; + +#[allow(unused_imports)] +use std::collections::{HashMap, BTreeMap}; +#[allow(unused_imports)] +use swagger; + +use swagger::{ApiError, XSpanId, XSpanIdString, Has, AuthData}; + +use {Api, + MultipartRequestPostResponse + }; +use models; + +define_encode_set! { + /// This encode set is used for object IDs + /// + /// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`, + /// the vertical bar (|) is encoded. + pub ID_ENCODE_SET = [PATH_SEGMENT_ENCODE_SET] | {'|'} +} + +/// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. +fn into_base_path(input: &str, correct_scheme: Option<&'static str>) -> Result { + // First convert to Uri, since a base path is a subset of Uri. + let uri = Uri::from_str(input)?; + + let scheme = uri.scheme().ok_or(ClientInitError::InvalidScheme)?; + + // Check the scheme if necessary + if let Some(correct_scheme) = correct_scheme { + if scheme != correct_scheme { + return Err(ClientInitError::InvalidScheme); + } + } + + let host = uri.host().ok_or_else(|| ClientInitError::MissingHost)?; + let port = uri.port().map(|x| format!(":{}", x)).unwrap_or_default(); + Ok(format!("{}://{}{}", scheme, host, port)) +} + +/// A client that implements the API by making HTTP calls out to a server. +pub struct Client where + F: Future + 'static { + client_service: Arc, Response=hyper::Response, Error=hyper::Error, Future=F>>>, + base_path: String, +} + +impl fmt::Debug for Client where + F: Future + 'static { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Client {{ base_path: {} }}", self.base_path) + } +} + +impl Clone for Client where + F: Future + 'static { + fn clone(&self) -> Self { + Client { + client_service: self.client_service.clone(), + base_path: self.base_path.clone() + } + } +} + +impl Client { + + /// Create an HTTP client. + /// + /// # Arguments + /// * `handle` - tokio reactor handle to use for execution + /// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com" + pub fn try_new_http(handle: Handle, base_path: &str) -> Result, ClientInitError> { + let http_connector = swagger::http_connector(); + Self::try_new_with_connector::( + handle, + base_path, + Some("http"), + http_connector, + ) + } + + /// Create a client with a TLS connection to the server. + /// + /// # Arguments + /// * `handle` - tokio reactor handle to use for execution + /// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com" + /// * `ca_certificate` - Path to CA certificate used to authenticate the server + pub fn try_new_https( + handle: Handle, + base_path: &str, + ca_certificate: CA, + ) -> Result, ClientInitError> + where + CA: AsRef, + { + let https_connector = swagger::https_connector(ca_certificate); + Self::try_new_with_connector::>( + handle, + base_path, + Some("https"), + https_connector, + ) + } + + /// Create a client with a mutually authenticated TLS connection to the server. + /// + /// # Arguments + /// * `handle` - tokio reactor handle to use for execution + /// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com" + /// * `ca_certificate` - Path to CA certificate used to authenticate the server + /// * `client_key` - Path to the client private key + /// * `client_certificate` - Path to the client's public certificate associated with the private key + pub fn try_new_https_mutual( + handle: Handle, + base_path: &str, + ca_certificate: CA, + client_key: K, + client_certificate: C, + ) -> Result, ClientInitError> + where + CA: AsRef, + K: AsRef, + C: AsRef, + { + let https_connector = + swagger::https_mutual_connector(ca_certificate, client_key, client_certificate); + Self::try_new_with_connector::>( + handle, + base_path, + Some("https"), + https_connector, + ) + } + + /// Create a client with a custom implementation of hyper::client::Connect. + /// + /// Intended for use with custom implementations of connect for e.g. protocol logging + /// or similar functionality which requires wrapping the transport layer. When wrapping a TCP connection, + /// this function should be used in conjunction with + /// `swagger::{http_connector, https_connector, https_mutual_connector}`. + /// + /// For ordinary tcp connections, prefer the use of `try_new_http`, `try_new_https` + /// and `try_new_https_mutual`, to avoid introducing a dependency on the underlying transport layer. + /// + /// # Arguments + /// + /// * `handle` - tokio reactor handle to use for execution + /// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com" + /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` + /// * `connector_fn` - Function which returns an implementation of `hyper::client::Connect` + pub fn try_new_with_connector( + handle: Handle, + base_path: &str, + protocol: Option<&'static str>, + connector_fn: Box C + Send + Sync>, + ) -> Result, ClientInitError> + where + C: hyper::client::Connect + hyper::client::Service, + { + let connector = connector_fn(&handle); + let client_service = Box::new(hyper::Client::configure().connector(connector).build( + &handle, + )); + + Ok(Client { + client_service: Arc::new(client_service), + base_path: into_base_path(base_path, protocol)?, + }) + } + + /// Constructor for creating a `Client` by passing in a pre-made `hyper` client. + /// + /// One should avoid relying on this function if possible, since it adds a dependency on the underlying transport + /// implementation, which it would be better to abstract away. Therefore, using this function may lead to a loss of + /// code generality, which may make it harder to move the application to a serverless environment, for example. + /// + /// The reason for this function's existence is to support legacy test code, which did mocking at the hyper layer. + /// This is not a recommended way to write new tests. If other reasons are found for using this function, they + /// should be mentioned here. + #[deprecated(note="Use try_new_with_client_service instead")] + pub fn try_new_with_hyper_client( + hyper_client: Arc, Response=hyper::Response, Error=hyper::Error, Future=hyper::client::FutureResponse>>>, + handle: Handle, + base_path: &str + ) -> Result, ClientInitError> + { + Ok(Client { + client_service: hyper_client, + base_path: into_base_path(base_path, None)?, + }) + } +} + +impl Client where + F: Future + 'static +{ + /// Constructor for creating a `Client` by passing in a pre-made `hyper` client Service. + /// + /// This allows adding custom wrappers around the underlying transport, for example for logging. + pub fn try_new_with_client_service(client_service: Arc, Response=hyper::Response, Error=hyper::Error, Future=F>>>, + handle: Handle, + base_path: &str) + -> Result, ClientInitError> + { + Ok(Client { + client_service: client_service, + base_path: into_base_path(base_path, None)?, + }) + } +} + +impl Api for Client where + F: Future + 'static, + C: Has { + + fn multipart_request_post(&self, param_string_field: String, param_binary_field: swagger::ByteArray, param_optional_string_field: Option, param_object_field: Option, context: &C) -> Box> { + let mut uri = format!( + "{}/multipart_request", + self.base_path + ); + + let mut query_string = self::url::form_urlencoded::Serializer::new("".to_owned()); + + + let query_string_str = query_string.finish(); + if !query_string_str.is_empty() { + uri += "?"; + uri += &query_string_str; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build URI: {}", err))))), + }; + + let mut request = hyper::Request::new(hyper::Method::Post, uri); + + let mut multipart = Multipart::new(); + + // For each parameter, encode as appropriate and add to the multipart body as a stream. + + let string_field_str = match serde_json::to_string(¶m_string_field) { + Ok(str) => str, + Err(e) => return Box::new(futures::done(Err(ApiError(format!("Unable to parse string_field to string: {}", e))))), + }; + + let string_field_vec = string_field_str.as_bytes().to_vec(); + + let string_field_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); + + let string_field_cursor = Cursor::new(string_field_vec); + + multipart.add_stream("string_field", string_field_cursor, None as Option<&str>, Some(string_field_mime)); + + + let optional_string_field_str = match serde_json::to_string(¶m_optional_string_field) { + Ok(str) => str, + Err(e) => return Box::new(futures::done(Err(ApiError(format!("Unable to parse optional_string_field to string: {}", e))))), + }; + + let optional_string_field_vec = optional_string_field_str.as_bytes().to_vec(); + + let optional_string_field_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); + + let optional_string_field_cursor = Cursor::new(optional_string_field_vec); + + multipart.add_stream("optional_string_field", optional_string_field_cursor, None as Option<&str>, Some(optional_string_field_mime)); + + + let object_field_str = match serde_json::to_string(¶m_object_field) { + Ok(str) => str, + Err(e) => return Box::new(futures::done(Err(ApiError(format!("Unable to parse object_field to string: {}", e))))), + }; + + let object_field_vec = object_field_str.as_bytes().to_vec(); + + let object_field_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); + + let object_field_cursor = Cursor::new(object_field_vec); + + multipart.add_stream("object_field", object_field_cursor, None as Option<&str>, Some(object_field_mime)); + + + let binary_field_vec = param_binary_field.to_vec(); + + let binary_field_mime = match mime::Mime::from_str("application/octet-stream") { + Ok(mime) => mime, + Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to get mime type: {:?}", err))))), + }; + + let binary_field_cursor = Cursor::new(binary_field_vec); + + let filename = None as Option<&str> ; + multipart.add_stream("binary_field", binary_field_cursor, filename, Some(binary_field_mime)); + + + 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(); + fields.to_body().read_to_string(&mut body_string).unwrap(); + let boundary = fields.boundary(); + + let multipart_header = match 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.set_body(body_string.into_bytes()); + request.headers_mut().set(ContentType(multipart_header)); + + + 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| { + match response.status().as_u16() { + 201 => { + let body = response.body(); + Box::new( + + future::ok( + MultipartRequestPostResponse::OK + ) + ) as Box> + }, + code => { + let headers = response.headers().clone(); + Box::new(response.body() + .take(100) + .concat2() + .then(move |body| + future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => Cow::from(format!("", e)), + }, + Err(e) => Cow::from(format!("", e)), + }))) + ) + ) as Box> + } + } + })) + + } + +} + +#[derive(Debug)] +pub enum ClientInitError { + InvalidScheme, + InvalidUri(hyper::error::UriError), + MissingHost, + SslError(openssl::error::ErrorStack) +} + +impl From for ClientInitError { + fn from(err: hyper::error::UriError) -> ClientInitError { + ClientInitError::InvalidUri(err) + } +} + +impl From for ClientInitError { + fn from(err: openssl::error::ErrorStack) -> ClientInitError { + ClientInitError::SslError(err) + } +} + +impl fmt::Display for ClientInitError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (self as &fmt::Debug).fmt(f) + } +} + +impl error::Error for ClientInitError { + fn description(&self) -> &str { + "Failed to produce a hyper client." + } +} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs new file mode 100644 index 000000000000..8d553034d0c0 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs @@ -0,0 +1,101 @@ +#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)] +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; + + +extern crate futures; +extern crate chrono; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; +extern crate mime; + +// Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module. +#[cfg(any(feature = "client", feature = "server"))] +#[macro_use] +extern crate hyper; + +extern crate swagger; + +#[macro_use] +extern crate url; + +use futures::Stream; +use std::io::Error; + +#[allow(unused_imports)] +use std::collections::HashMap; + +pub use futures::Future; + +#[cfg(any(feature = "client", feature = "server"))] +mod mimetypes; + +pub use swagger::{ApiError, ContextWrapper}; + +pub const BASE_PATH: &'static str = ""; +pub const API_VERSION: &'static str = "1.0.7"; + + +#[derive(Debug, PartialEq)] +pub enum MultipartRequestPostResponse { + /// OK + OK , +} + + +/// API +pub trait Api { + + + fn multipart_request_post(&self, string_field: String, binary_field: swagger::ByteArray, optional_string_field: Option, object_field: Option, context: &C) -> Box>; + +} + +/// API without a `Context` +pub trait ApiNoContext { + + + fn multipart_request_post(&self, string_field: String, binary_field: swagger::ByteArray, optional_string_field: Option, object_field: Option) -> Box>; + +} + +/// Trait to extend an API to make it easy to bind it to a context. +pub trait ContextWrapperExt<'a, C> where Self: Sized { + /// Binds this API to a context. + fn with_context(self: &'a Self, context: C) -> ContextWrapper<'a, Self, C>; +} + +impl<'a, T: Api + Sized, C> ContextWrapperExt<'a, C> for T { + fn with_context(self: &'a T, context: C) -> ContextWrapper<'a, T, C> { + ContextWrapper::::new(self, context) + } +} + +impl<'a, T: Api, C> ApiNoContext for ContextWrapper<'a, T, C> { + + + fn multipart_request_post(&self, string_field: String, binary_field: swagger::ByteArray, optional_string_field: Option, object_field: Option) -> Box> { + self.api().multipart_request_post(string_field, binary_field, optional_string_field, object_field, &self.context()) + } + +} + +#[cfg(feature = "client")] +pub mod client; + +// Re-export Client as a top-level name +#[cfg(feature = "client")] +pub use self::client::Client; + +#[cfg(feature = "server")] +pub mod server; + +// Re-export router() as a top-level name +#[cfg(feature = "server")] +pub use self::server::Service; + +pub mod models; diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/mimetypes.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/mimetypes.rs new file mode 100644 index 000000000000..45d98f894cda --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/mimetypes.rs @@ -0,0 +1,17 @@ +/// mime types for requests and responses + +pub mod responses { + use hyper::mime::*; + + // The macro is called per-operation to beat the recursion limit + +} + +pub mod requests { + use hyper::mime::*; + /// Create Mime objects for the request content types for MultipartRequestPost + lazy_static! { + pub static ref MULTIPART_REQUEST_POST: Mime = "multipart/form-data".parse().unwrap(); + } + +} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs new file mode 100644 index 000000000000..a1821ae32d11 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs @@ -0,0 +1,63 @@ +#![allow(unused_imports, unused_qualifications, unused_extern_crates)] +extern crate chrono; +extern crate uuid; + +use serde::ser::Serializer; + +use std::collections::HashMap; +use models; +use swagger; +use std::string::ParseError; + + + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct MultipartRequest { + #[serde(rename = "string_field")] + pub string_field: String, + + #[serde(rename = "optional_string_field")] + #[serde(skip_serializing_if="Option::is_none")] + pub optional_string_field: Option, + + #[serde(rename = "object_field")] + #[serde(skip_serializing_if="Option::is_none")] + pub object_field: Option, + + #[serde(rename = "binary_field")] + pub binary_field: swagger::ByteArray, + +} + +impl MultipartRequest { + pub fn new(string_field: String, binary_field: swagger::ByteArray, ) -> MultipartRequest { + MultipartRequest { + string_field: string_field, + optional_string_field: None, + object_field: None, + binary_field: binary_field, + } + } +} + + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct MultipartRequestObjectField { + #[serde(rename = "field_a")] + pub field_a: String, + + #[serde(rename = "field_b")] + #[serde(skip_serializing_if="Option::is_none")] + pub field_b: Option>, + +} + +impl MultipartRequestObjectField { + pub fn new(field_a: String, ) -> MultipartRequestObjectField { + MultipartRequestObjectField { + field_a: field_a, + field_b: None, + } + } +} + diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/server/context.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/server/context.rs new file mode 100644 index 000000000000..6f2900b3d70c --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/server/context.rs @@ -0,0 +1,91 @@ +use std::io; +use std::marker::PhantomData; +use std::default::Default; +use hyper; +use hyper::{Request, Response, Error, StatusCode}; +use server::url::form_urlencoded; +use swagger::auth::{Authorization, AuthData, Scopes}; +use swagger::{Has, Pop, Push, XSpanIdString}; +use Api; + +pub struct NewAddContext +{ + inner: T, + marker: PhantomData, +} + +impl NewAddContext + where + A: Default + Push, + B: Push, Result=C>, + C: Push, Result=D>, + T: hyper::server::NewService + 'static, +{ + pub fn new(inner: T) -> NewAddContext { + NewAddContext { + inner, + marker: PhantomData, + } + } +} + +impl hyper::server::NewService for NewAddContext + where + A: Default + Push, + B: Push, Result=C>, + C: Push, Result=D>, + T: hyper::server::NewService + 'static, +{ + type Request = Request; + type Response = Response; + type Error = Error; + type Instance = AddContext; + + fn new_service(&self) -> Result { + self.inner.new_service().map(|s| AddContext::new(s)) + } +} + +/// Middleware to extract authentication data from request +pub struct AddContext +{ + inner: T, + marker: PhantomData, +} + +impl AddContext + where + A: Default + Push, + B: Push, Result=C>, + C: Push, Result=D>, + T: hyper::server::Service, +{ + pub fn new(inner: T) -> AddContext { + AddContext { + inner, + marker: PhantomData, + } + } +} + +impl hyper::server::Service for AddContext + where + A: Default + Push, + B: Push, Result=C>, + C: Push, Result=D>, + T: hyper::server::Service, +{ + type Request = Request; + type Response = Response; + type Error = Error; + type Future = T::Future; + + fn call(&self, req: Self::Request) -> Self::Future { + let context = A::default().push(XSpanIdString::get_or_generate(&req)); + + + let context = context.push(None::); + let context = context.push(None::); + return self.inner.call((req, context)); + } +} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/server/mod.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/server/mod.rs new file mode 100644 index 000000000000..67e139f9b246 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/server/mod.rs @@ -0,0 +1,277 @@ +#![allow(unused_extern_crates)] +extern crate serde_ignored; +extern crate tokio_core; +extern crate native_tls; +extern crate hyper_tls; +extern crate openssl; +extern crate mime; +extern crate chrono; +extern crate percent_encoding; +extern crate url; +extern crate uuid; +extern crate multipart; + +use std::sync::Arc; +use std::marker::PhantomData; +use futures::{Future, future, Stream, stream}; +use hyper; +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 std::fs; +use serde_json; + +#[allow(unused_imports)] +use std::collections::{HashMap, BTreeMap}; +#[allow(unused_imports)] +use swagger; +use std::io; + +#[allow(unused_imports)] +use std::collections::BTreeSet; + +pub use swagger::auth::Authorization; +use swagger::{ApiError, XSpanId, XSpanIdString, Has, RequestParser}; +use swagger::auth::Scopes; + +use {Api, + MultipartRequestPostResponse + }; +#[allow(unused_imports)] +use models; + +pub mod context; + +header! { (Warning, "Warning") => [String] } + +mod paths { + extern crate regex; + + lazy_static! { + pub static ref GLOBAL_REGEX_SET: regex::RegexSet = regex::RegexSet::new(&[ + r"^/multipart_request$" + ]).unwrap(); + } + pub static ID_MULTIPART_REQUEST: usize = 0; +} + +pub struct NewService { + api_impl: Arc, + marker: PhantomData, +} + +impl NewService +where + T: Api + Clone + 'static, + C: Has + 'static +{ + pub fn new>>(api_impl: U) -> NewService { + NewService{api_impl: api_impl.into(), marker: PhantomData} + } +} + +impl hyper::server::NewService for NewService +where + T: Api + Clone + 'static, + C: Has + 'static +{ + type Request = (Request, C); + type Response = Response; + type Error = Error; + type Instance = Service; + + fn new_service(&self) -> Result { + Ok(Service::new(self.api_impl.clone())) + } +} + +pub struct Service { + api_impl: Arc, + marker: PhantomData, +} + +impl Service +where + T: Api + Clone + 'static, + C: Has + 'static { + pub fn new>>(api_impl: U) -> Service { + Service{api_impl: api_impl.into(), marker: PhantomData} + } +} + +impl hyper::server::Service for Service +where + T: Api + Clone + 'static, + C: Has + 'static +{ + type Request = (Request, C); + type Response = Response; + type Error = Error; + type Future = Box>; + + fn call(&self, (req, mut context): Self::Request) -> Self::Future { + let api_impl = self.api_impl.clone(); + let (method, uri, _, headers, body) = req.deconstruct(); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + + // This match statement is duplicated below in `parse_operation_id()`. + // Please update both places if changing how this code is autogenerated. + match &method { + + // MultipartRequestPost - POST /multipart_request + &hyper::Method::Post if path.matched(paths::ID_MULTIPART_REQUEST) => { + 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"))), + }; + // Form Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + Box::new(body.concat2() + .then(move |result| -> Box> { + match result { + Ok(body) => { + // Read Form Parameters from 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")))) + }, + }; + + + let file_string_field = entries.files.remove("string_field"); + let param_string_field = match file_string_field { + Some(file) => { + let path = &file[0].path; + let string_field_str = fs::read_to_string(path).expect("Reading saved String should never fail"); + let string_field_model: String = match serde_json::from_str(&string_field_str) { + Ok(model) => model, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("string_field data does not match API definition: {}", e)))) + } + }; + string_field_model + } + None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Missing required form parameter string_field")))), + }; + + + + let file_optional_string_field = entries.files.remove("optional_string_field"); + let param_optional_string_field = match file_optional_string_field { + Some(file) => { + let path = &file[0].path; + let optional_string_field_str = fs::read_to_string(path).unwrap(); + let optional_string_field_model: String = serde_json::from_str(&optional_string_field_str).expect("Impossible to fail to serialise"); + Some(optional_string_field_model) + } + None => None, + }; + + + + let file_object_field = entries.files.remove("object_field"); + let param_object_field = match file_object_field { + Some(file) => { + let path = &file[0].path; + let object_field_str = fs::read_to_string(path).unwrap(); + let object_field_model: models::MultipartRequestObjectField = serde_json::from_str(&object_field_str).expect("Impossible to fail to serialise"); + Some(object_field_model) + } + None => None, + }; + + + let file_binary_field = entries.files.remove("binary_field"); + let param_binary_field = match file_binary_field { + Some(file) => { + let path = &file[0].path; + let binary_field_str = fs::read_to_string(path).unwrap(); + swagger::ByteArray(binary_field_str.as_bytes().to_vec()) + } + None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Missing required form parameter binary_field")))), + }; + + Box::new(api_impl.multipart_request_post(param_string_field, param_binary_field, param_optional_string_field, param_object_field, &context) + .then(move |result| { + let mut response = Response::new(); + response.headers_mut().set(XSpanId((&context as &Has).get().0.to_string())); + + match result { + Ok(rsp) => match rsp { + MultipartRequestPostResponse::OK + + + => { + response.set_status(StatusCode::try_from(201).unwrap()); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + } + )) + as Box> + }, + Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))), + } + }) + ) + }, + + _ => Box::new(future::ok(Response::new().with_status(StatusCode::NotFound))) as Box>, + } + } +} + +impl Clone for Service +{ + fn clone(&self) -> Self { + Service { + api_impl: self.api_impl.clone(), + marker: self.marker.clone(), + } + } +} + +/// 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_() == hyper::mime::MULTIPART && mime.subtype() == hyper::mime::FORM_DATA { + mime.get_param(hyper::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() { + + // MultipartRequestPost - POST /multipart_request + &hyper::Method::Post if path.matched(paths::ID_MULTIPART_REQUEST) => Ok("MultipartRequestPost"), + _ => Err(()), + } + } +} diff --git a/samples/server/petstore/rust-server/output/openapi-v3/Cargo.toml b/samples/server/petstore/rust-server/output/openapi-v3/Cargo.toml index b2edca9c74bd..3b00d15503a4 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/Cargo.toml +++ b/samples/server/petstore/rust-server/output/openapi-v3/Cargo.toml @@ -23,8 +23,8 @@ swagger = "2" # lazy_static = "0.2" log = "0.3.0" -mime = "0.3.3" -multipart = {version = "0.13.3", optional = true} +mime = "0.2.6" +multipart = {version = "0.13.3"} native-tls = {version = "0.1.4", optional = true} openssl = {version = "0.9.14", optional = true} percent-encoding = {version = "1.0.0", optional = true} diff --git a/samples/server/petstore/rust-server/output/openapi-v3/README.md b/samples/server/petstore/rust-server/output/openapi-v3/README.md index 706821945d84..9ae326923828 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/README.md +++ b/samples/server/petstore/rust-server/output/openapi-v3/README.md @@ -56,6 +56,7 @@ To run a client, follow one of the following simple steps: ``` cargo run --example client RequiredOctetStreamPut +cargo run --example client UuidGet cargo run --example client XmlExtraPost cargo run --example client XmlOtherPost cargo run --example client XmlOtherPut @@ -115,6 +116,7 @@ All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- [****](docs/default_api.md#) | **PUT** /required_octet_stream | +[****](docs/default_api.md#) | **GET** /uuid | [****](docs/default_api.md#) | **POST** /xml_extra | [****](docs/default_api.md#) | **POST** /xml_other | [****](docs/default_api.md#) | **PUT** /xml_other | diff --git a/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml b/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml index f9282ee31152..1c250b1c94c0 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml +++ b/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml @@ -65,6 +65,15 @@ paths: description: OK 400: description: Bad Request + /uuid: + get: + responses: + 200: + content: + application/json: + schema: + $ref: '#/components/schemas/UuidObject' + description: Duplicate Response long text. One. /required_octet_stream: put: requestBody: diff --git a/samples/server/petstore/rust-server/output/openapi-v3/docs/default_api.md b/samples/server/petstore/rust-server/output/openapi-v3/docs/default_api.md index b8652374c9d0..b0bf1222fa45 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/docs/default_api.md +++ b/samples/server/petstore/rust-server/output/openapi-v3/docs/default_api.md @@ -5,6 +5,7 @@ All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- ****](default_api.md#) | **PUT** /required_octet_stream | +****](default_api.md#) | **GET** /uuid | ****](default_api.md#) | **POST** /xml_extra | ****](default_api.md#) | **POST** /xml_other | ****](default_api.md#) | **PUT** /xml_other | @@ -37,6 +38,28 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **** +> uuid::Uuid () + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + +[**uuid::Uuid**](UUID.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **** > (optional) diff --git a/samples/server/petstore/rust-server/output/openapi-v3/examples/client.rs b/samples/server/petstore/rust-server/output/openapi-v3/examples/client.rs index b94f73479676..35aec947f481 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/examples/client.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/examples/client.rs @@ -20,6 +20,7 @@ use tokio_core::reactor; use openapi_v3::{ApiNoContext, ContextWrapperExt, ApiError, RequiredOctetStreamPutResponse, + UuidGetResponse, XmlExtraPostResponse, XmlOtherPostResponse, XmlOtherPutResponse, @@ -34,6 +35,7 @@ fn main() { .help("Sets the operation to run") .possible_values(&[ "RequiredOctetStreamPut", + "UuidGet", "XmlExtraPost", "XmlOtherPost", "XmlOtherPut", @@ -84,6 +86,11 @@ fn main() { println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has).get().clone()); }, + Some("UuidGet") => { + let result = core.run(client.uuid_get()); + println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has).get().clone()); + }, + Some("XmlExtraPost") => { let result = core.run(client.xml_extra_post(None)); println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has).get().clone()); diff --git a/samples/server/petstore/rust-server/output/openapi-v3/examples/server_lib/server.rs b/samples/server/petstore/rust-server/output/openapi-v3/examples/server_lib/server.rs index 9e28fb179abf..ed9633e9c036 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/examples/server_lib/server.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/examples/server_lib/server.rs @@ -12,6 +12,7 @@ use swagger::{Has, XSpanIdString}; use openapi_v3::{Api, ApiError, RequiredOctetStreamPutResponse, + UuidGetResponse, XmlExtraPostResponse, XmlOtherPostResponse, XmlOtherPutResponse, @@ -41,6 +42,13 @@ impl Api for Server where C: Has{ } + fn uuid_get(&self, context: &C) -> Box> { + let context = context.clone(); + println!("uuid_get() - X-Span-ID: {:?}", context.get().0.clone()); + Box::new(futures::failed("Generic failure".into())) + } + + fn xml_extra_post(&self, duplicate_xml_object: Option, context: &C) -> Box> { let context = context.clone(); println!("xml_extra_post({:?}) - X-Span-ID: {:?}", duplicate_xml_object, context.get().0.clone()); diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/client/mod.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/client/mod.rs index 855f89cfce35..55d94240ebfc 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/client/mod.rs @@ -7,8 +7,6 @@ extern crate mime; extern crate chrono; extern crate url; - - use hyper; use hyper::header::{Headers, ContentType}; use hyper::Uri; @@ -26,9 +24,7 @@ use std::sync::Arc; use std::str; use std::str::FromStr; use std::string::ToString; - use mimetypes; - use serde_json; use serde_xml_rs; @@ -41,6 +37,7 @@ use swagger::{ApiError, XSpanId, XSpanIdString, Has, AuthData}; use {Api, RequiredOctetStreamPutResponse, + UuidGetResponse, XmlExtraPostResponse, XmlOtherPostResponse, XmlOtherPutResponse, @@ -273,17 +270,13 @@ impl Api for Client where let mut request = hyper::Request::new(hyper::Method::Put, uri); - // Body parameter let body = param_body.0; - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::REQUIRED_OCTET_STREAM_PUT.clone())); + 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| { @@ -321,6 +314,80 @@ impl Api for Client where } + fn uuid_get(&self, context: &C) -> Box> { + let mut uri = format!( + "{}/uuid", + self.base_path + ); + + let mut query_string = self::url::form_urlencoded::Serializer::new("".to_owned()); + + + let query_string_str = query_string.finish(); + if !query_string_str.is_empty() { + uri += "?"; + uri += &query_string_str; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build URI: {}", err))))), + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + + 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| { + match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body + .concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| + + str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e))) + .and_then(|body| + + serde_json::from_str::(body) + .map_err(|e| e.into()) + ) + + ) + .map(move |body| { + UuidGetResponse::DuplicateResponseLongText(body) + }) + ) as Box> + }, + code => { + let headers = response.headers().clone(); + Box::new(response.body() + .take(100) + .concat2() + .then(move |body| + future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => Cow::from(format!("", e)), + }, + Err(e) => Cow::from(format!("", e)), + }))) + ) + ) as Box> + } + } + })) + + } + fn xml_extra_post(&self, param_duplicate_xml_object: Option, context: &C) -> Box> { let mut uri = format!( "{}/xml_extra", @@ -347,14 +414,13 @@ impl Api for Client where body.to_xml() }); -if let Some(body) = body { - request.set_body(body); + if let Some(body) = body { + request.set_body(body); } request.headers_mut().set(ContentType(mimetypes::requests::XML_EXTRA_POST.clone())); + 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| { @@ -427,14 +493,13 @@ if let Some(body) = body { body.to_xml() }); -if let Some(body) = body { - request.set_body(body); + if let Some(body) = body { + request.set_body(body); } request.headers_mut().set(ContentType(mimetypes::requests::XML_OTHER_POST.clone())); + 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| { @@ -507,14 +572,13 @@ if let Some(body) = body { body.to_xml() }); -if let Some(body) = body { - request.set_body(body); + if let Some(body) = body { + request.set_body(body); } request.headers_mut().set(ContentType(mimetypes::requests::XML_OTHER_PUT.clone())); + 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| { @@ -587,14 +651,13 @@ if let Some(body) = body { body.to_xml() }); -if let Some(body) = body { - request.set_body(body); + if let Some(body) = body { + request.set_body(body); } request.headers_mut().set(ContentType(mimetypes::requests::XML_POST.clone())); + 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| { @@ -667,14 +730,13 @@ if let Some(body) = body { body.to_xml() }); -if let Some(body) = body { - request.set_body(body); + if let Some(body) = body { + request.set_body(body); } request.headers_mut().set(ContentType(mimetypes::requests::XML_PUT.clone())); + 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/output/openapi-v3/src/lib.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/lib.rs index 45731e516ace..8b28ecdfc736 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/lib.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/lib.rs @@ -11,6 +11,7 @@ extern crate chrono; extern crate lazy_static; #[macro_use] extern crate log; +extern crate mime; // Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module. #[cfg(any(feature = "client", feature = "server"))] @@ -45,6 +46,12 @@ pub enum RequiredOctetStreamPutResponse { OK , } +#[derive(Debug, PartialEq)] +pub enum UuidGetResponse { + /// Duplicate Response long text. One. + DuplicateResponseLongText ( uuid::Uuid ) , +} + #[derive(Debug, PartialEq)] pub enum XmlExtraPostResponse { /// OK @@ -93,6 +100,9 @@ pub trait Api { fn required_octet_stream_put(&self, body: swagger::ByteArray, context: &C) -> Box>; + fn uuid_get(&self, context: &C) -> Box>; + + fn xml_extra_post(&self, duplicate_xml_object: Option, context: &C) -> Box>; @@ -116,6 +126,9 @@ pub trait ApiNoContext { fn required_octet_stream_put(&self, body: swagger::ByteArray) -> Box>; + fn uuid_get(&self) -> Box>; + + fn xml_extra_post(&self, duplicate_xml_object: Option) -> Box>; @@ -152,6 +165,11 @@ impl<'a, T: Api, C> ApiNoContext for ContextWrapper<'a, T, C> { } + fn uuid_get(&self) -> Box> { + self.api().uuid_get(&self.context()) + } + + fn xml_extra_post(&self, duplicate_xml_object: Option) -> Box> { self.api().xml_extra_post(duplicate_xml_object, &self.context()) } diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/mimetypes.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/mimetypes.rs index 83396a3fa0c6..13936792a1f9 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/mimetypes.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/mimetypes.rs @@ -4,6 +4,10 @@ pub mod responses { use hyper::mime::*; // The macro is called per-operation to beat the recursion limit + /// Create Mime objects for the response content types for UuidGet + lazy_static! { + pub static ref UUID_GET_DUPLICATE_RESPONSE_LONG_TEXT: Mime = "application/json".parse().unwrap(); + } } diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/server/mod.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/server/mod.rs index f96ba0a9c5dc..66d4e219ac17 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/server/mod.rs @@ -5,11 +5,10 @@ extern crate native_tls; extern crate hyper_tls; extern crate openssl; extern crate mime; -extern crate uuid; extern crate chrono; extern crate percent_encoding; extern crate url; - +extern crate uuid; use std::sync::Arc; use std::marker::PhantomData; @@ -19,7 +18,6 @@ use hyper::{Request, Response, Error, StatusCode}; use hyper::header::{Headers, ContentType}; use self::url::form_urlencoded; use mimetypes; - use serde_json; use serde_xml_rs; @@ -38,6 +36,7 @@ use swagger::auth::Scopes; use {Api, RequiredOctetStreamPutResponse, + UuidGetResponse, XmlExtraPostResponse, XmlOtherPostResponse, XmlOtherPutResponse, @@ -57,15 +56,17 @@ mod paths { lazy_static! { pub static ref GLOBAL_REGEX_SET: regex::RegexSet = regex::RegexSet::new(&[ r"^/required_octet_stream$", + r"^/uuid$", r"^/xml$", r"^/xml_extra$", r"^/xml_other$" ]).unwrap(); } pub static ID_REQUIRED_OCTET_STREAM: usize = 0; - pub static ID_XML: usize = 1; - pub static ID_XML_EXTRA: usize = 2; - pub static ID_XML_OTHER: usize = 3; + pub static ID_UUID: usize = 1; + pub static ID_XML: usize = 2; + pub static ID_XML_EXTRA: usize = 3; + pub static ID_XML_OTHER: usize = 4; } pub struct NewService { @@ -133,12 +134,6 @@ where // RequiredOctetStreamPut - PUT /required_octet_stream &hyper::Method::Put if path.matched(paths::ID_REQUIRED_OCTET_STREAM) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -147,9 +142,7 @@ where match result { Ok(body) => { let param_body: Option = if !body.is_empty() { - Some(swagger::ByteArray(body.to_vec())) - } else { None }; @@ -157,8 +150,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.required_octet_stream_put(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -185,25 +176,57 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, + // UuidGet - GET /uuid + &hyper::Method::Get if path.matched(paths::ID_UUID) => { + Box::new({ + {{ + Box::new(api_impl.uuid_get(&context) + .then(move |result| { + let mut response = Response::new(); + response.headers_mut().set(XSpanId((&context as &Has).get().0.to_string())); + + match result { + Ok(rsp) => match rsp { + UuidGetResponse::DuplicateResponseLongText + + (body) + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::UUID_GET_DUPLICATE_RESPONSE_LONG_TEXT.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + } + )) + }} + }) as Box> + }, // XmlExtraPost - POST /xml_extra &hyper::Method::Post if path.matched(paths::ID_XML_EXTRA) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -211,25 +234,19 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_duplicate_xml_object: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) { Ok(param_duplicate_xml_object) => param_duplicate_xml_object, - Err(_) => None, } - } else { None }; - - Box::new(api_impl.xml_extra_post(param_duplicate_xml_object, &context) .then(move |result| { let mut response = Response::new(); @@ -267,25 +284,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter DuplicateXmlObject: {}", e)))), } }) ) as Box> - }, - // XmlOtherPost - POST /xml_other &hyper::Method::Post if path.matched(paths::ID_XML_OTHER) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -293,25 +300,19 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_another_xml_object: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) { Ok(param_another_xml_object) => param_another_xml_object, - Err(_) => None, } - } else { None }; - - Box::new(api_impl.xml_other_post(param_another_xml_object, &context) .then(move |result| { let mut response = Response::new(); @@ -349,25 +350,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter AnotherXmlObject: {}", e)))), } }) ) as Box> - }, - // XmlOtherPut - PUT /xml_other &hyper::Method::Put if path.matched(paths::ID_XML_OTHER) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -375,25 +366,19 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_string: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) { Ok(param_string) => param_string, - Err(_) => None, } - } else { None }; - - Box::new(api_impl.xml_other_put(param_string, &context) .then(move |result| { let mut response = Response::new(); @@ -431,25 +416,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter string: {}", e)))), } }) ) as Box> - }, - // XmlPost - POST /xml &hyper::Method::Post if path.matched(paths::ID_XML) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -457,25 +432,19 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_string: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) { Ok(param_string) => param_string, - Err(_) => None, } - } else { None }; - - Box::new(api_impl.xml_post(param_string, &context) .then(move |result| { let mut response = Response::new(); @@ -513,25 +482,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter string: {}", e)))), } }) ) as Box> - }, - // XmlPut - PUT /xml &hyper::Method::Put if path.matched(paths::ID_XML) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -539,25 +498,19 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_xml_object: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) { Ok(param_xml_object) => param_xml_object, - Err(_) => None, } - } else { None }; - - Box::new(api_impl.xml_put(param_xml_object, &context) .then(move |result| { let mut response = Response::new(); @@ -595,17 +548,13 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter XmlObject: {}", e)))), } }) ) as Box> - }, - _ => Box::new(future::ok(Response::new().with_status(StatusCode::NotFound))) as Box>, } } @@ -621,6 +570,7 @@ impl Clone for Service } } + /// Request parser for `Api`. pub struct ApiRequestParser; impl RequestParser for ApiRequestParser { @@ -631,6 +581,9 @@ impl RequestParser for ApiRequestParser { // RequiredOctetStreamPut - PUT /required_octet_stream &hyper::Method::Put if path.matched(paths::ID_REQUIRED_OCTET_STREAM) => Ok("RequiredOctetStreamPut"), + // UuidGet - GET /uuid + &hyper::Method::Get if path.matched(paths::ID_UUID) => Ok("UuidGet"), + // XmlExtraPost - POST /xml_extra &hyper::Method::Post if path.matched(paths::ID_XML_EXTRA) => Ok("XmlExtraPost"), diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/Cargo.toml b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/Cargo.toml index 59a86117f939..ced1aff24603 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/Cargo.toml +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/Cargo.toml @@ -23,8 +23,8 @@ swagger = "2" # lazy_static = "0.2" log = "0.3.0" -mime = "0.3.3" -multipart = {version = "0.13.3", optional = true} +mime = "0.2.6" +multipart = {version = "0.13.3"} native-tls = {version = "0.1.4", optional = true} openssl = {version = "0.9.14", optional = true} percent-encoding = {version = "1.0.0", optional = true} diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/client/mod.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/client/mod.rs index 2ef91fd174ce..1f8c143d76af 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/client/mod.rs @@ -7,7 +7,7 @@ extern crate mime; extern crate chrono; extern crate url; extern crate serde_urlencoded; - +extern crate multipart; use hyper; use hyper::header::{Headers, ContentType}; @@ -26,9 +26,10 @@ use std::sync::Arc; use std::str; use std::str::FromStr; use std::string::ToString; - +use hyper::mime::Mime; +use std::io::Cursor; +use client::multipart::client::lazy::Multipart; use mimetypes; - use serde_json; use serde_xml_rs; @@ -299,17 +300,13 @@ impl Api for Client where let mut request = hyper::Request::new(hyper::Method::Patch, uri); - // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::TEST_SPECIAL_TAGS.clone())); + 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| { @@ -382,20 +379,18 @@ impl Api for Client where let mut request = hyper::Request::new(hyper::Method::Post, uri); - // Body parameter let body = param_body.map(|ref body| { serde_json::to_string(body).expect("impossible to fail to serialize") }); -if let Some(body) = body { - request.set_body(body); + if let Some(body) = body { + request.set_body(body); } request.headers_mut().set(ContentType(mimetypes::requests::FAKE_OUTER_BOOLEAN_SERIALIZE.clone())); + 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| { @@ -472,14 +467,13 @@ if let Some(body) = body { serde_json::to_string(body).expect("impossible to fail to serialize") }); -if let Some(body) = body { - request.set_body(body); + if let Some(body) = body { + request.set_body(body); } request.headers_mut().set(ContentType(mimetypes::requests::FAKE_OUTER_COMPOSITE_SERIALIZE.clone())); + 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| { @@ -556,14 +550,13 @@ if let Some(body) = body { serde_json::to_string(body).expect("impossible to fail to serialize") }); -if let Some(body) = body { - request.set_body(body); + if let Some(body) = body { + request.set_body(body); } request.headers_mut().set(ContentType(mimetypes::requests::FAKE_OUTER_NUMBER_SERIALIZE.clone())); + 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| { @@ -640,14 +633,13 @@ if let Some(body) = body { serde_json::to_string(body).expect("impossible to fail to serialize") }); -if let Some(body) = body { - request.set_body(body); + if let Some(body) = body { + request.set_body(body); } request.headers_mut().set(ContentType(mimetypes::requests::FAKE_OUTER_STRING_SERIALIZE.clone())); + 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| { @@ -722,14 +714,11 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Put, uri); let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::TEST_BODY_WITH_QUERY_PARAMS.clone())); + 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| { @@ -790,14 +779,11 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Patch, uri); let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::TEST_CLIENT_MODEL.clone())); + 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| { @@ -890,6 +876,7 @@ if let Some(body) = body { 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())); if let Some(auth_data) = (context as &Has>).get().as_ref() { if let AuthData::Basic(ref basic_header) = *auth_data { @@ -898,7 +885,6 @@ if let Some(body) = body { )) } } - Box::new(self.client_service.call(request) .map_err(|e| ApiError(format!("No response received: {}", e))) .and_then(|mut response| { @@ -986,15 +972,13 @@ if let Some(body) = body { 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())); + request.headers_mut().set(XSpanId((context as &Has).get().0.clone())); // Header parameters header! { (RequestEnumHeaderStringArray, "enum_header_string_array") => (String)* } param_enum_header_string_array.map(|header| request.headers_mut().set(RequestEnumHeaderStringArray(header.clone()))); header! { (RequestEnumHeaderString, "enum_header_string") => [String] } 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| { @@ -1064,14 +1048,11 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Post, uri); let body = serde_json::to_string(¶m_param).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::TEST_INLINE_ADDITIONAL_PROPERTIES.clone())); + 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| { @@ -1139,9 +1120,8 @@ if let Some(body) = body { request.headers_mut().set(ContentType(mimetypes::requests::TEST_JSON_FORM_DATA.clone())); request.set_body(body.into_bytes()); + 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| { @@ -1205,17 +1185,13 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Patch, uri); - // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::TEST_CLASSNAME.clone())); + 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| { @@ -1288,17 +1264,13 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Post, uri); - // Body parameter let body = param_body.to_xml(); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::ADD_PET.clone())); + 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| { @@ -1360,12 +1332,9 @@ if let Some(body) = body { request.headers_mut().set(XSpanId((context as &Has).get().0.clone())); - // Header parameters header! { (RequestApiKey, "api_key") => [String] } 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| { @@ -1428,8 +1397,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| { @@ -1515,8 +1482,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| { @@ -1607,7 +1572,6 @@ if let Some(body) = body { request.headers_mut().set(ApiKey(api_key.to_string())); } } - Box::new(self.client_service.call(request) .map_err(|e| ApiError(format!("No response received: {}", e))) .and_then(|mut response| { @@ -1700,14 +1664,11 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Put, uri); let body = param_body.to_xml(); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::UPDATE_PET.clone())); + 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| { @@ -1793,9 +1754,8 @@ if let Some(body) = body { request.headers_mut().set(ContentType(mimetypes::requests::UPDATE_PET_WITH_FORM.clone())); request.set_body(body.into_bytes()); + 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| { @@ -1855,17 +1815,57 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Post, uri); - 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"); + let mut multipart = Multipart::new(); + + // For each parameter, encode as appropriate and add to the multipart body as a stream. + + let additional_metadata_str = match serde_json::to_string(¶m_additional_metadata) { + Ok(str) => str, + Err(e) => return Box::new(futures::done(Err(ApiError(format!("Unable to parse additional_metadata to string: {}", e))))), + }; + + let additional_metadata_vec = additional_metadata_str.as_bytes().to_vec(); + + let additional_metadata_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); + + let additional_metadata_cursor = Cursor::new(additional_metadata_vec); + + multipart.add_stream("additional_metadata", additional_metadata_cursor, None as Option<&str>, Some(additional_metadata_mime)); + + + let file_str = match serde_json::to_string(¶m_file) { + Ok(str) => str, + Err(e) => return Box::new(futures::done(Err(ApiError(format!("Unable to parse file to string: {}", e))))), + }; + + let file_vec = file_str.as_bytes().to_vec(); + + let file_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); + + let file_cursor = Cursor::new(file_vec); + + multipart.add_stream("file", file_cursor, None as Option<&str>, Some(file_mime)); + + + 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(); + fields.to_body().read_to_string(&mut body_string).unwrap(); + let boundary = fields.boundary(); + + let multipart_header = match 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.set_body(body_string.into_bytes()); + request.headers_mut().set(ContentType(multipart_header)); + - 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())); - - Box::new(self.client_service.call(request) .map_err(|e| ApiError(format!("No response received: {}", e))) .and_then(|mut response| { @@ -1940,8 +1940,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| { @@ -2018,7 +2016,6 @@ if let Some(body) = body { request.headers_mut().set(ApiKey(api_key.to_string())); } } - Box::new(self.client_service.call(request) .map_err(|e| ApiError(format!("No response received: {}", e))) .and_then(|mut response| { @@ -2093,8 +2090,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| { @@ -2187,14 +2182,11 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Post, uri); let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::PLACE_ORDER.clone())); + 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| { @@ -2277,17 +2269,13 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Post, uri); - // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::CREATE_USER.clone())); + 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| { @@ -2348,14 +2336,11 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Post, uri); let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::CREATE_USERS_WITH_ARRAY_INPUT.clone())); + 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| { @@ -2416,14 +2401,11 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Post, uri); let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::CREATE_USERS_WITH_LIST_INPUT.clone())); + 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| { @@ -2485,8 +2467,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| { @@ -2557,8 +2537,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| { @@ -2654,8 +2632,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| { @@ -2750,8 +2726,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| { @@ -2812,14 +2786,11 @@ if let Some(body) = body { let mut request = hyper::Request::new(hyper::Method::Put, uri); let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::UPDATE_USER.clone())); + 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/output/petstore-with-fake-endpoints-models-for-testing/src/lib.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/lib.rs index 026ca6ef5de7..479be7ad6524 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/lib.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/lib.rs @@ -11,6 +11,7 @@ extern crate chrono; extern crate lazy_static; #[macro_use] extern crate log; +extern crate mime; // Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module. #[cfg(any(feature = "client", feature = "server"))] diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/mod.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/mod.rs index 898516f3f25d..c29765490055 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/mod.rs @@ -5,11 +5,11 @@ extern crate native_tls; extern crate hyper_tls; extern crate openssl; extern crate mime; -extern crate uuid; extern crate chrono; extern crate percent_encoding; extern crate url; - +extern crate uuid; +extern crate multipart; use std::sync::Arc; use std::marker::PhantomData; @@ -19,7 +19,9 @@ 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 std::fs; use serde_json; use serde_xml_rs; @@ -211,12 +213,6 @@ where // TestSpecialTags - PATCH /another-fake/dummy &hyper::Method::Patch if path.matched(paths::ID_ANOTHER_FAKE_DUMMY) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -224,12 +220,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -237,7 +230,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -245,8 +237,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.test_special_tags(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -285,25 +275,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // FakeOuterBooleanSerialize - POST /fake/outer/boolean &hyper::Method::Post if path.matched(paths::ID_FAKE_OUTER_BOOLEAN) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -311,26 +291,19 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, - Err(_) => None, } - } else { None }; - - Box::new(api_impl.fake_outer_boolean_serialize(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -369,25 +342,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // FakeOuterCompositeSerialize - POST /fake/outer/composite &hyper::Method::Post if path.matched(paths::ID_FAKE_OUTER_COMPOSITE) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -395,26 +358,19 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, - Err(_) => None, } - } else { None }; - - Box::new(api_impl.fake_outer_composite_serialize(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -453,25 +409,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // FakeOuterNumberSerialize - POST /fake/outer/number &hyper::Method::Post if path.matched(paths::ID_FAKE_OUTER_NUMBER) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -479,26 +425,19 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, - Err(_) => None, } - } else { None }; - - Box::new(api_impl.fake_outer_number_serialize(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -537,25 +476,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // FakeOuterStringSerialize - POST /fake/outer/string &hyper::Method::Post if path.matched(paths::ID_FAKE_OUTER_STRING) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -563,26 +492,19 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, - Err(_) => None, } - } else { None }; - - Box::new(api_impl.fake_outer_string_serialize(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -621,28 +543,18 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // TestBodyWithQueryParams - PUT /fake/body-with-query-params &hyper::Method::Put if path.matched(paths::ID_FAKE_BODY_WITH_QUERY_PARAMS) => { - - - - - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect::>(); let param_query = query_params.iter().filter(|e| e.0 == "query").map(|e| e.1.to_owned()) - .nth(0); let param_query = match param_query { Some(param_query) => match param_query.parse::() { @@ -651,8 +563,6 @@ where }, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required query parameter query"))), }; - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -660,12 +570,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -673,7 +580,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -681,8 +587,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.test_body_with_query_params(param_query, param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -713,25 +617,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // TestClientModel - PATCH /fake &hyper::Method::Patch if path.matched(paths::ID_FAKE) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -739,12 +633,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -752,7 +643,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -760,8 +650,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.test_client_model(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -800,17 +688,13 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // TestEndpointParameters - POST /fake &hyper::Method::Post if path.matched(paths::ID_FAKE) => { { @@ -822,16 +706,8 @@ where }; } - - - - - - - Box::new({ {{ - // Form parameters let param_integer = Some(56); let param_int32 = Some(56); @@ -847,7 +723,6 @@ where let param_date_time = None; let param_password = Some("password_example".to_string()); let param_callback = Some("callback_example".to_string()); - 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(); @@ -881,27 +756,17 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // TestEnumParameters - GET /fake &hyper::Method::Get if path.matched(paths::ID_FAKE) => { - - - // Header parameters header! { (RequestEnumHeaderStringArray, "enum_header_string_array") => (String)* } let param_enum_header_string_array = headers.get::().map(|header| header.0.clone()); header! { (RequestEnumHeaderString, "enum_header_string") => [String] } let param_enum_header_string = headers.get::().map(|header| header.0.clone()); - - - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect::>(); let param_enum_query_string_array = query_params.iter().filter(|e| e.0 == "enum_query_string_array").map(|e| e.1.to_owned()) @@ -913,29 +778,21 @@ where None }; let param_enum_query_string = query_params.iter().filter(|e| e.0 == "enum_query_string").map(|e| e.1.to_owned()) - .nth(0); let param_enum_query_string = param_enum_query_string.and_then(|param_enum_query_string| param_enum_query_string.parse::<>().ok()); let param_enum_query_integer = query_params.iter().filter(|e| e.0 == "enum_query_integer").map(|e| e.1.to_owned()) - .nth(0); let param_enum_query_integer = param_enum_query_integer.and_then(|param_enum_query_integer| param_enum_query_integer.parse::<>().ok()); let param_enum_query_double = query_params.iter().filter(|e| e.0 == "enum_query_double").map(|e| e.1.to_owned()) - .nth(0); let param_enum_query_double = param_enum_query_double.and_then(|param_enum_query_double| param_enum_query_double.parse::<>().ok()); - - - Box::new({ {{ - // 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(); @@ -969,22 +826,12 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // TestInlineAdditionalProperties - POST /fake/inline-additionalProperties &hyper::Method::Post if path.matched(paths::ID_FAKE_INLINE_ADDITIONALPROPERTIES) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -992,12 +839,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_param: Option> = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -1005,7 +849,6 @@ where Ok(param_param) => param_param, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter param - doesn't match schema: {}", e)))), } - } else { None }; @@ -1013,8 +856,6 @@ where Some(param_param) => param_param, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter param"))), }; - - Box::new(api_impl.test_inline_additional_properties(param_param, &context) .then(move |result| { let mut response = Response::new(); @@ -1045,33 +886,20 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter param: {}", e)))), } }) ) as Box> - }, - // TestJsonFormData - GET /fake/jsonFormData &hyper::Method::Get if path.matched(paths::ID_FAKE_JSONFORMDATA) => { - - - - - - - Box::new({ {{ - // Form parameters let param_param = "param_example".to_string(); let param_param2 = "param2_example".to_string(); - Box::new(api_impl.test_json_form_data(param_param, param_param2, &context) .then(move |result| { let mut response = Response::new(); @@ -1098,14 +926,10 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // TestClassname - PATCH /fake_classname_test &hyper::Method::Patch if path.matched(paths::ID_FAKE_CLASSNAME_TEST) => { { @@ -1117,12 +941,6 @@ where }; } - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -1130,12 +948,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -1143,7 +958,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -1151,8 +965,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.test_classname(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -1191,17 +1003,13 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // AddPet - POST /pet &hyper::Method::Post if path.matched(paths::ID_PET) => { { @@ -1231,12 +1039,6 @@ where } } } - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -1244,11 +1046,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -1256,7 +1056,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -1264,8 +1063,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.add_pet(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -1296,17 +1093,13 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // DeletePet - DELETE /pet/{petId} &hyper::Method::Delete if path.matched(paths::ID_PET_PETID) => { { @@ -1336,8 +1129,6 @@ where } } } - - // Path parameters let path = uri.path().to_string(); let path_params = @@ -1346,7 +1137,6 @@ where .unwrap_or_else(|| panic!("Path {} matched RE PET_PETID in set but failed match against \"{}\"", path, paths::REGEX_PET_PETID.as_str()) ); - let param_pet_id = match percent_encoding::percent_decode(path_params["petId"].as_bytes()).decode_utf8() { Ok(param_pet_id) => match param_pet_id.parse::() { Ok(param_pet_id) => param_pet_id, @@ -1354,18 +1144,11 @@ where }, Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"])))) }; - // Header parameters header! { (RequestApiKey, "api_key") => [String] } let param_api_key = headers.get::().map(|header| header.0.clone()); - - - - - Box::new({ {{ - Box::new(api_impl.delete_pet(param_pet_id, param_api_key, &context) .then(move |result| { let mut response = Response::new(); @@ -1392,14 +1175,10 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // FindPetsByStatus - GET /pet/findByStatus &hyper::Method::Get if path.matched(paths::ID_PET_FINDBYSTATUS) => { { @@ -1429,22 +1208,13 @@ where } } } - - - - - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect::>(); let param_status = query_params.iter().filter(|e| e.0 == "status").map(|e| e.1.to_owned()) .filter_map(|param_status| param_status.parse::().ok()) .collect::>(); - - - Box::new({ {{ - Box::new(api_impl.find_pets_by_status(param_status.as_ref(), &context) .then(move |result| { let mut response = Response::new(); @@ -1486,14 +1256,10 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // FindPetsByTags - GET /pet/findByTags &hyper::Method::Get if path.matched(paths::ID_PET_FINDBYTAGS) => { { @@ -1523,22 +1289,13 @@ where } } } - - - - - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect::>(); let param_tags = query_params.iter().filter(|e| e.0 == "tags").map(|e| e.1.to_owned()) .filter_map(|param_tags| param_tags.parse::().ok()) .collect::>(); - - - Box::new({ {{ - Box::new(api_impl.find_pets_by_tags(param_tags.as_ref(), &context) .then(move |result| { let mut response = Response::new(); @@ -1580,14 +1337,10 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // GetPetById - GET /pet/{petId} &hyper::Method::Get if path.matched(paths::ID_PET_PETID) => { { @@ -1599,8 +1352,6 @@ where }; } - - // Path parameters let path = uri.path().to_string(); let path_params = @@ -1609,7 +1360,6 @@ where .unwrap_or_else(|| panic!("Path {} matched RE PET_PETID in set but failed match against \"{}\"", path, paths::REGEX_PET_PETID.as_str()) ); - let param_pet_id = match percent_encoding::percent_decode(path_params["petId"].as_bytes()).decode_utf8() { Ok(param_pet_id) => match param_pet_id.parse::() { Ok(param_pet_id) => param_pet_id, @@ -1617,14 +1367,8 @@ where }, Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"])))) }; - - - - - Box::new({ {{ - Box::new(api_impl.get_pet_by_id(param_pet_id, &context) .then(move |result| { let mut response = Response::new(); @@ -1673,14 +1417,10 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // UpdatePet - PUT /pet &hyper::Method::Put if path.matched(paths::ID_PET) => { { @@ -1710,12 +1450,6 @@ where } } } - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -1723,11 +1457,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -1735,7 +1467,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -1743,8 +1474,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.update_pet(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -1789,17 +1518,13 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // UpdatePetWithForm - POST /pet/{petId} &hyper::Method::Post if path.matched(paths::ID_PET_PETID) => { { @@ -1829,8 +1554,6 @@ where } } } - - // Path parameters let path = uri.path().to_string(); let path_params = @@ -1839,7 +1562,6 @@ where .unwrap_or_else(|| panic!("Path {} matched RE PET_PETID in set but failed match against \"{}\"", path, paths::REGEX_PET_PETID.as_str()) ); - let param_pet_id = match percent_encoding::percent_decode(path_params["petId"].as_bytes()).decode_utf8() { Ok(param_pet_id) => match param_pet_id.parse::() { Ok(param_pet_id) => param_pet_id, @@ -1847,18 +1569,11 @@ where }, Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"])))) }; - - - - - Box::new({ {{ - // Form parameters let param_name = Some("name_example".to_string()); let param_status = Some("status_example".to_string()); - Box::new(api_impl.update_pet_with_form(param_pet_id, param_name, param_status, &context) .then(move |result| { let mut response = Response::new(); @@ -1885,14 +1600,10 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // UploadFile - POST /pet/{petId}/uploadImage &hyper::Method::Post if path.matched(paths::ID_PET_PETID_UPLOADIMAGE) => { { @@ -1922,8 +1633,10 @@ 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"))), + }; // Path parameters let path = uri.path().to_string(); let path_params = @@ -1932,7 +1645,6 @@ where .unwrap_or_else(|| panic!("Path {} matched RE PET_PETID_UPLOADIMAGE in set but failed match against \"{}\"", path, paths::REGEX_PET_PETID_UPLOADIMAGE.as_str()) ); - let param_pet_id = match percent_encoding::percent_decode(path_params["petId"].as_bytes()).decode_utf8() { Ok(param_pet_id) => match param_pet_id.parse::() { Ok(param_pet_id) => param_pet_id, @@ -1940,18 +1652,48 @@ where }, Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"])))) }; + // Form Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + Box::new(body.concat2() + .then(move |result| -> Box> { + match result { + Ok(body) => { + // Read Form Parameters from 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")))) + }, + }; + + + let file_additional_metadata = entries.files.remove("additional_metadata"); + let param_additional_metadata = match file_additional_metadata { + Some(file) => { + let path = &file[0].path; + let additional_metadata_str = fs::read_to_string(path).unwrap(); + let additional_metadata_model: String = serde_json::from_str(&additional_metadata_str).expect("Impossible to fail to serialise"); + Some(additional_metadata_model) + } + None => None, + }; + - - - - - Box::new({ - {{ - - // Form parameters - let param_additional_metadata = Some("additional_metadata_example".to_string()); - let param_file = Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE"))); - + + let file_file = entries.files.remove("file"); + let param_file = match file_file { + Some(file) => { + let path = &file[0].path; + let file_str = fs::read_to_string(path).unwrap(); + let file_model: swagger::ByteArray = serde_json::from_str(&file_str).expect("Impossible to fail to serialise"); + Some(file_model) + } + None => None, + }; + Box::new(api_impl.upload_file(param_pet_id, param_additional_metadata, param_file, &context) .then(move |result| { let mut response = Response::new(); @@ -1986,18 +1728,16 @@ where future::ok(response) } )) - - }} - }) as Box> - - + as Box> + }, + Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))), + } + }) + ) }, - // DeleteOrder - DELETE /store/order/{order_id} &hyper::Method::Delete if path.matched(paths::ID_STORE_ORDER_ORDER_ID) => { - - // Path parameters let path = uri.path().to_string(); let path_params = @@ -2006,7 +1746,6 @@ where .unwrap_or_else(|| panic!("Path {} matched RE STORE_ORDER_ORDER_ID in set but failed match against \"{}\"", path, paths::REGEX_STORE_ORDER_ORDER_ID.as_str()) ); - let param_order_id = match percent_encoding::percent_decode(path_params["order_id"].as_bytes()).decode_utf8() { Ok(param_order_id) => match param_order_id.parse::() { Ok(param_order_id) => param_order_id, @@ -2014,14 +1753,8 @@ where }, Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["order_id"])))) }; - - - - - Box::new({ {{ - Box::new(api_impl.delete_order(param_order_id, &context) .then(move |result| { let mut response = Response::new(); @@ -2055,14 +1788,10 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // GetInventory - GET /store/inventory &hyper::Method::Get if path.matched(paths::ID_STORE_INVENTORY) => { { @@ -2074,16 +1803,8 @@ where }; } - - - - - - - Box::new({ {{ - Box::new(api_impl.get_inventory(&context) .then(move |result| { let mut response = Response::new(); @@ -2118,18 +1839,12 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // GetOrderById - GET /store/order/{order_id} &hyper::Method::Get if path.matched(paths::ID_STORE_ORDER_ORDER_ID) => { - - // Path parameters let path = uri.path().to_string(); let path_params = @@ -2138,7 +1853,6 @@ where .unwrap_or_else(|| panic!("Path {} matched RE STORE_ORDER_ORDER_ID in set but failed match against \"{}\"", path, paths::REGEX_STORE_ORDER_ORDER_ID.as_str()) ); - let param_order_id = match percent_encoding::percent_decode(path_params["order_id"].as_bytes()).decode_utf8() { Ok(param_order_id) => match param_order_id.parse::() { Ok(param_order_id) => param_order_id, @@ -2146,14 +1860,8 @@ where }, Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["order_id"])))) }; - - - - - Box::new({ {{ - Box::new(api_impl.get_order_by_id(param_order_id, &context) .then(move |result| { let mut response = Response::new(); @@ -2202,22 +1910,12 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // PlaceOrder - POST /store/order &hyper::Method::Post if path.matched(paths::ID_STORE_ORDER) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -2225,12 +1923,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -2238,7 +1933,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -2246,8 +1940,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.place_order(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -2293,25 +1985,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // CreateUser - POST /user &hyper::Method::Post if path.matched(paths::ID_USER) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -2319,12 +2001,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -2332,7 +2011,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -2340,8 +2018,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.create_user(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -2372,25 +2048,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // CreateUsersWithArrayInput - POST /user/createWithArray &hyper::Method::Post if path.matched(paths::ID_USER_CREATEWITHARRAY) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -2398,12 +2064,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option> = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -2411,7 +2074,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -2419,8 +2081,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.create_users_with_array_input(param_body.as_ref(), &context) .then(move |result| { let mut response = Response::new(); @@ -2451,25 +2111,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // CreateUsersWithListInput - POST /user/createWithList &hyper::Method::Post if path.matched(paths::ID_USER_CREATEWITHLIST) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -2477,12 +2127,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option> = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -2490,7 +2137,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -2498,8 +2144,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.create_users_with_list_input(param_body.as_ref(), &context) .then(move |result| { let mut response = Response::new(); @@ -2530,21 +2174,15 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // DeleteUser - DELETE /user/{username} &hyper::Method::Delete if path.matched(paths::ID_USER_USERNAME) => { - - // Path parameters let path = uri.path().to_string(); let path_params = @@ -2553,7 +2191,6 @@ where .unwrap_or_else(|| panic!("Path {} matched RE USER_USERNAME in set but failed match against \"{}\"", path, paths::REGEX_USER_USERNAME.as_str()) ); - let param_username = match percent_encoding::percent_decode(path_params["username"].as_bytes()).decode_utf8() { Ok(param_username) => match param_username.parse::() { Ok(param_username) => param_username, @@ -2561,14 +2198,8 @@ where }, Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["username"])))) }; - - - - - Box::new({ {{ - Box::new(api_impl.delete_user(param_username, &context) .then(move |result| { let mut response = Response::new(); @@ -2602,18 +2233,12 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // GetUserByName - GET /user/{username} &hyper::Method::Get if path.matched(paths::ID_USER_USERNAME) => { - - // Path parameters let path = uri.path().to_string(); let path_params = @@ -2622,7 +2247,6 @@ where .unwrap_or_else(|| panic!("Path {} matched RE USER_USERNAME in set but failed match against \"{}\"", path, paths::REGEX_USER_USERNAME.as_str()) ); - let param_username = match percent_encoding::percent_decode(path_params["username"].as_bytes()).decode_utf8() { Ok(param_username) => match param_username.parse::() { Ok(param_username) => param_username, @@ -2630,14 +2254,8 @@ where }, Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["username"])))) }; - - - - - Box::new({ {{ - Box::new(api_impl.get_user_by_name(param_username, &context) .then(move |result| { let mut response = Response::new(); @@ -2686,25 +2304,15 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // LoginUser - GET /user/login &hyper::Method::Get if path.matched(paths::ID_USER_LOGIN) => { - - - - - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect::>(); let param_username = query_params.iter().filter(|e| e.0 == "username").map(|e| e.1.to_owned()) - .nth(0); let param_username = match param_username { Some(param_username) => match param_username.parse::() { @@ -2714,7 +2322,6 @@ where None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required query parameter username"))), }; let param_password = query_params.iter().filter(|e| e.0 == "password").map(|e| e.1.to_owned()) - .nth(0); let param_password = match param_password { Some(param_password) => match param_password.parse::() { @@ -2723,12 +2330,8 @@ where }, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required query parameter password"))), }; - - - Box::new({ {{ - Box::new(api_impl.login_user(param_username, param_password, &context) .then(move |result| { let mut response = Response::new(); @@ -2779,26 +2382,14 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // LogoutUser - GET /user/logout &hyper::Method::Get if path.matched(paths::ID_USER_LOGOUT) => { - - - - - - - Box::new({ {{ - Box::new(api_impl.logout_user(&context) .then(move |result| { let mut response = Response::new(); @@ -2825,18 +2416,12 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // UpdateUser - PUT /user/{username} &hyper::Method::Put if path.matched(paths::ID_USER_USERNAME) => { - - // Path parameters let path = uri.path().to_string(); let path_params = @@ -2845,7 +2430,6 @@ where .unwrap_or_else(|| panic!("Path {} matched RE USER_USERNAME in set but failed match against \"{}\"", path, paths::REGEX_USER_USERNAME.as_str()) ); - let param_username = match percent_encoding::percent_decode(path_params["username"].as_bytes()).decode_utf8() { Ok(param_username) => match param_username.parse::() { Ok(param_username) => param_username, @@ -2853,10 +2437,6 @@ where }, Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["username"])))) }; - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -2864,12 +2444,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -2877,7 +2454,6 @@ where Ok(param_body) => param_body, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter body - doesn't match schema: {}", e)))), } - } else { None }; @@ -2885,8 +2461,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.update_user(param_username, param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -2924,17 +2498,13 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - _ => Box::new(future::ok(Response::new().with_status(StatusCode::NotFound))) as Box>, } } @@ -2950,6 +2520,18 @@ impl Clone for Service } } +/// 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_() == hyper::mime::MULTIPART && mime.subtype() == hyper::mime::FORM_DATA { + mime.get_param(hyper::mime::BOUNDARY).map(|x| x.as_str()) + } else { + None + } + }) +} + /// Request parser for `Api`. pub struct ApiRequestParser; impl RequestParser for ApiRequestParser { diff --git a/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml b/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml index 3a837e477ea4..bfae24310b9e 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml +++ b/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml @@ -23,8 +23,8 @@ swagger = "2" # lazy_static = "0.2" log = "0.3.0" -mime = "0.3.3" -multipart = {version = "0.13.3", optional = true} +mime = "0.2.6" +multipart = {version = "0.13.3"} native-tls = {version = "0.1.4", optional = true} openssl = {version = "0.9.14", optional = true} percent-encoding = {version = "1.0.0", optional = true} diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs index 0835b2a79c3c..64b47aa5f242 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs @@ -7,8 +7,6 @@ extern crate mime; extern crate chrono; extern crate url; - - use hyper; use hyper::header::{Headers, ContentType}; use hyper::Uri; @@ -26,12 +24,9 @@ use std::sync::Arc; use std::str; use std::str::FromStr; use std::string::ToString; - use mimetypes; - use serde_json; - #[allow(unused_imports)] use std::collections::{HashMap, BTreeMap}; #[allow(unused_imports)] @@ -274,8 +269,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| { @@ -336,14 +329,11 @@ impl Api for Client where let mut request = hyper::Request::new(hyper::Method::Put, uri); let body = serde_json::to_string(¶m_nested_response).expect("impossible to fail to serialize"); - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::DUMMY_PUT.clone())); + 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| { @@ -405,8 +395,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| { @@ -480,14 +468,11 @@ impl Api for Client where let mut request = hyper::Request::new(hyper::Method::Post, uri); let body = param_body; - request.set_body(body); - request.headers_mut().set(ContentType(mimetypes::requests::HTML_POST.clone())); + 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| { @@ -562,8 +547,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| { diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs index 5f9e44062b09..b8d7ed225b3d 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs @@ -11,6 +11,7 @@ extern crate chrono; extern crate lazy_static; #[macro_use] extern crate log; +extern crate mime; // Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module. #[cfg(any(feature = "client", feature = "server"))] diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs index 1312c9d01836..f3dfff3a1d10 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs @@ -5,11 +5,10 @@ extern crate native_tls; extern crate hyper_tls; extern crate openssl; extern crate mime; -extern crate uuid; extern crate chrono; extern crate percent_encoding; extern crate url; - +extern crate uuid; use std::sync::Arc; use std::marker::PhantomData; @@ -19,10 +18,8 @@ use hyper::{Request, Response, Error, StatusCode}; use hyper::header::{Headers, ContentType}; use self::url::form_urlencoded; use mimetypes; - use serde_json; - #[allow(unused_imports)] use std::collections::{HashMap, BTreeMap}; #[allow(unused_imports)] @@ -132,16 +129,8 @@ where // DummyGet - GET /dummy &hyper::Method::Get if path.matched(paths::ID_DUMMY) => { - - - - - - - Box::new({ {{ - Box::new(api_impl.dummy_get(&context) .then(move |result| { let mut response = Response::new(); @@ -168,22 +157,12 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // DummyPut - PUT /dummy &hyper::Method::Put if path.matched(paths::ID_DUMMY) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -191,12 +170,9 @@ where .then(move |result| -> Box> { match result { Ok(body) => { - let mut unused_elements = Vec::new(); let param_nested_response: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&*body); - match serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); @@ -204,7 +180,6 @@ where Ok(param_nested_response) => param_nested_response, Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter nested_response - doesn't match schema: {}", e)))), } - } else { None }; @@ -212,8 +187,6 @@ where Some(param_nested_response) => param_nested_response, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter nested_response"))), }; - - Box::new(api_impl.dummy_put(param_nested_response, &context) .then(move |result| { let mut response = Response::new(); @@ -244,29 +217,17 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter nested_response: {}", e)))), } }) ) as Box> - }, - // FileResponseGet - GET /file_response &hyper::Method::Get if path.matched(paths::ID_FILE_RESPONSE) => { - - - - - - - Box::new({ {{ - Box::new(api_impl.file_response_get(&context) .then(move |result| { let mut response = Response::new(); @@ -301,22 +262,12 @@ where future::ok(response) } )) - }} }) as Box> - - }, - // HtmlPost - POST /html &hyper::Method::Post if path.matched(paths::ID_HTML) => { - - - - - - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. @@ -325,9 +276,7 @@ where match result { Ok(body) => { let param_body: Option = if !body.is_empty() { - Some(String::from_utf8(body.to_vec()).unwrap()) - } else { None }; @@ -335,8 +284,6 @@ where Some(param_body) => param_body, None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter body"))), }; - - Box::new(api_impl.html_post(param_body, &context) .then(move |result| { let mut response = Response::new(); @@ -371,29 +318,17 @@ where future::ok(response) } )) - - }, Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter body: {}", e)))), } }) ) as Box> - }, - // RawJsonGet - GET /raw_json &hyper::Method::Get if path.matched(paths::ID_RAW_JSON) => { - - - - - - - Box::new({ {{ - Box::new(api_impl.raw_json_get(&context) .then(move |result| { let mut response = Response::new(); @@ -428,14 +363,10 @@ where future::ok(response) } )) - }} }) as Box> - - }, - _ => Box::new(future::ok(Response::new().with_status(StatusCode::NotFound))) as Box>, } } @@ -451,6 +382,7 @@ impl Clone for Service } } + /// Request parser for `Api`. pub struct ApiRequestParser; impl RequestParser for ApiRequestParser {