Skip to content

Commit ccf8589

Browse files
azriel-healthpointdsteeley
authored andcommitted
[Rust Server] Update templates so generated client and server compile (OpenAPITools#17876)
1 parent 4f37ffc commit ccf8589

17 files changed

+142
-127
lines changed

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ client = [
5050
"serde_ignored", "regex", "percent-encoding", "lazy_static",
5151
{{/hasCallbacks}}
5252
{{! Anything added to the list below, should probably be added to the callbacks list below }}
53-
"hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
53+
"hyper", "hyper-util/http1", "hyper-util/http2", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
5454
]
5555
server = [
5656
{{#apiUsesMultipart}}
@@ -89,7 +89,7 @@ openssl = { version = "0.10", optional = true }
8989
async-trait = "0.1.88"
9090
chrono = { version = "0.4", features = ["serde"] }
9191
futures = "0.3"
92-
swagger = { version = "7.0.0-rc1", features = ["serdejson", "server", "client", "tls", "tcp"] }
92+
swagger = { version = "7.0.0-rc1", features = ["serdejson", "server", "client", "tls"] }
9393
log = "0.4.27"
9494
mime = "0.3"
9595

@@ -114,7 +114,10 @@ uuid = { version = "1.17.0", features = ["serde", "v4"]}
114114
{{/apiUsesUuid}}
115115

116116
# Common between server and client features
117+
bytes = "1.10.1"
118+
http-body-util = "0.1.3"
117119
hyper = { version = "1.6", features = ["full"], optional = true }
120+
hyper-util = { version = "0.1.12", features = ["service"] }
118121
{{#apiUsesMultipartRelated}}
119122
mime_multipart = { version = "0.5", optional = true }
120123
hyper_0_10 = {package = "hyper", version = "0.10", default-features = false, optional=true }
@@ -126,6 +129,7 @@ url = { version = "2.5", optional = true }
126129
{{#usesUrlEncodedForm}}
127130
serde_urlencoded = { version = "0.6.1", optional = true }
128131
{{/usesUrlEncodedForm}}
132+
tower-service = "0.3.3"
129133

130134
# Server, and client callback-specific
131135
lazy_static = { version = "1.5", optional = true }
@@ -136,8 +140,7 @@ regex = { version = "1.11", optional = true }
136140
anyhow = { version = "1", optional = true }
137141
clap-verbosity-flag = { version = "3.0", optional = true }
138142
simple_logger = { version = "5.0", features = ["stderr"], optional = true }
139-
structopt = { version = "0.3", optional = true }
140-
tokio = { version = "1.45", features = ["rt-threaded", "macros", "stream"], optional = true }
143+
tokio = { version = "1.45", features = ["rt-multi-thread", "macros"], optional = true }
141144
{{#apiHasDeleteMethods}}
142145
dialoguer = { version = "0.8", optional = true }
143146
{{/apiHasDeleteMethods}}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::BTreeSet;
22
use crate::server::Authorization;
33
use serde::{Deserialize, Serialize};
4-
use swagger::{ApiError, auth::{Basic, Bearer}};
4+
use swagger::{ApiError, auth::AuthData};
55

66
#[derive(Debug, Serialize, Deserialize)]
77
pub struct Claims {
@@ -17,14 +17,14 @@ pub struct Claims {
1717
pub trait AuthenticationApi {
1818
1919
/// Method should be implemented (see example-code) to map Bearer-token to an Authorization
20-
fn bearer_authorization(&self, token: &Bearer) -> Result<Authorization, ApiError>;
20+
fn bearer_authorization(&self, token: &str) -> Result<Authorization, ApiError>;
2121
2222
/// Method should be implemented (see example-code) to map ApiKey to an Authorization
2323
fn apikey_authorization(&self, token: &str) -> Result<Authorization, ApiError>;
2424
2525
/// Method should be implemented (see example-code) to map Basic (Username:password) to an Authorization
26-
fn basic_authorization(&self, basic: &Basic) -> Result<Authorization, ApiError>;
27-
}
26+
fn basic_authorization(&self, username: &str, password: &str) -> Result<Authorization, ApiError>;
27+
}
2828

2929
// Implement it for AllowAllAuthenticator (dummy is needed, but should not used as we have Bearer authorization)
3030
use swagger::auth::{AllowAllAuthenticator, RcBound, Scopes};
@@ -46,7 +46,7 @@ where
4646
RC::Result: Send + 'static {
4747
4848
/// Get method to map Bearer-token to an Authorization
49-
fn bearer_authorization(&self, _token: &Bearer) -> Result<Authorization, ApiError> {
49+
fn bearer_authorization(&self, _token: &str) -> Result<Authorization, ApiError> {
5050
Ok(dummy_authorization())
5151
}
5252

@@ -56,7 +56,7 @@ where
5656
}
5757

5858
/// Get method to map basic token to an Authorization
59-
fn basic_authorization(&self, _basic: &Basic) -> Result<Authorization, ApiError> {
59+
fn basic_authorization(&self, _username: &str, _password: &str) -> Result<Authorization, ApiError> {
6060
Ok(dummy_authorization())
6161
}
6262
}

modules/openapi-generator/src/main/resources/rust-server/cargo-config

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ rustflags = [
66

77
"-W", "trivial_numeric_casts", # detects trivial casts of numeric types which could be removed
88

9-
"-W", "unsafe_code", # usage of `unsafe` code
9+
# unsafe is used in `TokioIo` bridging code copied from `hyper`.
10+
# "-W", "unsafe_code", # usage of `unsafe` code
1011

1112
"-W", "unused_qualifications", # detects unnecessarily qualified names
1213

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use async_trait::async_trait;
2+
use bytes::Bytes;
23
use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt};
4+
use http_body_util::{combinators::BoxBody, Full};
35
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
4-
use hyper::{Body, Request, Response, service::Service, Uri};
6+
use hyper::{body::{Body, Incoming}, Request, Response, service::Service, Uri};
57
use percent_encoding::{utf8_percent_encode, AsciiSet};
68
use std::borrow::Cow;
79
use std::convert::TryInto;
@@ -18,6 +20,7 @@ use std::string::ToString;
1820
use std::task::{Context, Poll};
1921
use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString};
2022
use url::form_urlencoded;
23+
use tower_service::Service as _;
2124

2225
{{#apiUsesMultipartFormData}}
2326
use mime::Mime;

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

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ fn into_base_path(input: impl TryInto<Uri, Error=hyper::http::uri::InvalidUri>,
2929
/// A client that implements the API by making HTTP calls out to a server.
3030
pub struct Client<S, C> where
3131
S: Service<
32-
(Request<Body>, C),
33-
Response=Response<Body>> + Clone + Sync + Send + 'static,
32+
(Request<BoxBody<Bytes, Infallible>>, C),
33+
Response=Response<Incoming>> + Clone + Sync + Send + 'static,
3434
S::Future: Send + 'static,
3535
S::Error: Into<crate::ServiceError> + fmt::Display,
3636
C: Clone + Send + Sync + 'static
@@ -47,8 +47,8 @@ pub struct Client<S, C> where
4747

4848
impl<S, C> fmt::Debug for Client<S, C> where
4949
S: Service<
50-
(Request<Body>, C),
51-
Response=Response<Body>> + Clone + Sync + Send + 'static,
50+
(Request<BoxBody<Bytes, Infallible>>, C),
51+
Response=Response<Incoming>> + Clone + Sync + Send + 'static,
5252
S::Future: Send + 'static,
5353
S::Error: Into<crate::ServiceError> + fmt::Display,
5454
C: Clone + Send + Sync + 'static
@@ -60,8 +60,8 @@ impl<S, C> fmt::Debug for Client<S, C> where
6060
6161
impl<S, C> Clone for Client<S, C> where
6262
S: Service<
63-
(Request<Body>, C),
64-
Response=Response<Body>> + Clone + Sync + Send + 'static,
63+
(Request<BoxBody<Bytes, Infallible>>, C),
64+
Response=Response<Incoming>> + Clone + Sync + Send + 'static,
6565
S::Future: Send + 'static,
6666
S::Error: Into<crate::ServiceError> + fmt::Display,
6767
C: Clone + Send + Sync + 'static
@@ -75,8 +75,19 @@ impl<S, C> Clone for Client<S, C> where
7575
}
7676
}
7777

78-
impl<Connector, C> Client<DropContextService<hyper::client::Client<Connector, Body>, C>, C> where
79-
Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
78+
impl<Connector, C> Client<
79+
DropContextService<
80+
hyper_util::service::TowerToHyperService<
81+
hyper_util::client::legacy::Client<
82+
Connector,
83+
BoxBody<Bytes, Infallible>
84+
>
85+
>,
86+
C
87+
>,
88+
C
89+
> where
90+
Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static,
8091
C: Clone + Send + Sync + 'static,
8192
{
8293
/// Create a client with a custom implementation of hyper::client::Connect.
@@ -99,8 +110,8 @@ impl<Connector, C> Client<DropContextService<hyper::client::Client<Connector, Bo
99110
connector: Connector,
100111
) -> Result<Self, ClientInitError>
101112
{
102-
let client_service = hyper::client::Client::builder().build(connector);
103-
let client_service = DropContextService::new(client_service);
113+
let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector);
114+
let client_service = DropContextService::new(hyper_util::service::TowerToHyperService::new(client_service));
104115
105116
Ok(Self {
106117
client_service,
@@ -112,26 +123,19 @@ impl<Connector, C> Client<DropContextService<hyper::client::Client<Connector, Bo
112123
113124
#[derive(Debug, Clone)]
114125
pub enum HyperClient {
115-
Http(hyper::client::Client<hyper::client::HttpConnector, Body>),
116-
Https(hyper::client::Client<HttpsConnector, Body>),
126+
Http(hyper_util::client::legacy::Client<hyper_util::client::legacy::connect::HttpConnector, BoxBody<Bytes, Infallible>>),
127+
Https(hyper_util::client::legacy::Client<HttpsConnector, BoxBody<Bytes, Infallible>>),
117128
}
118129
119-
impl Service<Request<Body>> for HyperClient {
120-
type Response = Response<Body>;
121-
type Error = hyper::Error;
122-
type Future = hyper::client::ResponseFuture;
123-
124-
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
125-
match self {
126-
HyperClient::Http(client) => client.poll_ready(cx),
127-
HyperClient::Https(client) => client.poll_ready(cx),
128-
}
129-
}
130+
impl Service<Request<BoxBody<Bytes, Infallible>>> for HyperClient {
131+
type Response = Response<Incoming>;
132+
type Error = hyper_util::client::legacy::Error;
133+
type Future = hyper_util::client::legacy::ResponseFuture;
130134
131-
fn call(&mut self, req: Request<Body>) -> Self::Future {
135+
fn call(&self, req: Request<BoxBody<Bytes, Infallible>>) -> Self::Future {
132136
match self {
133-
HyperClient::Http(client) => client.call(req),
134-
HyperClient::Https(client) => client.call(req)
137+
HyperClient::Http(client) => client.request(req),
138+
HyperClient::Https(client) => client.request(req)
135139
}
136140
}
137141
}
@@ -155,13 +159,13 @@ impl<C> Client<DropContextService<HyperClient, C>, C> where
155159
156160
let client_service = match scheme.as_str() {
157161
"http" => {
158-
HyperClient::Http(hyper::client::Client::builder().build(connector.build()))
162+
HyperClient::Http(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector.build()))
159163
},
160164
"https" => {
161165
let connector = connector.https()
162166
.build()
163167
.map_err(ClientInitError::SslError)?;
164-
HyperClient::Https(hyper::client::Client::builder().build(connector))
168+
HyperClient::Https(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector))
165169
},
166170
_ => {
167171
return Err(ClientInitError::InvalidScheme);
@@ -178,7 +182,18 @@ impl<C> Client<DropContextService<HyperClient, C>, C> where
178182
}
179183
}
180184

181-
impl<C> Client<DropContextService<hyper::client::Client<hyper::client::HttpConnector, Body>, C>, C> where
185+
impl<C> Client<
186+
DropContextService<
187+
hyper_util::service::TowerToHyperService<
188+
hyper_util::client::legacy::Client<
189+
HttpsConnector,
190+
BoxBody<Bytes, Infallible>
191+
>
192+
>,
193+
C
194+
>,
195+
C
196+
> where
182197
C: Clone + Send + Sync + 'static
183198
{
184199
/// Create an HTTP client.
@@ -200,7 +215,18 @@ type HttpsConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;
200215
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
201216
type HttpsConnector = hyper_openssl::HttpsConnector<hyper::client::HttpConnector>;
202217

203-
impl<C> Client<DropContextService<hyper::client::Client<HttpsConnector, Body>, C>, C> where
218+
impl<C> Client<
219+
DropContextService<
220+
hyper_util::service::TowerToHyperService<
221+
hyper_util::client::legacy::Client<
222+
HttpsConnector,
223+
BoxBody<Bytes, Infallible>
224+
>
225+
>,
226+
C
227+
>,
228+
C
229+
> where
204230
C: Clone + Send + Sync + 'static
205231
{
206232
/// Create a client with a TLS connection to the server
@@ -268,8 +294,8 @@ impl<C> Client<DropContextService<hyper::client::Client<HttpsConnector, Body>, C
268294

269295
impl<S, C> Client<S, C> where
270296
S: Service<
271-
(Request<Body>, C),
272-
Response=Response<Body>> + Clone + Sync + Send + 'static,
297+
(Request<BoxBody<Bytes, Infallible>>, C),
298+
Response=Response<Incoming>> + Clone + Sync + Send + 'static,
273299
S::Future: Send + 'static,
274300
S::Error: Into<crate::ServiceError> + fmt::Display,
275301
C: Clone + Send + Sync + 'static
@@ -331,22 +357,19 @@ impl Error for ClientInitError {
331357
}
332358
}
333359
360+
fn body_from_string(s: String) -> BoxBody<Bytes, Infallible> {
361+
BoxBody::new(Full::new(Bytes::from(s)))
362+
}
363+
334364
#[async_trait]
335365
impl<S, C> Api<C> for Client<S, C> where
336366
S: Service<
337-
(Request<Body>, C),
338-
Response=Response<Body>> + Clone + Sync + Send + 'static,
367+
(Request<BoxBody<Bytes, Infallible>>, C),
368+
Response=Response<Incoming>> + Clone + Sync + Send + 'static,
339369
S::Future: Send + 'static,
340370
S::Error: Into<crate::ServiceError> + fmt::Display,
341371
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<AuthData>>{{/hasAuthMethods}} + Clone + Send + Sync + 'static,
342372
{
343-
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), crate::ServiceError>> {
344-
match self.client_service.clone().poll_ready(cx) {
345-
Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
346-
Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)),
347-
Poll::Pending => Poll::Pending,
348-
}
349-
}
350373
351374
{{#apiInfo}}
352375
{{#apis}}

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
let mut request = match Request::builder()
8282
.method("{{{vendorExtensions.x-http-method}}}")
8383
.uri(uri)
84-
.body(Body::empty()) {
84+
.body(BoxBody::new(http_body_util::Empty::new())) {
8585
Ok(req) => req,
8686
Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
8787
};
@@ -208,9 +208,10 @@
208208
{{/headers}}
209209
{{#dataType}}
210210
let body = response.into_body();
211-
let body = body
212-
.into_raw()
213-
.map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?;
211+
let body = http_body_util::BodyExt::collect(body)
212+
.await
213+
.map(|f| f.to_bytes().to_vec())
214+
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))?;
214215

215216
{{>client-response-body-instance}}
216217

@@ -248,9 +249,9 @@
248249
{{/responses}}
249250
code => {
250251
let headers = response.headers().clone();
251-
let body = response.into_body()
252-
.take(100)
253-
.into_raw().await;
252+
let body = http_body_util::BodyExt::collect(response.into_body())
253+
.await
254+
.map(|f| f.to_bytes().to_vec());
254255
Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
255256
code,
256257
headers,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
});
2222

2323
// Add the message body to the request object.
24-
*request.body_mut() = Body::from(body);
24+
*request.body_mut() = BoxBody::new(Full::new(Bytes::from(body)));
2525
{{/x-consumes-multipart-related}}
2626
{{#x-consumes-form}}
2727

@@ -94,7 +94,7 @@
9494
let body = serde_json::to_string(&param_{{{paramName}}}).expect("impossible to fail to serialize");
9595
{{/x-consumes-json}}
9696
{{/vendorExtensions}}
97-
*request.body_mut() = Body::from(body);
97+
*request.body_mut() = body_from_string(body);
9898
{{^required}}
9999
}
100100
{{/required}}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
(body_string, multipart_header)
5858
};
5959

60-
*request.body_mut() = Body::from(body_string);
60+
*request.body_mut() = body_from_string(body_string);
6161

6262
request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(&multipart_header) {
6363
Ok(h) => h,

0 commit comments

Comments
 (0)