diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java index 3e4619f27af2..06bc5de749de 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java @@ -23,7 +23,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties { public boolean isFormParam, isQueryParam, isPathParam, isHeaderParam, isCookieParam, isBodyParam, hasMore, isContainer, secondaryParam, isCollectionFormatMulti, isPrimitiveType, isModel, isExplode; - public String baseName, paramName, dataType, datatypeWithEnum, dataFormat, + public String baseName, paramName, dataType, datatypeWithEnum, dataFormat, contentType, collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName, style; public String nameInLowerCase; // property name in lower case @@ -178,13 +178,14 @@ public class CodegenParameter implements IJsonSchemaValidationProperties { output.isMapContainer = this.isMapContainer; output.isExplode = this.isExplode; output.style = this.style; + output.contentType = this.contentType; return output; } @Override public int hashCode() { - return Objects.hash(isFormParam, isQueryParam, isPathParam, isHeaderParam, isCookieParam, isBodyParam, hasMore, isContainer, secondaryParam, isCollectionFormatMulti, isPrimitiveType, isModel, isExplode, baseName, paramName, dataType, datatypeWithEnum, dataFormat, collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName, style, example, jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isFreeFormObject, isListContainer, isMapContainer, isFile, isEnum, _enum, allowableValues, items, mostInnerItems, vendorExtensions, hasValidation, getMaxProperties(), getMinProperties(), isNullable, required, getMaximum(), getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(), getMaxLength(), getMinLength(), getPattern(), getMaxItems(), getMinItems(), getUniqueItems(), multipleOf); + return Objects.hash(isFormParam, isQueryParam, isPathParam, isHeaderParam, isCookieParam, isBodyParam, hasMore, isContainer, secondaryParam, isCollectionFormatMulti, isPrimitiveType, isModel, isExplode, baseName, paramName, dataType, datatypeWithEnum, dataFormat, collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName, style, example, jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isFreeFormObject, isListContainer, isMapContainer, isFile, isEnum, _enum, allowableValues, items, mostInnerItems, vendorExtensions, hasValidation, getMaxProperties(), getMinProperties(), isNullable, required, getMaximum(), getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(), getMaxLength(), getMinLength(), getPattern(), getMaxItems(), getMinItems(), getUniqueItems(), contentType, multipleOf); } @Override @@ -259,6 +260,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties { Objects.equals(getPattern(), that.getPattern()) && Objects.equals(getMaxItems(), that.getMaxItems()) && Objects.equals(getMinItems(), that.getMinItems()) && + Objects.equals(contentType, that.contentType) && Objects.equals(multipleOf, that.multipleOf); } @@ -332,6 +334,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties { sb.append(", maxItems=").append(maxItems); sb.append(", minItems=").append(minItems); sb.append(", uniqueItems=").append(uniqueItems); + sb.append(", contentType=").append(contentType); sb.append(", multipleOf=").append(multipleOf); sb.append('}'); return sb.toString(); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 45677bb61e6a..18c71a797d50 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -1511,6 +1511,23 @@ public class DefaultCodegen implements CodegenConfig { setParameterExampleValue(codegenParameter); } + /** + * Sets the content type of the parameter based on the encoding specified in the request body. + * + * @param codegenParameter Codegen parameter + * @param mediaType MediaType from the request body + */ + public void setParameterContentType(CodegenParameter codegenParameter, MediaType mediaType) { + if (mediaType != null && mediaType.getEncoding() != null) { + Encoding encoding = mediaType.getEncoding().get(codegenParameter.baseName); + if (encoding != null) { + codegenParameter.contentType = encoding.getContentType(); + } else { + LOGGER.debug("encoding not specified for " + codegenParameter.baseName); + } + } + } + /** * Return the example value of the property * @@ -2879,13 +2896,17 @@ public class DefaultCodegen implements CodegenConfig { RequestBody requestBody = operation.getRequestBody(); if (requestBody != null) { String contentType = getContentType(requestBody); + if (contentType != null) { + contentType = contentType.toLowerCase(Locale.ROOT); + } if (contentType != null && - (contentType.toLowerCase(Locale.ROOT).startsWith("application/x-www-form-urlencoded") || - contentType.toLowerCase(Locale.ROOT).startsWith("multipart"))) { + (contentType.startsWith("application/x-www-form-urlencoded") || + contentType.startsWith("multipart"))) { // process form parameters formParams = fromRequestBodyToFormParameters(requestBody, imports); - op.isMultipart = contentType.toLowerCase(Locale.ROOT).startsWith("multipart"); + op.isMultipart = contentType.startsWith("multipart"); for (CodegenParameter cp : formParams) { + setParameterContentType(cp, requestBody.getContent().get(contentType)); postProcessParameter(cp); } // add form parameters to the beginning of all parameter list 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 c72d079bc9b8..02124094c47f 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 @@ -544,6 +544,10 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig { return mimetype.toLowerCase(Locale.ROOT).startsWith(octetMimeType); } + private boolean isMimetypeMultipartRelated(String mimetype) { + return mimetype.toLowerCase(Locale.ROOT).startsWith("multipart/related"); + } + private boolean isMimetypePlain(String mimetype) { return isMimetypePlainText(mimetype) || isMimetypeHtmlText(mimetype) || isMimetypeOctetStream(mimetype); } @@ -847,6 +851,11 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig { additionalProperties.put("usesUrlEncodedForm", true); } else if (isMimetypeMultipartFormData(mediaType)) { op.vendorExtensions.put("consumesMultipart", true); + additionalProperties.put("apiUsesMultipartFormData", true); + additionalProperties.put("apiUsesMultipart", true); + } else if (isMimetypeMultipartRelated(mediaType)) { + op.vendorExtensions.put("consumesMultipartRelated", true); + additionalProperties.put("apiUsesMultipartRelated", true); additionalProperties.put("apiUsesMultipart", true); } } 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 d4b7a0896684..2ef5dbbb1419 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache @@ -11,8 +11,14 @@ license = "Unlicense" default = ["client", "server"] client = [ {{#apiUsesMultipart}} - "multipart", "multipart/client", "swagger/multipart", + "mime_0_2", {{/apiUsesMultipart}} +{{#apiUsesMultipartFormData}} + "multipart", "multipart/client", "swagger/multipart", +{{/apiUsesMultipartFormData}} + {{#apiUsesMultipartRelated}} + "hyper_0_10", "mime_multipart", +{{/apiUsesMultipartRelated}} {{#usesUrlEncodedForm}} "serde_urlencoded", {{/usesUrlEncodedForm}} @@ -20,8 +26,14 @@ client = [ ] server = [ {{#apiUsesMultipart}} - "multipart", "multipart/server", + "mime_0_2", {{/apiUsesMultipart}} +{{#apiUsesMultipartFormData}} + "multipart", "multipart/server", +{{/apiUsesMultipartFormData}} +{{#apiUsesMultipartRelated}} + "hyper_0_10", "mime_multipart", +{{/apiUsesMultipartRelated}} "serde_json", "serde_ignored", "hyper", "native-tls", "openssl", "tokio", "tokio-tls", "regex", "percent-encoding", "url", "lazy_static" ] conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] @@ -44,9 +56,11 @@ serde_derive = "1.0" serde-xml-rs = {git = "git://github.com/Metaswitch/serde-xml-rs.git" , branch = "master"} {{/usesXml}} {{#apiUsesMultipart}} -mime_0_2 = { package = "mime", version = "0.2.6" } -multipart = { version = "0.16", default-features = false, optional = true } +mime_0_2 = { package = "mime", version = "0.2.6", optional = true } {{/apiUsesMultipart}} +{{#apiUsesMultipartFormData}} +multipart = { version = "0.16", default-features = false, optional = true } +{{/apiUsesMultipartFormData}} {{#apiUsesUuid}} uuid = {version = "0.7", features = ["serde", "v4"]} {{/apiUsesUuid}} @@ -54,6 +68,10 @@ uuid = {version = "0.7", features = ["serde", "v4"]} # Common between server and client features hyper = {version = "0.12", optional = true} hyper-tls = {version = "0.2.1", optional = true} +{{#apiUsesMultipartRelated}} +mime_multipart = {version = "0.5", optional = true} +hyper_0_10 = {package = "hyper", version = "0.10", default-features = false, optional=true} +{{/apiUsesMultipartRelated}} native-tls = {version = "0.1.4", optional = true} openssl = {version = "0.9.14", optional = true} serde_json = {version = "1.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 0d724d598594..8b7b2ecea995 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 @@ -25,11 +25,16 @@ use swagger; use swagger::{ApiError, XSpanIdString, Has, AuthData}; use swagger::client::Service; -{{#apiUsesMultipart}} +{{#apiUsesMultipartFormData}} use mime::Mime; use std::io::Cursor; use multipart::client::lazy::Multipart; -{{/apiUsesMultipart}} +{{/apiUsesMultipartFormData}} +{{#apiUsesMultipartRelated}} +use hyper_0_10::header::{Headers, ContentType}; +header! { (ContentId, "Content-ID") => [String] } +use mime_multipart::{Node, Part, generate_boundary, write_multipart}; +{{/apiUsesMultipartRelated}} {{#apiUsesUuid}} use uuid; {{/apiUsesUuid}} @@ -253,7 +258,7 @@ impl Api for Client where {{#vendorExtensions}} {{#consumesMultipart}} - let mut multipart = Multipart::new(); + let mut multipart = Multipart::new(); {{#vendorExtensions}} {{#formParams}} @@ -274,7 +279,7 @@ impl Api for Client where let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec); - multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, None as Option<&str>, Some({{{paramName}}}_mime)); + multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, None as Option<&str>, Some({{{paramName}}}_mime)); {{/jsonSchema}} {{/isByteArray}} {{#isByteArray}} @@ -314,11 +319,10 @@ impl Api for Client where Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", multipart_header, e)))) }); {{/consumesMultipart}} -{{/vendorExtensions}} -{{#vendorExtensions}} {{^consumesMultipart}} {{#vendorExtensions}} - {{#formParams}} + {{^consumesMultipartRelated}} + {{#formParams}} {{#-first}} let params = &[ {{/-first}} @@ -334,7 +338,70 @@ impl Api for Client where }); *request.body_mut() = Body::from(body.into_bytes()); {{/-last}} - {{/formParams}} + {{/formParams}} + {{/consumesMultipartRelated}} + {{#consumesMultipartRelated}} + {{#formParams}} + {{#-first}} + // Construct the Body for a multipart/related request. The mime 0.2.6 library + // does not parse quoted-string parameters correctly. The boundary doesn't + // need to be a quoted string if it does not contain a '/', hence ensure + // no such boundary is used. + let mut boundary = generate_boundary(); + for b in boundary.iter_mut() { + if b == &('/' as u8) { + *b = '=' as u8; + } + } + + let mut body_parts = vec![]; + {{/-first}} + + {{^required}} + if let Some({{{paramName}}}) = param_{{{paramName}}} { + {{/required}} + let part = Node::Part(Part { + headers: { + let mut h = Headers::new(); + h.set(ContentType("{{{contentType}}}".parse().unwrap())); + h.set(ContentId("{{{baseName}}}".parse().unwrap())); + h + }, + {{#isBinary}} + body: {{#required}}param_{{/required}}{{{paramName}}}.0, + {{/isBinary}} + {{^isBinary}} + body: serde_json::to_string(&{{{paramName}}}) + .expect("Impossible to fail to serialize") + .into_bytes(), + {{/isBinary}} + }); + body_parts.push(part); + {{^required}} + } + {{/required}} + {{#-last}} + + // Write the body into a vec. + let mut body: Vec = vec![]; + write_multipart(&mut body, &boundary, &body_parts) + .expect("Failed to write multipart body"); + + // Add the message body to the request object. + *request.body_mut() = Body::from(body); + + let header = &mimetypes::requests::{{#vendorExtensions}}{{{uppercase_operation_id}}}{{/vendorExtensions}}; + request.headers_mut().insert(CONTENT_TYPE, + match HeaderValue::from_bytes( + &[header.as_bytes(), "; boundary=".as_bytes(), &boundary, "; type=\"application/json\"".as_bytes()].concat() + ) { + Ok(h) => h, + Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", header, e)))) + }); + + {{/-last}} + {{/formParams}} + {{/consumesMultipartRelated}} {{/vendorExtensions}} {{#bodyParam}} {{#-first}} 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 23998b4ef99b..56f67e937fca 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/lib.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/lib.mustache @@ -12,6 +12,11 @@ extern crate lazy_static; extern crate url; #[macro_use] extern crate log; +{{#apiUsesMultipartRelated}} +#[cfg(any(feature = "client", feature = "server"))] +#[macro_use] +extern crate hyper_0_10; +{{/apiUsesMultipartRelated}} // Crates for conversion support #[cfg(feature = "conversion")] @@ -35,6 +40,14 @@ extern crate hyper; extern crate hyper_tls; #[cfg(any(feature = "client", feature = "server"))] extern crate openssl; +{{#apiUsesMultipart}} +#[cfg(any(feature = "client", feature = "server"))] +extern crate mime_0_2; +{{/apiUsesMultipart}} +{{#apiUsesMultipartRelated}} +#[cfg(any(feature = "client", feature = "server"))] +extern crate mime_multipart; +{{/apiUsesMultipartRelated}} #[cfg(any(feature = "client", feature = "server"))] extern crate native_tls; #[cfg(feature = "server")] @@ -51,11 +64,10 @@ extern crate tokio; {{#usesXml}}extern crate serde_xml_rs;{{/usesXml}} -{{#apiUsesMultipart}} +{{#apiUsesMultipartFormData}} #[cfg(any(feature = "client", feature = "server"))] extern crate multipart; -extern crate mime_0_2; -{{/apiUsesMultipart}} +{{/apiUsesMultipartFormData}} #[cfg(any(feature = "client", feature = "server"))] {{#usesUrlEncodedForm}}extern crate serde_urlencoded;{{/usesUrlEncodedForm}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/mimetypes.mustache b/modules/openapi-generator/src/main/resources/rust-server/mimetypes.mustache index 9804318e61dd..d0de7d94455d 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/mimetypes.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/mimetypes.mustache @@ -15,5 +15,8 @@ pub mod requests { {{/bodyParam}}{{^bodyParam}}{{#vendorExtensions}}{{#formParams}}{{#-first}} /// Create &str objects for the request content types for {{{operationId}}} pub static {{{uppercase_operation_id}}}: &str = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/x-www-form-urlencoded{{/consumes}}"; -{{/-first}}{{/formParams}}{{/vendorExtensions}}{{/bodyParam}}{{/vendorExtensions.consumesMultipart}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} +{{/-first}}{{/formParams}}{{#relatedParams}}{{#-first}} + /// Create &str objects for the request content types for {{{operationId}}} + pub static {{{uppercase_operation_id}}}: &str = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}multipart/related{{/consumes}}"; +{{/-first}}{{/relatedParams}}{{/vendorExtensions}}{{/bodyParam}}{{/vendorExtensions.consumesMultipart}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} } diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-mod.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-mod.mustache index d0123f012756..bea189c3c7c0 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 @@ -13,10 +13,16 @@ use swagger::{ApiError, XSpanIdString, Has, RequestParser}; use swagger::auth::Scopes; use swagger::context::ContextualPayload; use url::form_urlencoded; -{{#apiUsesMultipart}} +{{#apiUsesMultipartRelated}} +use hyper_0_10::header::{Headers, ContentType}; +header! { (ContentId, "Content-ID") => [String] } +use mime_0_2::{TopLevel, SubLevel, Mime as Mime2}; +use mime_multipart::{read_multipart_body, Node, Part}; +{{/apiUsesMultipartRelated}} +{{#apiUsesMultipartFormData}} use multipart::server::Multipart; use multipart::server::save::SaveResult; -{{/apiUsesMultipart}} +{{/apiUsesMultipartFormData}} {{#usesXml}} use serde_xml_rs; {{/usesXml}} @@ -175,7 +181,7 @@ where } {{/hasAuthMethods}} {{#vendorExtensions}} - {{#consumesMultipart}} + {{#consumesMultipart}} let boundary = match swagger::multipart::boundary(&headers) { Some(boundary) => boundary.to_string(), None => return Box::new(future::ok(Response::builder() @@ -364,7 +370,7 @@ where .expect("Unable to create Bad Request response due to failure to process all message"))) }, }; - {{#formParams}}{{#-first}}{{/-first}} + {{#formParams}} let field_{{{paramName}}} = entries.fields.remove("{{{paramName}}}"); let param_{{{paramName}}} = match field_{{{paramName}}} { Some(field) => { @@ -415,25 +421,131 @@ where {{/vendorExtensions}} {{/bodyParams}} {{/consumesMultipart}} - {{^consumesMultipart}} - {{^bodyParams}} - {{#vendorExtensions}} + {{^consumesMultipartRelated}} + {{^consumesMultipart}} + {{^bodyParams}} + {{#vendorExtensions}} Box::new({ {{ - {{#formParams}} - {{#-first}} + {{#formParams}} + {{#-first}} // Form parameters - {{/-first}} - let param_{{{paramName}}} = + {{/-first}} + let param_{{{paramName}}} = {{^isContainer}}{{#vendorExtensions}}{{{example}}};{{/vendorExtensions}}{{/isContainer}} {{#isListContainer}}{{#required}}Vec::new();{{/required}}{{^required}}None;{{/required}}{{/isListContainer}} {{#isMapContainer}}None;{{/isMapContainer}} - {{/formParams}} - {{/vendorExtensions}} - {{/bodyParams}} - {{/consumesMultipart}} -{{/vendorExtensions}} + {{/formParams}} + {{/vendorExtensions}} + {{/bodyParams}} + {{/consumesMultipart}} + {{/consumesMultipartRelated}} + {{#consumesMultipartRelated}} + // 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| -> Self::Future { + match result { + Ok(body) => { + let mut unused_elements: Vec = vec![]; + // Get multipart chunks. + + // Extract the top-level content type header. + let content_type_mime = headers + .get(CONTENT_TYPE) + .ok_or("Missing content-type header".to_string()) + .and_then(|v| v.to_str().map_err(|e| format!("Couldn't read content-type header value for {{operationId}}: {}", e))) + .and_then(|v| v.parse::().map_err(|_e| format!("Couldn't parse content-type header value for {{operationId}}"))); + + // Insert top-level content type header into a Headers object. + let mut multi_part_headers = Headers::new(); + match content_type_mime { + Ok(content_type_mime) => { + multi_part_headers.set(ContentType(content_type_mime)); + }, + Err(e) => { + return Box::new(future::ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(e)) + .expect("Unable to create Bad Request response due to unable to read content-type header for {{operationId}}"))); + } + } + + // &*body expresses the body as a byteslice, &mut provides a + // mutable reference to that byteslice. + let nodes = match read_multipart_body(&mut&*body, &multi_part_headers, false) { + Ok(nodes) => nodes, + Err(e) => { + return Box::new(future::ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Could not read multipart body for {{operationId}}: {}", e))) + .expect("Unable to create Bad Request response due to unable to read multipart body for {{operationId}}"))); + } + }; + + {{#formParams}} + let mut param_{{{paramName}}} = None; + {{/formParams}} + + for node in nodes { + if let Node::Part(part) = node { + let content_type = part.content_type().map(|x| format!("{}",x)); + match content_type.as_ref().map(|x| x.as_str()) { + {{#formParams}} + {{^isBinary}} + Some("{{{contentType}}}") => { + // Extract JSON part. + let deserializer = &mut serde_json::Deserializer::from_slice(part.body.as_slice()); + let json_data: {{dataType}} = match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in JSON part: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(json_data) => json_data, + Err(e) => return Box::new(future::ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse body parameter {{dataType}} - doesn't match schema: {}", e))) + .expect("Unable to create Bad Request response for invalid body parameter {{dataType}} due to schema"))) + }; + // Push JSON part to return object. + param_{{{paramName}}}.get_or_insert(json_data); + }, + {{/isBinary}} + {{#isBinary}} + Some("{{{contentType}}}") => { + param_{{{paramName}}}.get_or_insert(swagger::ByteArray(part.body)); + }, + {{/isBinary}} + {{/formParams}} + Some(content_type) => { + warn!("Ignoring unknown content type: {}", content_type); + unused_elements.push(content_type.to_string()); + }, + None => { + warn!("Missing content type"); + }, + } + } else { + unimplemented!("No support for handling unexpected parts"); + // unused_elements.push(); + } + } + + // Check that the required multipart chunks are present. + {{#formParams}} + {{#required}} + let param_{{{paramName}}} = match param_required_binary_field { + Some(x) => x, + None => return Box::new(future::ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Missing required multipart/related parameter {{{paramName}}}"))) + .expect("Unable to create Bad Request response for missing multipart/related parameter {{{paramName}}} due to schema"))) + }; + {{/required}} + {{/formParams}} + {{/consumesMultipartRelated}} + {{/vendorExtensions}} Box::new( api_impl.{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}( {{#allParams}} @@ -537,8 +649,23 @@ where {{#vendorExtensions}} {{^consumesMultipart}} {{^bodyParams}} + {{#vendorExtensions}} + {{#consumesMultipartRelated}} + + }, + Err(e) => Box::new(future::ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't read body parameter {{{baseName}}}: {}", e))) + .expect("Unable to create Bad Request response due to unable to read body parameter {{{baseName}}}"))), + } + }) + ) as Self::Future + {{/consumesMultipartRelated}} + {{^consumesMultipartRelated}} }} }) as Self::Future + {{/consumesMultipartRelated}} + {{/vendorExtensions}} {{/bodyParams}} {{/consumesMultipart}} {{/vendorExtensions}} 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 index 70c4e5d46020..b0e929d12114 100644 --- 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 @@ -23,6 +23,33 @@ paths: responses: '201': description: 'OK' + /multipart_related_request: + post: + requestBody: + required: true + content: + multipart/related: # message with binary body part(s) + schema: + $ref: '#/components/schemas/multipart_related_request' + encoding: + object_field: + contentType: application/json + optional_binary_field: + contentType: application/zip + headers: + Content-Id: + schema: + type: string + required_binary_field: + contentType: image/png + headers: + Content-Id: + schema: + type: string + + responses: + '201': + description: 'OK' components: schemas: multipart_request: @@ -49,3 +76,25 @@ components: binary_field: type: string format: byte + multipart_related_request: + type: object + required: + - required_binary_field + properties: + object_field: + type: object + required: + - field_a + properties: + field_a: + type: string + field_b: + type: array + items: + type: string + optional_binary_field: + type: string + format: binary + required_binary_field: + type: string + format: binary diff --git a/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml b/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml index 904866a013e3..b051e31f6c90 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml +++ b/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml @@ -8,11 +8,15 @@ license = "Unlicense" [features] default = ["client", "server"] client = [ + "mime_0_2", "multipart", "multipart/client", "swagger/multipart", + "hyper_0_10", "mime_multipart", "serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio", "url" ] server = [ + "mime_0_2", "multipart", "multipart/server", + "hyper_0_10", "mime_multipart", "serde_json", "serde_ignored", "hyper", "native-tls", "openssl", "tokio", "tokio-tls", "regex", "percent-encoding", "url", "lazy_static" ] conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] @@ -29,12 +33,14 @@ serde = "1.0" serde_derive = "1.0" # Crates included if required by the API definition -mime_0_2 = { package = "mime", version = "0.2.6" } +mime_0_2 = { package = "mime", version = "0.2.6", optional = true } multipart = { version = "0.16", default-features = false, optional = true } # Common between server and client features hyper = {version = "0.12", optional = true} hyper-tls = {version = "0.2.1", optional = true} +mime_multipart = {version = "0.5", optional = true} +hyper_0_10 = {package = "hyper", version = "0.10", default-features = false, optional=true} native-tls = {version = "0.1.4", optional = true} openssl = {version = "0.9.14", optional = true} serde_json = {version = "1.0", optional = true} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/README.md b/samples/server/petstore/rust-server/output/multipart-v3/README.md index 3e91d461ca3e..40917d75680a 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/README.md +++ b/samples/server/petstore/rust-server/output/multipart-v3/README.md @@ -61,6 +61,7 @@ cargo run --example server To run a client, follow one of the following simple steps: ``` +cargo run --example client MultipartRelatedRequestPost cargo run --example client MultipartRequestPost ``` @@ -95,11 +96,13 @@ All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- +[****](docs/default_api.md#) | **POST** /multipart_related_request | [****](docs/default_api.md#) | **POST** /multipart_request | ## Documentation For Models + - [MultipartRelatedRequest](docs/MultipartRelatedRequest.md) - [MultipartRequest](docs/MultipartRequest.md) - [MultipartRequestObjectField](docs/MultipartRequestObjectField.md) 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 index a05b882da125..830f1ad0d8db 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/api/openapi.yaml +++ b/samples/server/petstore/rust-server/output/multipart-v3/api/openapi.yaml @@ -17,6 +17,39 @@ paths: responses: "201": description: OK + /multipart_related_request: + post: + requestBody: + content: + multipart/related: + encoding: + object_field: + contentType: application/json + style: form + optional_binary_field: + contentType: application/zip + headers: + Content-Id: + explode: false + schema: + type: string + style: simple + style: form + required_binary_field: + contentType: image/png + headers: + Content-Id: + explode: false + schema: + type: string + style: simple + style: form + schema: + $ref: '#/components/schemas/multipart_related_request' + required: true + responses: + "201": + description: OK components: schemas: multipart_request: @@ -34,6 +67,19 @@ components: - binary_field - string_field type: object + multipart_related_request: + properties: + object_field: + $ref: '#/components/schemas/multipart_request_object_field' + optional_binary_field: + format: binary + type: string + required_binary_field: + format: binary + type: string + required: + - required_binary_field + type: object multipart_request_object_field: properties: field_a: diff --git a/samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRelatedRequest.md b/samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRelatedRequest.md new file mode 100644 index 000000000000..0180168d1ec6 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/docs/MultipartRelatedRequest.md @@ -0,0 +1,12 @@ +# MultipartRelatedRequest + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**object_field** | [***models::MultipartRequestObjectField**](multipart_request_object_field.md) | | [optional] [default to None] +**optional_binary_field** | [***swagger::ByteArray**](file.md) | | [optional] [default to None] +**required_binary_field** | [***swagger::ByteArray**](file.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/default_api.md b/samples/server/petstore/rust-server/output/multipart-v3/docs/default_api.md index b88fe084c35a..09d889d7e522 100644 --- 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 @@ -4,9 +4,45 @@ All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- +****](default_api.md#) | **POST** /multipart_related_request | ****](default_api.md#) | **POST** /multipart_request | +# **** +> (required_binary_field, optional) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **required_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 +------------- | ------------- | ------------- | ------------- + **required_binary_field** | **swagger::ByteArray**| | + **object_field** | [**multipart_request_object_field**](multipart_request_object_field.md)| | + **optional_binary_field** | **swagger::ByteArray**| | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: multipart/related + - **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) + # **** > (string_field, binary_field, optional) 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 index a0db4112970e..a5a21b2eda6d 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/examples/client.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/client.rs @@ -14,6 +14,7 @@ use futures::{Future, future, Stream, stream}; #[allow(unused_imports)] use multipart_v3::{Api, ApiNoContext, Client, ContextWrapperExt, ApiError, + MultipartRelatedRequestPostResponse, MultipartRequestPostResponse }; use clap::{App, Arg}; @@ -24,6 +25,8 @@ fn main() { .help("Sets the operation to run") .possible_values(&[ + "MultipartRelatedRequestPost", + "MultipartRequestPost", ]) @@ -70,6 +73,16 @@ fn main() { match matches.value_of("operation") { + Some("MultipartRelatedRequestPost") => { + let mut rt = tokio::runtime::Runtime::new().unwrap(); + let result = rt.block_on(client.multipart_related_request_post( + swagger::ByteArray(Vec::from("BINARY_DATA_HERE")), + None, + Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE"))) + )); + println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + Some("MultipartRequestPost") => { let mut rt = tokio::runtime::Runtime::new().unwrap(); let result = rt.block_on(client.multipart_request_post( 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 index 23dec986b52c..1aac22ba9b5d 100644 --- 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 @@ -17,6 +17,7 @@ use swagger; use swagger::{Has, XSpanIdString}; use multipart_v3::{Api, ApiError, + MultipartRelatedRequestPostResponse, MultipartRequestPostResponse }; use multipart_v3::models; @@ -35,6 +36,13 @@ impl Server { impl Api for Server where C: Has{ + fn multipart_related_request_post(&self, required_binary_field: swagger::ByteArray, object_field: Option, optional_binary_field: Option, context: &C) -> Box + Send> { + let context = context.clone(); + println!("multipart_related_request_post({:?}, {:?}, {:?}) - X-Span-ID: {:?}", required_binary_field, object_field, optional_binary_field, context.get().0.clone()); + Box::new(futures::failed("Generic failure".into())) + } + + fn multipart_request_post(&self, string_field: String, binary_field: swagger::ByteArray, optional_string_field: Option, object_field: Option, context: &C) -> Box + Send> { let context = context.clone(); println!("multipart_request_post(\"{}\", {:?}, {:?}, {:?}) - X-Span-ID: {:?}", string_field, binary_field, optional_string_field, object_field, context.get().0.clone()); 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 index 1a7515d28f1b..73f323958e39 100644 --- 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 @@ -28,8 +28,12 @@ use swagger::client::Service; use mime::Mime; use std::io::Cursor; use multipart::client::lazy::Multipart; +use hyper_0_10::header::{Headers, ContentType}; +header! { (ContentId, "Content-ID") => [String] } +use mime_multipart::{Node, Part, generate_boundary, write_multipart}; use {Api, + MultipartRelatedRequestPostResponse, MultipartRequestPostResponse }; @@ -196,6 +200,146 @@ impl Api for Client where F: Future, Error=hyper::Error> + Send + 'static { + fn multipart_related_request_post(&self, param_required_binary_field: swagger::ByteArray, param_object_field: Option, param_optional_binary_field: Option, context: &C) -> Box + Send> { + let mut uri = format!( + "{}/multipart_related_request", + self.base_path + ); + + // Query parameters + let mut query_string = 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(future::err(ApiError(format!("Unable to build URI: {}", err)))), + }; + + let mut request = match hyper::Request::builder() + .method("POST") + .uri(uri) + .body(Body::empty()) { + Ok(req) => req, + Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e)))) + }; + + // Construct the Body for a multipart/related request. The mime 0.2.6 library + // does not parse quoted-string parameters correctly. The boundary doesn't + // need to be a quoted string if it does not contain a '/', hence ensure + // no such boundary is used. + let mut boundary = generate_boundary(); + for b in boundary.iter_mut() { + if b == &('/' as u8) { + *b = '=' as u8; + } + } + + let mut body_parts = vec![]; + + if let Some(object_field) = param_object_field { + let part = Node::Part(Part { + headers: { + let mut h = Headers::new(); + h.set(ContentType("application/json".parse().unwrap())); + h.set(ContentId("object_field".parse().unwrap())); + h + }, + body: serde_json::to_string(&object_field) + .expect("Impossible to fail to serialize") + .into_bytes(), + }); + body_parts.push(part); + } + + if let Some(optional_binary_field) = param_optional_binary_field { + let part = Node::Part(Part { + headers: { + let mut h = Headers::new(); + h.set(ContentType("application/zip".parse().unwrap())); + h.set(ContentId("optional_binary_field".parse().unwrap())); + h + }, + body: optional_binary_field.0, + }); + body_parts.push(part); + } + + let part = Node::Part(Part { + headers: { + let mut h = Headers::new(); + h.set(ContentType("image/png".parse().unwrap())); + h.set(ContentId("required_binary_field".parse().unwrap())); + h + }, + body: param_required_binary_field.0, + }); + body_parts.push(part); + + // Write the body into a vec. + let mut body: Vec = vec![]; + write_multipart(&mut body, &boundary, &body_parts) + .expect("Failed to write multipart body"); + + // Add the message body to the request object. + *request.body_mut() = Body::from(body); + + let header = &mimetypes::requests::MULTIPART_RELATED_REQUEST_POST; + request.headers_mut().insert(CONTENT_TYPE, + match HeaderValue::from_bytes( + &[header.as_bytes(), "; boundary=".as_bytes(), &boundary, "; type=\"application/json\"".as_bytes()].concat() + ) { + Ok(h) => h, + Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", header, e)))) + }); + + + let header = HeaderValue::from_str((context as &dyn Has).get().0.clone().to_string().as_str()); + request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { + Ok(h) => h, + Err(e) => return Box::new(future::err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))) + }); + + + Box::new(self.client_service.request(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| { + match response.status().as_u16() { + 201 => { + let body = response.into_body(); + Box::new( + future::ok( + MultipartRelatedRequestPostResponse::OK + ) + ) as Box + Send> + }, + code => { + let headers = response.headers().clone(); + Box::new(response.into_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 + Send> + } + } + })) + + } + 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 + Send> { let mut uri = format!( "{}/multipart_request", @@ -223,7 +367,7 @@ impl Api for Client where Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e)))) }; - let mut multipart = Multipart::new(); + let mut multipart = Multipart::new(); // For each parameter, encode as appropriate and add to the multipart body as a stream. @@ -238,7 +382,7 @@ impl Api for Client where 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)); + 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, @@ -251,7 +395,7 @@ impl Api for Client where 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)); + 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, @@ -264,7 +408,7 @@ impl Api for Client where 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)); + 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(); 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 index 3ec1048e6696..5a537443398d 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs @@ -12,6 +12,9 @@ extern crate lazy_static; extern crate url; #[macro_use] extern crate log; +#[cfg(any(feature = "client", feature = "server"))] +#[macro_use] +extern crate hyper_0_10; // Crates for conversion support #[cfg(feature = "conversion")] @@ -36,6 +39,10 @@ extern crate hyper_tls; #[cfg(any(feature = "client", feature = "server"))] extern crate openssl; #[cfg(any(feature = "client", feature = "server"))] +extern crate mime_0_2; +#[cfg(any(feature = "client", feature = "server"))] +extern crate mime_multipart; +#[cfg(any(feature = "client", feature = "server"))] extern crate native_tls; #[cfg(feature = "server")] extern crate percent_encoding; @@ -53,7 +60,6 @@ extern crate tokio; #[cfg(any(feature = "client", feature = "server"))] extern crate multipart; -extern crate mime_0_2; #[cfg(any(feature = "client", feature = "server"))] @@ -77,6 +83,12 @@ pub const BASE_PATH: &'static str = ""; pub const API_VERSION: &'static str = "1.0.7"; +#[derive(Debug, PartialEq)] +pub enum MultipartRelatedRequestPostResponse { + /// OK + OK +} + #[derive(Debug, PartialEq)] pub enum MultipartRequestPostResponse { /// OK @@ -88,6 +100,9 @@ pub enum MultipartRequestPostResponse { pub trait Api { + fn multipart_related_request_post(&self, required_binary_field: swagger::ByteArray, object_field: Option, optional_binary_field: Option, context: &C) -> Box + Send>; + + fn multipart_request_post(&self, string_field: String, binary_field: swagger::ByteArray, optional_string_field: Option, object_field: Option, context: &C) -> Box + Send>; } @@ -96,6 +111,9 @@ pub trait Api { pub trait ApiNoContext { + fn multipart_related_request_post(&self, required_binary_field: swagger::ByteArray, object_field: Option, optional_binary_field: Option) -> Box + Send>; + + fn multipart_request_post(&self, string_field: String, binary_field: swagger::ByteArray, optional_string_field: Option, object_field: Option) -> Box + Send>; } @@ -115,6 +133,11 @@ impl<'a, T: Api + Sized, C> ContextWrapperExt<'a, C> for T { impl<'a, T: Api, C> ApiNoContext for ContextWrapper<'a, T, C> { + fn multipart_related_request_post(&self, required_binary_field: swagger::ByteArray, object_field: Option, optional_binary_field: Option) -> Box + Send> { + self.api().multipart_related_request_post(required_binary_field, object_field, optional_binary_field, &self.context()) + } + + fn multipart_request_post(&self, string_field: String, binary_field: swagger::ByteArray, optional_string_field: Option, object_field: Option) -> Box + Send> { self.api().multipart_request_post(string_field, binary_field, optional_string_field, object_field, &self.context()) } 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 index 8c8403a8c6c6..4b7ff4a282cb 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/mimetypes.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/mimetypes.rs @@ -7,4 +7,7 @@ pub mod responses { pub mod requests { + /// Create &str objects for the request content types for MultipartRelatedRequestPost + pub static MULTIPART_RELATED_REQUEST_POST: &str = "multipart/related"; + } 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 index 17f279438a0a..da2eb016dac6 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs @@ -8,6 +8,33 @@ use swagger; use std::string::ParseError; +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "conversion", derive(LabelledGeneric))] +pub struct MultipartRelatedRequest { + #[serde(rename = "object_field")] + #[serde(skip_serializing_if="Option::is_none")] + pub object_field: Option, + + #[serde(rename = "optional_binary_field")] + #[serde(skip_serializing_if="Option::is_none")] + pub optional_binary_field: Option, + + #[serde(rename = "required_binary_field")] + pub required_binary_field: swagger::ByteArray, + +} + +impl MultipartRelatedRequest { + pub fn new(required_binary_field: swagger::ByteArray, ) -> MultipartRelatedRequest { + MultipartRelatedRequest { + object_field: None, + optional_binary_field: None, + required_binary_field: required_binary_field, + } + } +} + + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[cfg_attr(feature = "conversion", derive(LabelledGeneric))] pub struct MultipartRequest { 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 index 9ba9dc819faa..2661285ce7a0 100644 --- 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 @@ -13,6 +13,10 @@ use swagger::{ApiError, XSpanIdString, Has, RequestParser}; use swagger::auth::Scopes; use swagger::context::ContextualPayload; use url::form_urlencoded; +use hyper_0_10::header::{Headers, ContentType}; +header! { (ContentId, "Content-ID") => [String] } +use mime_0_2::{TopLevel, SubLevel, Mime as Mime2}; +use mime_multipart::{read_multipart_body, Node, Part}; use multipart::server::Multipart; use multipart::server::save::SaveResult; @@ -21,6 +25,7 @@ use mimetypes; pub use swagger::auth::Authorization; use {Api, + MultipartRelatedRequestPostResponse, MultipartRequestPostResponse }; @@ -34,11 +39,13 @@ mod paths { lazy_static! { pub static ref GLOBAL_REGEX_SET: regex::RegexSet = regex::RegexSet::new(vec![ + r"^/multipart_related_request$", r"^/multipart_request$" ]) .expect("Unable to create global regex set"); } - pub static ID_MULTIPART_REQUEST: usize = 0; + pub static ID_MULTIPART_RELATED_REQUEST: usize = 0; + pub static ID_MULTIPART_REQUEST: usize = 1; } pub struct MakeService { @@ -117,6 +124,150 @@ where // Please update both places if changing how this code is autogenerated. match &method { + // MultipartRelatedRequestPost - POST /multipart_related_request + &hyper::Method::POST if path.matched(paths::ID_MULTIPART_RELATED_REQUEST) => { + // 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| -> Self::Future { + match result { + Ok(body) => { + let mut unused_elements: Vec = vec![]; + + // Get multipart chunks. + + // Extract the top-level content type header. + let content_type_mime = headers + .get(CONTENT_TYPE) + .ok_or("Missing content-type header".to_string()) + .and_then(|v| v.to_str().map_err(|e| format!("Couldn't read content-type header value for MultipartRelatedRequestPost: {}", e))) + .and_then(|v| v.parse::().map_err(|_e| format!("Couldn't parse content-type header value for MultipartRelatedRequestPost"))); + + // Insert top-level content type header into a Headers object. + let mut multi_part_headers = Headers::new(); + match content_type_mime { + Ok(content_type_mime) => { + multi_part_headers.set(ContentType(content_type_mime)); + }, + Err(e) => { + return Box::new(future::ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(e)) + .expect("Unable to create Bad Request response due to unable to read content-type header for MultipartRelatedRequestPost"))); + } + } + + // &*body expresses the body as a byteslice, &mut provides a + // mutable reference to that byteslice. + let nodes = match read_multipart_body(&mut&*body, &multi_part_headers, false) { + Ok(nodes) => nodes, + Err(e) => { + return Box::new(future::ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Could not read multipart body for MultipartRelatedRequestPost: {}", e))) + .expect("Unable to create Bad Request response due to unable to read multipart body for MultipartRelatedRequestPost"))); + } + }; + + let mut param_object_field = None; + let mut param_optional_binary_field = None; + let mut param_required_binary_field = None; + + for node in nodes { + if let Node::Part(part) = node { + let content_type = part.content_type().map(|x| format!("{}",x)); + match content_type.as_ref().map(|x| x.as_str()) { + Some("application/json") => { + // Extract JSON part. + let deserializer = &mut serde_json::Deserializer::from_slice(part.body.as_slice()); + let json_data: models::MultipartRequestObjectField = match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in JSON part: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(json_data) => json_data, + Err(e) => return Box::new(future::ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't parse body parameter models::MultipartRequestObjectField - doesn't match schema: {}", e))) + .expect("Unable to create Bad Request response for invalid body parameter models::MultipartRequestObjectField due to schema"))) + }; + // Push JSON part to return object. + param_object_field.get_or_insert(json_data); + }, + Some("application/zip") => { + param_optional_binary_field.get_or_insert(swagger::ByteArray(part.body)); + }, + Some("image/png") => { + param_required_binary_field.get_or_insert(swagger::ByteArray(part.body)); + }, + Some(content_type) => { + warn!("Ignoring unknown content type: {}", content_type); + unused_elements.push(content_type.to_string()); + }, + None => { + warn!("Missing content type"); + }, + } + } else { + unimplemented!("No support for handling unexpected parts"); + // unused_elements.push(); + } + } + + // Check that the required multipart chunks are present. + let param_required_binary_field = match param_required_binary_field { + Some(x) => x, + None => return Box::new(future::ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Missing required multipart/related parameter required_binary_field"))) + .expect("Unable to create Bad Request response for missing multipart/related parameter required_binary_field due to schema"))) + }; + Box::new( + api_impl.multipart_related_request_post( + param_required_binary_field, + param_object_field, + param_optional_binary_field, + &context + ).then(move |result| { + let mut response = Response::new(Body::empty()); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().to_string().as_str()) + .expect("Unable to create X-Span-ID header value")); + + + match result { + Ok(rsp) => match rsp { + MultipartRelatedRequestPostResponse::OK + + + => { + *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = Body::from("An internal error occurred"); + }, + } + + future::ok(response) + } + )) + + }, + Err(e) => Box::new(future::ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::from(format!("Couldn't read body parameter Default: {}", e))) + .expect("Unable to create Bad Request response due to unable to read body parameter Default"))), + } + }) + ) as Self::Future + }, + // MultipartRequestPost - POST /multipart_request &hyper::Method::POST if path.matched(paths::ID_MULTIPART_REQUEST) => { let boundary = match swagger::multipart::boundary(&headers) { @@ -147,7 +298,6 @@ where .expect("Unable to create Bad Request response due to failure to process all message"))) }, }; - let field_string_field = entries.fields.remove("string_field"); let param_string_field = match field_string_field { Some(field) => { @@ -174,7 +324,6 @@ where .expect("Unable to create Bad Request due to missing required form parameter string_field"))) } }; - let field_optional_string_field = entries.fields.remove("optional_string_field"); let param_optional_string_field = match field_optional_string_field { Some(field) => { @@ -199,7 +348,6 @@ where None } }; - let field_object_field = entries.fields.remove("object_field"); let param_object_field = match field_object_field { Some(field) => { @@ -224,7 +372,6 @@ where None } }; - let field_binary_field = entries.fields.remove("binary_field"); let param_binary_field = match field_binary_field { Some(field) => { @@ -241,7 +388,6 @@ where .expect("Unable to create Bad Request due to missing required form parameter binary_field"))) } }; - Box::new( api_impl.multipart_request_post( param_string_field, @@ -315,6 +461,9 @@ impl RequestParser for ApiRequestParser { let path = paths::GLOBAL_REGEX_SET.matches(request.uri().path()); match request.method() { + // MultipartRelatedRequestPost - POST /multipart_related_request + &hyper::Method::POST if path.matched(paths::ID_MULTIPART_RELATED_REQUEST) => Ok("MultipartRelatedRequestPost"), + // 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/src/server/mod.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/server/mod.rs index e91b9c4fb3fa..2f5fba31bc40 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 @@ -147,7 +147,6 @@ where &hyper::Method::GET if path.matched(paths::ID_MULTIGET) => { Box::new({ {{ - Box::new( api_impl.multiget_get( &context @@ -322,7 +321,6 @@ where } Box::new({ {{ - Box::new( api_impl.multiple_auth_scheme_get( &context @@ -391,7 +389,6 @@ where } Box::new({ {{ - Box::new( api_impl.readonly_auth_scheme_get( &context @@ -449,7 +446,6 @@ where .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.required_octet_stream_put( param_body, @@ -497,7 +493,6 @@ where &hyper::Method::GET if path.matched(paths::ID_RESPONSES_WITH_HEADERS) => { Box::new({ {{ - Box::new( api_impl.responses_with_headers_get( &context @@ -574,7 +569,6 @@ where &hyper::Method::GET if path.matched(paths::ID_UUID) => { Box::new({ {{ - Box::new( api_impl.uuid_get( &context @@ -642,7 +636,6 @@ where } else { None }; - Box::new( api_impl.xml_extra_post( param_duplicate_xml_object, @@ -722,7 +715,6 @@ where } else { None }; - Box::new( api_impl.xml_other_post( param_another_xml_object, @@ -802,7 +794,6 @@ where } else { None }; - Box::new( api_impl.xml_other_put( param_string, @@ -882,7 +873,6 @@ where } else { None }; - Box::new( api_impl.xml_post( param_string, @@ -962,7 +952,6 @@ where } else { None }; - Box::new( api_impl.xml_put( param_xml_object, diff --git a/samples/server/petstore/rust-server/output/ops-v3/src/server/mod.rs b/samples/server/petstore/rust-server/output/ops-v3/src/server/mod.rs index 31cdcc5860d4..a6964835a744 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/src/server/mod.rs @@ -227,7 +227,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP10) => { Box::new({ {{ - Box::new( api_impl.op10_get( &context @@ -268,7 +267,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP11) => { Box::new({ {{ - Box::new( api_impl.op11_get( &context @@ -309,7 +307,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP12) => { Box::new({ {{ - Box::new( api_impl.op12_get( &context @@ -350,7 +347,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP13) => { Box::new({ {{ - Box::new( api_impl.op13_get( &context @@ -391,7 +387,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP14) => { Box::new({ {{ - Box::new( api_impl.op14_get( &context @@ -432,7 +427,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP15) => { Box::new({ {{ - Box::new( api_impl.op15_get( &context @@ -473,7 +467,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP16) => { Box::new({ {{ - Box::new( api_impl.op16_get( &context @@ -514,7 +507,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP17) => { Box::new({ {{ - Box::new( api_impl.op17_get( &context @@ -555,7 +547,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP18) => { Box::new({ {{ - Box::new( api_impl.op18_get( &context @@ -596,7 +587,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP19) => { Box::new({ {{ - Box::new( api_impl.op19_get( &context @@ -637,7 +627,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP1) => { Box::new({ {{ - Box::new( api_impl.op1_get( &context @@ -678,7 +667,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP20) => { Box::new({ {{ - Box::new( api_impl.op20_get( &context @@ -719,7 +707,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP21) => { Box::new({ {{ - Box::new( api_impl.op21_get( &context @@ -760,7 +747,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP22) => { Box::new({ {{ - Box::new( api_impl.op22_get( &context @@ -801,7 +787,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP23) => { Box::new({ {{ - Box::new( api_impl.op23_get( &context @@ -842,7 +827,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP24) => { Box::new({ {{ - Box::new( api_impl.op24_get( &context @@ -883,7 +867,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP25) => { Box::new({ {{ - Box::new( api_impl.op25_get( &context @@ -924,7 +907,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP26) => { Box::new({ {{ - Box::new( api_impl.op26_get( &context @@ -965,7 +947,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP27) => { Box::new({ {{ - Box::new( api_impl.op27_get( &context @@ -1006,7 +987,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP28) => { Box::new({ {{ - Box::new( api_impl.op28_get( &context @@ -1047,7 +1027,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP29) => { Box::new({ {{ - Box::new( api_impl.op29_get( &context @@ -1088,7 +1067,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP2) => { Box::new({ {{ - Box::new( api_impl.op2_get( &context @@ -1129,7 +1107,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP30) => { Box::new({ {{ - Box::new( api_impl.op30_get( &context @@ -1170,7 +1147,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP31) => { Box::new({ {{ - Box::new( api_impl.op31_get( &context @@ -1211,7 +1187,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP32) => { Box::new({ {{ - Box::new( api_impl.op32_get( &context @@ -1252,7 +1227,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP33) => { Box::new({ {{ - Box::new( api_impl.op33_get( &context @@ -1293,7 +1267,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP34) => { Box::new({ {{ - Box::new( api_impl.op34_get( &context @@ -1334,7 +1307,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP35) => { Box::new({ {{ - Box::new( api_impl.op35_get( &context @@ -1375,7 +1347,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP36) => { Box::new({ {{ - Box::new( api_impl.op36_get( &context @@ -1416,7 +1387,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP37) => { Box::new({ {{ - Box::new( api_impl.op37_get( &context @@ -1457,7 +1427,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP3) => { Box::new({ {{ - Box::new( api_impl.op3_get( &context @@ -1498,7 +1467,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP4) => { Box::new({ {{ - Box::new( api_impl.op4_get( &context @@ -1539,7 +1507,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP5) => { Box::new({ {{ - Box::new( api_impl.op5_get( &context @@ -1580,7 +1547,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP6) => { Box::new({ {{ - Box::new( api_impl.op6_get( &context @@ -1621,7 +1587,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP7) => { Box::new({ {{ - Box::new( api_impl.op7_get( &context @@ -1662,7 +1627,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP8) => { Box::new({ {{ - Box::new( api_impl.op8_get( &context @@ -1703,7 +1667,6 @@ where &hyper::Method::GET if path.matched(paths::ID_OP9) => { Box::new({ {{ - Box::new( api_impl.op9_get( &context 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 3556f8a6a676..9d0617535dd1 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 @@ -8,11 +8,13 @@ license = "Unlicense" [features] default = ["client", "server"] client = [ + "mime_0_2", "multipart", "multipart/client", "swagger/multipart", "serde_urlencoded", "serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio", "url" ] server = [ + "mime_0_2", "multipart", "multipart/server", "serde_json", "serde_ignored", "hyper", "native-tls", "openssl", "tokio", "tokio-tls", "regex", "percent-encoding", "url", "lazy_static" ] @@ -33,7 +35,7 @@ serde_derive = "1.0" # TODO: this should be updated to point at the official crate once # https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream serde-xml-rs = {git = "git://github.com/Metaswitch/serde-xml-rs.git" , branch = "master"} -mime_0_2 = { package = "mime", version = "0.2.6" } +mime_0_2 = { package = "mime", version = "0.2.6", optional = true } multipart = { version = "0.16", default-features = false, optional = true } uuid = {version = "0.7", features = ["serde", "v4"]} 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 581e8b39082e..344b27f3935d 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 @@ -2194,7 +2194,7 @@ impl Api for Client where Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e)))) }; - let mut multipart = Multipart::new(); + let mut multipart = Multipart::new(); // For each parameter, encode as appropriate and add to the multipart body as a stream. @@ -2209,7 +2209,7 @@ impl Api for Client where 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)); + 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, @@ -2222,7 +2222,7 @@ impl Api for Client where let file_cursor = Cursor::new(file_vec); - multipart.add_stream("file", file_cursor, None as Option<&str>, Some(file_mime)); + multipart.add_stream("file", file_cursor, None as Option<&str>, Some(file_mime)); let mut fields = match multipart.prepare() { Ok(fields) => fields, 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 754a6d0d3357..2e3ceabf98ca 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 @@ -36,6 +36,8 @@ extern crate hyper_tls; #[cfg(any(feature = "client", feature = "server"))] extern crate openssl; #[cfg(any(feature = "client", feature = "server"))] +extern crate mime_0_2; +#[cfg(any(feature = "client", feature = "server"))] extern crate native_tls; #[cfg(feature = "server")] extern crate percent_encoding; @@ -53,7 +55,6 @@ extern crate serde_xml_rs; #[cfg(any(feature = "client", feature = "server"))] extern crate multipart; -extern crate mime_0_2; #[cfg(any(feature = "client", feature = "server"))] extern crate serde_urlencoded; 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 2b1f82bcecab..9055d25389dd 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 @@ -256,7 +256,6 @@ where .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.test_special_tags( param_body, @@ -338,7 +337,6 @@ where } else { None }; - Box::new( api_impl.fake_outer_boolean_serialize( param_body, @@ -420,7 +418,6 @@ where } else { None }; - Box::new( api_impl.fake_outer_composite_serialize( param_body, @@ -502,7 +499,6 @@ where } else { None }; - Box::new( api_impl.fake_outer_number_serialize( param_body, @@ -584,7 +580,6 @@ where } else { None }; - Box::new( api_impl.fake_outer_string_serialize( param_body, @@ -669,7 +664,6 @@ where }; Box::new({ {{ - Box::new( api_impl.hyphen_param( param_hyphen_param, @@ -757,7 +751,6 @@ where .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.test_body_with_query_params( param_query, @@ -841,7 +834,6 @@ where .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.test_client_model( param_body, @@ -916,63 +908,62 @@ where Box::new({ {{ // Form parameters - let param_integer = + let param_integer = Some(56); - let param_int32 = + let param_int32 = Some(56); - let param_int64 = + let param_int64 = Some(789); - let param_number = + let param_number = 8.14; - let param_float = + let param_float = Some(3.4); - let param_double = + let param_double = 1.2; - let param_string = + let param_string = Some("string_example".to_string()); - let param_pattern_without_delimiter = + let param_pattern_without_delimiter = "pattern_without_delimiter_example".to_string(); - let param_byte = + let param_byte = swagger::ByteArray(Vec::from("BYTE_ARRAY_DATA_HERE")); - let param_binary = + let param_binary = Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE"))); - let param_date = + let param_date = None; - let param_date_time = + let param_date_time = None; - let param_password = + let param_password = Some("password_example".to_string()); - let param_callback = + let param_callback = Some("callback_example".to_string()); - Box::new( api_impl.test_endpoint_parameters( param_number, @@ -1070,11 +1061,10 @@ Some("callback_example".to_string()); Box::new({ {{ // Form parameters - let param_enum_form_string = + 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(), @@ -1157,7 +1147,6 @@ Some("enum_form_string_example".to_string()); .body(Body::from("Missing required body parameter param")) .expect("Unable to create Bad Request response for missing body parameter param"))), }; - Box::new( api_impl.test_inline_additional_properties( param_param, @@ -1213,15 +1202,14 @@ Some("enum_form_string_example".to_string()); Box::new({ {{ // Form parameters - let param_param = + let param_param = "param_example".to_string(); - let param_param2 = + let param_param2 = "param2_example".to_string(); - Box::new( api_impl.test_json_form_data( param_param, @@ -1302,7 +1290,6 @@ Some("enum_form_string_example".to_string()); .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.test_classname( param_body, @@ -1423,7 +1410,6 @@ Some("enum_form_string_example".to_string()); .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.add_pet( param_body, @@ -1535,7 +1521,6 @@ Some("enum_form_string_example".to_string()); }); Box::new({ {{ - Box::new( api_impl.delete_pet( param_pet_id, @@ -1613,7 +1598,6 @@ Some("enum_form_string_example".to_string()); .collect::>(); Box::new({ {{ - Box::new( api_impl.find_pets_by_status( param_status.as_ref(), @@ -1706,7 +1690,6 @@ Some("enum_form_string_example".to_string()); .collect::>(); Box::new({ {{ - Box::new( api_impl.find_pets_by_tags( param_tags.as_ref(), @@ -1795,7 +1778,6 @@ Some("enum_form_string_example".to_string()); }; Box::new({ {{ - Box::new( api_impl.get_pet_by_id( param_pet_id, @@ -1917,7 +1899,6 @@ Some("enum_form_string_example".to_string()); .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.update_pet( param_body, @@ -2037,15 +2018,14 @@ Some("enum_form_string_example".to_string()); Box::new({ {{ // Form parameters - let param_name = + let param_name = Some("name_example".to_string()); - let param_status = + let param_status = Some("status_example".to_string()); - Box::new( api_impl.update_pet_with_form( param_pet_id, @@ -2165,7 +2145,6 @@ Some("status_example".to_string()); .expect("Unable to create Bad Request response due to failure to process all message"))) }, }; - let field_additional_metadata = entries.fields.remove("additional_metadata"); let param_additional_metadata = match field_additional_metadata { Some(field) => { @@ -2190,7 +2169,6 @@ Some("status_example".to_string()); None } }; - let field_file = entries.fields.remove("file"); let param_file = match field_file { Some(field) => { @@ -2215,7 +2193,6 @@ Some("status_example".to_string()); None } }; - Box::new( api_impl.upload_file( param_pet_id, @@ -2296,7 +2273,6 @@ Some("status_example".to_string()); }; Box::new({ {{ - Box::new( api_impl.delete_order( param_order_id, @@ -2355,7 +2331,6 @@ Some("status_example".to_string()); } Box::new({ {{ - Box::new( api_impl.get_inventory( &context @@ -2426,7 +2401,6 @@ Some("status_example".to_string()); }; Box::new({ {{ - Box::new( api_impl.get_order_by_id( param_order_id, @@ -2519,7 +2493,6 @@ Some("status_example".to_string()); .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.place_order( param_body, @@ -2618,7 +2591,6 @@ Some("status_example".to_string()); .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.create_user( param_body, @@ -2701,7 +2673,6 @@ Some("status_example".to_string()); .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.create_users_with_array_input( param_body.as_ref(), @@ -2784,7 +2755,6 @@ Some("status_example".to_string()); .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.create_users_with_list_input( param_body.as_ref(), @@ -2860,7 +2830,6 @@ Some("status_example".to_string()); }; Box::new({ {{ - Box::new( api_impl.delete_user( param_username, @@ -2930,7 +2899,6 @@ Some("status_example".to_string()); }; Box::new({ {{ - Box::new( api_impl.get_user_by_name( param_username, @@ -3028,7 +2996,6 @@ Some("status_example".to_string()); }; Box::new({ {{ - Box::new( api_impl.login_user( param_username, @@ -3100,7 +3067,6 @@ Some("status_example".to_string()); &hyper::Method::GET if path.matched(paths::ID_USER_LOGOUT) => { Box::new({ {{ - Box::new( api_impl.logout_user( &context @@ -3190,7 +3156,6 @@ Some("status_example".to_string()); .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.update_user( param_username, 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 a9314680d3b3..01eb2099cde3 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 @@ -129,7 +129,6 @@ where &hyper::Method::GET if path.matched(paths::ID_DUMMY) => { Box::new({ {{ - Box::new( api_impl.dummy_get( &context @@ -198,7 +197,6 @@ where .body(Body::from("Missing required body parameter nested_response")) .expect("Unable to create Bad Request response for missing body parameter nested_response"))), }; - Box::new( api_impl.dummy_put( param_nested_response, @@ -253,7 +251,6 @@ where &hyper::Method::GET if path.matched(paths::ID_FILE_RESPONSE) => { Box::new({ {{ - Box::new( api_impl.file_response_get( &context @@ -326,7 +323,6 @@ where .body(Body::from("Missing required body parameter body")) .expect("Unable to create Bad Request response for missing body parameter body"))), }; - Box::new( api_impl.html_post( param_body, @@ -383,7 +379,6 @@ where &hyper::Method::GET if path.matched(paths::ID_RAW_JSON) => { Box::new({ {{ - Box::new( api_impl.raw_json_get( &context