Skip to content

Commit 1b4601c

Browse files
authored
fix(rust-server): Handle multiple content-types in responses (#24179)
* fix(rust-server): dispatch response bodies on Content-Type for multi-content-type responses (#24097) * Review markups * Regenerate rust-server sample after merging master Merging upstream master (which includes PR #24192, a fix to InlineModelResolver's inline-schema merging) surfaces a previously orphaned model for the testEnumParameters enum_header_string parameter's inline enum. Regenerating picks up the new model_doc.mustache formatting for it.
1 parent 231c3c4 commit 1b4601c

102 files changed

Lines changed: 1438 additions & 563 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java

Lines changed: 171 additions & 158 deletions
Large diffs are not rendered by default.

modules/openapi-generator/src/main/resources/rust-server/client-imports.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ use multipart::client::lazy::Multipart;
2929
{{/apiUsesMultipartFormData}}
3030
{{#apiUsesMultipartRelated}}
3131
use hyper::header::HeaderMap;
32-
use mime_multipart::{Node, Part, write_multipart};
32+
use log::warn;
33+
use mime_multipart::{read_multipart_body, Node, Part, write_multipart};
3334
{{/apiUsesMultipartRelated}}
3435

3536
use crate::models;

modules/openapi-generator/src/main/resources/rust-server/client-operation.mustache

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,10 @@
191191
{{#responses}}
192192
{{{code}}} => {
193193
{{#headers}}
194-
let response_{{{name}}} = match response.headers().get(HeaderName::from_static("{{{nameInLowerCase}}}")) {
194+
{{#-first}}
195+
let (header, body) = response.into_parts();
196+
{{/-first}}
197+
let response_{{{name}}} = match header.headers.get(HeaderName::from_static("{{{nameInLowerCase}}}")) {
195198
Some(response_{{{name}}}) => {
196199
let response_{{{name}}} = response_{{{name}}}.clone();
197200
let response_{{{name}}} = match TryInto::<header::IntoHeaderValue<{{{dataType}}}>>::try_into(response_{{{name}}}) {
@@ -217,14 +220,25 @@
217220

218221
{{/headers}}
219222
{{#dataType}}
220-
let body = response.into_body();
223+
{{#headers}}{{#-first}}
224+
let body = http_body_util::BodyExt::collect(body)
225+
{{/-first}}{{/headers}}
226+
{{^headers}}
227+
{{#vendorExtensions.x-response-content-types}}
228+
{{#-first}}
229+
let (header, body) = response.into_parts();
221230
let body = http_body_util::BodyExt::collect(body)
231+
{{/-first}}
232+
{{/vendorExtensions.x-response-content-types}}
233+
{{^vendorExtensions.x-response-content-types}}
234+
let body = http_body_util::BodyExt::collect(response.into_body())
235+
{{/vendorExtensions.x-response-content-types}}
236+
{{/headers}}
222237
.await
223238
.map(|f| f.to_bytes().to_vec())
224239
.map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?;
225240

226-
{{>client-response-body-instance}}
227-
241+
{{>client-response-body}}
228242

229243
Ok({{{operationId}}}Response::{{#exts}}{{x-response-id}}{{/exts}}
230244
{{^headers}}

modules/openapi-generator/src/main/resources/rust-server/client-request-body-instance.mustache

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
// Consumes multipart/form body
55
{{>client-request-body-multipart-form}}
6-
76
{{/x-consumes-multipart-form}}
87
{{#x-consumes-multipart-related}}
98

modules/openapi-generator/src/main/resources/rust-server/client-request-body-multipart-form.mustache

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, None as Option<&str>, Some({{{paramName}}}_mime));
2222
{{/jsonSchema}}
2323
{{/isByteArray}}
24-
2524
{{#isByteArray}}
2625
let {{{paramName}}}_vec = param_{{{paramName}}}.to_vec();
2726

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{{#exts}}
2+
{{#x-produces-bytes}}
3+
let body = swagger::ByteArray(body.to_vec());
4+
{{/x-produces-bytes}}
5+
{{^x-produces-bytes}}
6+
let body = str::from_utf8(&body)
7+
.map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?;
8+
{{#x-produces-xml}}
9+
// ToDo: this will move to swagger-rs and become a standard From conversion trait
10+
// once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
11+
let body = serde_xml_rs::from_str::<{{{dataType}}}>(body)
12+
.map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?;
13+
{{/x-produces-xml}}
14+
{{#x-produces-json}}
15+
let body = serde_json::from_str::<{{{dataType}}}>(body)
16+
.map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?;
17+
{{/x-produces-json}}
18+
{{#x-produces-plain-text}}
19+
let body = body.to_string();
20+
{{/x-produces-plain-text}}
21+
{{/x-produces-bytes}}
22+
{{/exts}}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{{#vendorExtensions.x-response-content-types}}
2+
{{#-first}}
3+
// Body has multiple variant schemas
4+
let content_type = if let Some(content_type) = header.headers.get(CONTENT_TYPE) {
5+
content_type.to_str()
6+
} else {
7+
return Err(ApiError(String::from("Missing content type header")));
8+
};
9+
10+
let content_type = content_type.map(|s|
11+
s.split(';').next().expect("Splitting content type header failed").trim());
12+
13+
let body = match content_type {
14+
{{/-first}}
15+
Ok(ct) if ct.eq_ignore_ascii_case("{{{contentType}}}") => {
16+
{{>client-response-body-variant-instance}}
17+
{{{variantName}}}(body)
18+
},
19+
{{#-last}}
20+
e => {
21+
return Err(ApiError(format!("Unexpected content type: {:?}", e)));
22+
}
23+
};
24+
{{/-last}}
25+
{{/vendorExtensions.x-response-content-types}}
26+
{{^vendorExtensions.x-response-content-types}}
27+
{{>client-response-body-instance}}
28+
{{/vendorExtensions.x-response-content-types}}

modules/openapi-generator/src/main/resources/rust-server/model_doc.mustache

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
{{#models}}{{#model}}# {{{classname}}}
22

3+
{{#vars}}
4+
{{#-first}}
35
## Properties
46
Name | Type | Description | Notes
57
------------ | ------------- | ------------- | -------------
6-
{{#vars}}**{{{name}}}** | {{#isPrimitiveType}}**{{{dataType}}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{^isContainer}}{{^isDateTime}}*{{/isDateTime}}{{/isContainer}}{{{dataType}}}**]({{{complexType}}}.md){{/isPrimitiveType}} | {{{description}}} | {{^required}}[optional] {{/required}}{{#isReadOnly}}[readonly] {{/isReadOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}}
8+
{{/-first}}
9+
**{{{name}}}** | {{#isPrimitiveType}}**{{{dataType}}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{^isContainer}}{{^isDateTime}}*{{/isDateTime}}{{/isContainer}}{{{dataType}}}**]({{{complexType}}}.md){{/isPrimitiveType}} | {{{description}}} | {{^required}}[optional] {{/required}}{{#isReadOnly}}[readonly] {{/isReadOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}}
10+
{{/vars}}
11+
{{^vars}}
12+
## Type
13+
{{#arrayModelType}}**Vec<{{{arrayModelType}}}>**{{/arrayModelType}}{{^arrayModelType}}**{{{dataType}}}**{{/arrayModelType}}
714
{{/vars}}
815

916
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

modules/openapi-generator/src/main/resources/rust-server/server-operation-handler.mustache

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ where
242242
{{/bodyParam.exts.x-consumes-plain-text}}
243243
{{/exts.x-consumes-form}}
244244
{{/exts.x-consumes-multipart-form}}
245-
{{>server-request-body-instance}}
245+
{{>server-request-body}}
246246

247247
{{/exts.x-has-request-body}}
248248
let result = api_impl.{{#exts}}{{{x-operation-id}}}{{/exts}}(
@@ -331,7 +331,7 @@ where
331331
}
332332
{{/required}}
333333
{{/headers}}
334-
{{>server-response-body-instance}}
334+
{{>server-response-body}}
335335

336336
},
337337
{{/responses}}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{#exts}}
2+
{{#x-consumes-multipart}}
3+
{{#x-consumes-multipart-related}}
4+
{{>server-request-body-multipart-related}}
5+
{{/x-consumes-multipart-related}}
6+
{{^x-consumes-multipart-related}}
7+
{{^bodyParams}}
8+
{{>server-request-body-multipart-form}}
9+
{{/bodyParams}}
10+
{{/x-consumes-multipart-related}}
11+
{{/x-consumes-multipart}}
12+
{{^x-consumes-multipart}}
13+
{{#bodyParams}}
14+
{{>server-request-body-basic}}
15+
{{/bodyParams}}
16+
{{^bodyParams}}
17+
{{>server-request-body-form}}
18+
{{/bodyParams}}
19+
{{/x-consumes-multipart}}
20+
{{/exts}}

0 commit comments

Comments
 (0)