Skip to content

Commit 95105ce

Browse files
authored
[Rust Server] Support complex query parameters (#5831)
* [Rust Server] Support complex query parameters * [Rust Server] Remove unused extern crate * [Rust Server] tokio should be a dev-dependency * [Rust Server] Add test for complex query params * Update samples Co-authored-by: Matt Williams
1 parent cdb500c commit 95105ce

File tree

29 files changed

+330
-46
lines changed

29 files changed

+330
-46
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ mime_multipart = {version = "0.5", optional = true}
8787
hyper_0_10 = {package = "hyper", version = "0.10", default-features = false, optional=true}
8888
{{/apiUsesMultipartRelated}}
8989
serde_ignored = {version = "0.0.4", optional = true}
90-
tokio = {version = "0.1.17", optional = true}
9190
url = {version = "1.5", optional = true}
9291

9392
# Client-specific
@@ -111,6 +110,7 @@ frunk-enum-core = { version = "0.2.0", optional = true }
111110
clap = "2.25"
112111
error-chain = "0.12"
113112
env_logger = "0.6"
113+
tokio = "0.1.17"
114114
{{^apiUsesUuid}}
115115
uuid = {version = "0.7", features = ["serde", "v4"]}
116116
{{/apiUsesUuid}}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
{{^required}}
3535
if let Some(param_{{{paramName}}}) = param_{{{paramName}}} {
3636
{{/required}}
37-
query_string.append_pair("{{{baseName}}}", &param_{{{paramName}}}{{#isListContainer}}.join(","){{/isListContainer}}{{^isListContainer}}.to_string(){{/isListContainer}});
37+
query_string.append_pair("{{{baseName}}}", &param_{{{paramName}}}{{#isListContainer}}.iter().map(ToString::to_string).collect::<Vec<String>>().join(","){{/isListContainer}}{{^isListContainer}}.to_string(){{/isListContainer}});
3838
{{^required}}
3939
}
4040
{{/required}}

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

-2
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@ extern crate mime_multipart;
6767
extern crate percent_encoding;
6868
#[cfg(any(feature = "client", feature = "server"))]
6969
extern crate serde_ignored;
70-
#[cfg(any(feature = "client", feature = "server"))]
71-
extern crate tokio;
7270

7371
#[cfg(any(feature = "client", feature = "server"))]
7472
{{#apiUsesUuid}}extern crate uuid;{{/apiUsesUuid}}

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

+6
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ impl std::convert::From<{{{dataType}}}> for {{{classname}}} {
6464
}
6565

6666
{{#vendorExtensions.isString}}
67+
impl std::string::ToString for {{{classname}}} {
68+
fn to_string(&self) -> String {
69+
self.0.to_string()
70+
}
71+
}
72+
6773
impl std::str::FromStr for {{{classname}}} {
6874
type Err = std::string::ParseError;
6975
fn from_str(x: &str) -> std::result::Result<Self, Self::Err> {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
{{/-first}}
113113
let param_{{{paramName}}} = query_params.iter().filter(|e| e.0 == "{{{baseName}}}").map(|e| e.1.to_owned())
114114
{{#isListContainer}}
115-
.filter_map(|param_{{{paramName}}}| param_{{{paramName}}}.parse::<{{{baseType}}}>().ok())
115+
.filter_map(|param_{{{paramName}}}| param_{{{paramName}}}.parse().ok())
116116
.collect::<Vec<_>>();
117117
{{^required}}
118118
let param_{{{paramName}}} = if !param_{{{paramName}}}.is_empty() {

modules/openapi-generator/src/test/resources/3_0/rust-server/openapi-v3.yaml

+21
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,27 @@ paths:
337337
responses:
338338
"204":
339339
description: Success.
340+
/merge-patch-json:
341+
get:
342+
responses:
343+
200:
344+
description: merge-patch+json-encoded response
345+
content:
346+
application/merge-patch+json:
347+
schema:
348+
$ref: "#/components/schemas/anotherXmlObject"
349+
/complex-query-param:
350+
get:
351+
parameters:
352+
- name: list-of-strings
353+
in: query
354+
schema:
355+
type: array
356+
items:
357+
$ref: '#/components/schemas/StringObject'
358+
responses:
359+
'200':
360+
description: Success
340361

341362
components:
342363
securitySchemes:

samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ hyper = {version = "0.12", optional = true}
4949
mime_multipart = {version = "0.5", optional = true}
5050
hyper_0_10 = {package = "hyper", version = "0.10", default-features = false, optional=true}
5151
serde_ignored = {version = "0.0.4", optional = true}
52-
tokio = {version = "0.1.17", optional = true}
5352
url = {version = "1.5", optional = true}
5453

5554
# Client-specific
@@ -70,6 +69,7 @@ frunk-enum-core = { version = "0.2.0", optional = true }
7069
clap = "2.25"
7170
error-chain = "0.12"
7271
env_logger = "0.6"
72+
tokio = "0.1.17"
7373
uuid = {version = "0.7", features = ["serde", "v4"]}
7474

7575
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]

samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ extern crate mime_multipart;
4646
extern crate percent_encoding;
4747
#[cfg(any(feature = "client", feature = "server"))]
4848
extern crate serde_ignored;
49-
#[cfg(any(feature = "client", feature = "server"))]
50-
extern crate tokio;
5149

5250
#[cfg(any(feature = "client", feature = "server"))]
5351

samples/server/petstore/rust-server/output/no-example-v3/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ serde_json = "1.0"
3939
# Common between server and client features
4040
hyper = {version = "0.12", optional = true}
4141
serde_ignored = {version = "0.0.4", optional = true}
42-
tokio = {version = "0.1.17", optional = true}
4342
url = {version = "1.5", optional = true}
4443

4544
# Client-specific
@@ -60,6 +59,7 @@ frunk-enum-core = { version = "0.2.0", optional = true }
6059
clap = "2.25"
6160
error-chain = "0.12"
6261
env_logger = "0.6"
62+
tokio = "0.1.17"
6363
uuid = {version = "0.7", features = ["serde", "v4"]}
6464

6565
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]

samples/server/petstore/rust-server/output/no-example-v3/src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ extern crate hyper_openssl;
3939
extern crate percent_encoding;
4040
#[cfg(any(feature = "client", feature = "server"))]
4141
extern crate serde_ignored;
42-
#[cfg(any(feature = "client", feature = "server"))]
43-
extern crate tokio;
4442

4543
#[cfg(any(feature = "client", feature = "server"))]
4644

samples/server/petstore/rust-server/output/openapi-v3/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ uuid = {version = "0.7", features = ["serde", "v4"]}
4545
# Common between server and client features
4646
hyper = {version = "0.12", optional = true}
4747
serde_ignored = {version = "0.0.4", optional = true}
48-
tokio = {version = "0.1.17", optional = true}
4948
url = {version = "1.5", optional = true}
5049

5150
# Client-specific
@@ -66,6 +65,7 @@ frunk-enum-core = { version = "0.2.0", optional = true }
6665
clap = "2.25"
6766
error-chain = "0.12"
6867
env_logger = "0.6"
68+
tokio = "0.1.17"
6969

7070
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]
7171
tokio-openssl = "0.3"

samples/server/petstore/rust-server/output/openapi-v3/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ To run a client, follow one of the following simple steps:
6262

6363
```
6464
cargo run --example client CallbackWithHeaderPost
65+
cargo run --example client ComplexQueryParamGet
6566
cargo run --example client MandatoryRequestHeaderGet
6667
cargo run --example client MergePatchJsonGet
6768
cargo run --example client MultigetGet
@@ -114,6 +115,7 @@ All URIs are relative to *http://localhost*
114115
Method | HTTP request | Description
115116
------------- | ------------- | -------------
116117
[****](docs/default_api.md#) | **POST** /callback-with-header |
118+
[****](docs/default_api.md#) | **GET** /complex-query-param |
117119
[****](docs/default_api.md#) | **GET** /enum_in_path/{path_param} |
118120
[****](docs/default_api.md#) | **GET** /mandatory-request-header |
119121
[****](docs/default_api.md#) | **GET** /merge-patch-json |

samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml

+15
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,21 @@ paths:
345345
description: Success.
346346
servers:
347347
- url: /override
348+
/complex-query-param:
349+
get:
350+
parameters:
351+
- explode: true
352+
in: query
353+
name: list-of-strings
354+
required: false
355+
schema:
356+
items:
357+
$ref: '#/components/schemas/StringObject'
358+
type: array
359+
style: form
360+
responses:
361+
"200":
362+
description: Success
348363
components:
349364
schemas:
350365
EnumWithStarObject:

samples/server/petstore/rust-server/output/openapi-v3/docs/default_api.md

+33
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ All URIs are relative to *http://localhost*
55
Method | HTTP request | Description
66
------------- | ------------- | -------------
77
****](default_api.md#) | **POST** /callback-with-header |
8+
****](default_api.md#) | **GET** /complex-query-param |
89
****](default_api.md#) | **GET** /enum_in_path/{path_param} |
910
****](default_api.md#) | **GET** /mandatory-request-header |
1011
****](default_api.md#) | **GET** /merge-patch-json |
@@ -51,6 +52,38 @@ No authorization required
5152

5253
[[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)
5354

55+
# ****
56+
> (optional)
57+
58+
59+
### Required Parameters
60+
61+
Name | Type | Description | Notes
62+
------------- | ------------- | ------------- | -------------
63+
**optional** | **map[string]interface{}** | optional parameters | nil if no parameters
64+
65+
### Optional Parameters
66+
Optional parameters are passed through a map[string]interface{}.
67+
68+
Name | Type | Description | Notes
69+
------------- | ------------- | ------------- | -------------
70+
**list_of_strings** | [**String**](String.md)| |
71+
72+
### Return type
73+
74+
(empty response body)
75+
76+
### Authorization
77+
78+
No authorization required
79+
80+
### HTTP request headers
81+
82+
- **Content-Type**: Not defined
83+
- **Accept**: Not defined
84+
85+
[[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)
86+
5487
# ****
5588
> (path_param)
5689

samples/server/petstore/rust-server/output/openapi-v3/examples/client/main.rs

+8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use futures::{Future, future, Stream, stream};
3030
use openapi_v3::{Api, ApiNoContext, Client, ContextWrapperExt,
3131
ApiError,
3232
CallbackWithHeaderPostResponse,
33+
ComplexQueryParamGetResponse,
3334
EnumInPathPathParamGetResponse,
3435
MandatoryRequestHeaderGetResponse,
3536
MergePatchJsonGetResponse,
@@ -66,6 +67,7 @@ fn main() {
6667
.help("Sets the operation to run")
6768
.possible_values(&[
6869
"CallbackWithHeaderPost",
70+
"ComplexQueryParamGet",
6971
"MandatoryRequestHeaderGet",
7072
"MergePatchJsonGet",
7173
"MultigetGet",
@@ -136,6 +138,12 @@ fn main() {
136138
));
137139
info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has<XSpanIdString>).get().clone());
138140
},
141+
Some("ComplexQueryParamGet") => {
142+
let result = rt.block_on(client.complex_query_param_get(
143+
Some(&Vec::new())
144+
));
145+
info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has<XSpanIdString>).get().clone());
146+
},
139147
/* Disabled because there's no example.
140148
Some("EnumInPathPathParamGet") => {
141149
let result = rt.block_on(client.enum_in_path_path_param_get(

samples/server/petstore/rust-server/output/openapi-v3/examples/server/server.rs

+11
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ use openapi_v3::{
106106
Api,
107107
ApiError,
108108
CallbackWithHeaderPostResponse,
109+
ComplexQueryParamGetResponse,
109110
EnumInPathPathParamGetResponse,
110111
MandatoryRequestHeaderGetResponse,
111112
MergePatchJsonGetResponse,
@@ -139,6 +140,16 @@ impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
139140
Box::new(future::err("Generic failure".into()))
140141
}
141142

143+
fn complex_query_param_get(
144+
&self,
145+
list_of_strings: Option<&Vec<models::StringObject>>,
146+
context: &C) -> Box<Future<Item=ComplexQueryParamGetResponse, Error=ApiError> + Send>
147+
{
148+
let context = context.clone();
149+
info!("complex_query_param_get({:?}) - X-Span-ID: {:?}", list_of_strings, context.get().0.clone());
150+
Box::new(future::err("Generic failure".into()))
151+
}
152+
142153
fn enum_in_path_path_param_get(
143154
&self,
144155
path_param: models::StringEnum,

samples/server/petstore/rust-server/output/openapi-v3/src/client/mod.rs

+76
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ define_encode_set! {
3636

3737
use {Api,
3838
CallbackWithHeaderPostResponse,
39+
ComplexQueryParamGetResponse,
3940
EnumInPathPathParamGetResponse,
4041
MandatoryRequestHeaderGetResponse,
4142
MergePatchJsonGetResponse,
@@ -346,6 +347,81 @@ impl<C, F> Api<C> for Client<F> where
346347
}))
347348
}
348349

350+
fn complex_query_param_get(
351+
&self,
352+
param_list_of_strings: Option<&Vec<models::StringObject>>,
353+
context: &C) -> Box<dyn Future<Item=ComplexQueryParamGetResponse, Error=ApiError> + Send>
354+
{
355+
let mut uri = format!(
356+
"{}/complex-query-param",
357+
self.base_path
358+
);
359+
360+
// Query parameters
361+
let mut query_string = url::form_urlencoded::Serializer::new("".to_owned());
362+
if let Some(param_list_of_strings) = param_list_of_strings {
363+
query_string.append_pair("list-of-strings", &param_list_of_strings.iter().map(ToString::to_string).collect::<Vec<String>>().join(","));
364+
}
365+
let query_string_str = query_string.finish();
366+
if !query_string_str.is_empty() {
367+
uri += "?";
368+
uri += &query_string_str;
369+
}
370+
371+
let uri = match Uri::from_str(&uri) {
372+
Ok(uri) => uri,
373+
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build URI: {}", err)))),
374+
};
375+
376+
let mut request = match hyper::Request::builder()
377+
.method("GET")
378+
.uri(uri)
379+
.body(Body::empty()) {
380+
Ok(req) => req,
381+
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e))))
382+
};
383+
384+
let header = HeaderValue::from_str((context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str());
385+
request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
386+
Ok(h) => h,
387+
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create X-Span ID header value: {}", e))))
388+
});
389+
390+
Box::new(self.client_service.request(request)
391+
.map_err(|e| ApiError(format!("No response received: {}", e)))
392+
.and_then(|mut response| {
393+
match response.status().as_u16() {
394+
200 => {
395+
let body = response.into_body();
396+
Box::new(
397+
future::ok(
398+
ComplexQueryParamGetResponse::Success
399+
)
400+
) as Box<dyn Future<Item=_, Error=_> + Send>
401+
},
402+
code => {
403+
let headers = response.headers().clone();
404+
Box::new(response.into_body()
405+
.take(100)
406+
.concat2()
407+
.then(move |body|
408+
future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
409+
code,
410+
headers,
411+
match body {
412+
Ok(ref body) => match str::from_utf8(body) {
413+
Ok(body) => Cow::from(body),
414+
Err(e) => Cow::from(format!("<Body was not UTF8: {:?}>", e)),
415+
},
416+
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
417+
})))
418+
)
419+
) as Box<dyn Future<Item=_, Error=_> + Send>
420+
}
421+
}
422+
}))
423+
}
424+
349425
fn enum_in_path_path_param_get(
350426
&self,
351427
param_path_param: models::StringEnum,

0 commit comments

Comments
 (0)