From f32b1463bcb02ae2a1fd08552bd9aeee4c56e507 Mon Sep 17 00:00:00 2001 From: Richard Whitehouse Date: Sat, 29 Feb 2020 19:23:54 +0000 Subject: [PATCH] [Rust Server] Support numeric operation IDs (#5453) * [Rust Server] Support operation IDs which begin with a number * [Rust Server] Add test for a numeric operation ID * Update samples --- .../codegen/languages/RustServerCodegen.java | 5 +- ...ith-fake-endpoints-models-for-testing.yaml | 8 ++ .../README.md | 2 + .../api/openapi.yaml | 9 ++ .../docs/fake_api.md | 23 +++++ .../examples/client.rs | 10 +++ .../examples/server_lib/mod.rs | 8 ++ .../src/client/mod.rs | 73 +++++++++++++++- .../src/lib.rs | 17 ++++ .../src/server/mod.rs | 86 ++++++++++++++----- 10 files changed, 219 insertions(+), 22 deletions(-) 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 82d7bf93f4a..fcfd8f496e7 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 @@ -410,7 +410,10 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig { public String toOperationId(String operationId) { // method name cannot use reserved keyword, e.g. return if (isReservedWord(operationId)) { - LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + camelize(sanitizeName("call_" + operationId))); + LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + camelize("call_" + operationId)); + operationId = "call_" + operationId; + } else if (operationId.matches("\\d.*")) { + LOGGER.warn(operationId + " cannot be used as method name because it starts with a digit. Renamed to " + camelize("call_" + operationId)); operationId = "call_" + operationId; } diff --git a/modules/openapi-generator/src/test/resources/2_0/rust-server/petstore-with-fake-endpoints-models-for-testing.yaml b/modules/openapi-generator/src/test/resources/2_0/rust-server/petstore-with-fake-endpoints-models-for-testing.yaml index c07ed5e8533..8f081c09dc1 100644 --- a/modules/openapi-generator/src/test/resources/2_0/rust-server/petstore-with-fake-endpoints-models-for-testing.yaml +++ b/modules/openapi-generator/src/test/resources/2_0/rust-server/petstore-with-fake-endpoints-models-for-testing.yaml @@ -965,6 +965,14 @@ paths: responses: 200: description: Success + /fake/operation-with-numeric-id: + get: + tags: + - fake + operationId: 123example + responses: + 200: + description: success /fake/response-with-numerical-description: get: tags: diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/README.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/README.md index b420ca26817..2d5aaf71eff 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/README.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/README.md @@ -62,6 +62,7 @@ To run a client, follow one of the following simple steps: ``` cargo run --example client TestSpecialTags +cargo run --example client Call123example cargo run --example client FakeOuterBooleanSerialize cargo run --example client FakeOuterCompositeSerialize cargo run --example client FakeOuterNumberSerialize @@ -129,6 +130,7 @@ All URIs are relative to *http://petstore.swagger.io:80/v2* Method | HTTP request | Description ------------- | ------------- | ------------- [**test_special_tags**](docs/another_fake_api.md#test_special_tags) | **PATCH** /another-fake/dummy | To test special tags +[**123example**](docs/fake_api.md#123example) | **GET** /fake/operation-with-numeric-id | [**fakeOuterBooleanSerialize**](docs/fake_api.md#fakeOuterBooleanSerialize) | **POST** /fake/outer/boolean | [**fakeOuterCompositeSerialize**](docs/fake_api.md#fakeOuterCompositeSerialize) | **POST** /fake/outer/composite | [**fakeOuterNumberSerialize**](docs/fake_api.md#fakeOuterNumberSerialize) | **POST** /fake/outer/number | diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/api/openapi.yaml b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/api/openapi.yaml index 5aac6fd8f8b..27f96b0bef1 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/api/openapi.yaml +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/api/openapi.yaml @@ -1001,6 +1001,15 @@ paths: description: Success tags: - fake + /fake/operation-with-numeric-id: + get: + operationId: 123example + responses: + "200": + content: {} + description: success + tags: + - fake /fake/response-with-numerical-description: get: operationId: fake_response_with_numerical_description diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/fake_api.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/fake_api.md index 2cedd4a049b..8391c28dd49 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/fake_api.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/fake_api.md @@ -4,6 +4,7 @@ All URIs are relative to *http://petstore.swagger.io:80/v2* Method | HTTP request | Description ------------- | ------------- | ------------- +**123example**](fake_api.md#123example) | **GET** /fake/operation-with-numeric-id | **fakeOuterBooleanSerialize**](fake_api.md#fakeOuterBooleanSerialize) | **POST** /fake/outer/boolean | **fakeOuterCompositeSerialize**](fake_api.md#fakeOuterCompositeSerialize) | **POST** /fake/outer/composite | **fakeOuterNumberSerialize**](fake_api.md#fakeOuterNumberSerialize) | **POST** /fake/outer/number | @@ -18,6 +19,28 @@ Method | HTTP request | Description **testJsonFormData**](fake_api.md#testJsonFormData) | **GET** /fake/jsonFormData | test json serialization of form data +# **123example** +> 123example() + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **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) + # **fakeOuterBooleanSerialize** > bool fakeOuterBooleanSerialize(optional) diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/client.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/client.rs index e7a1024d328..790b8712b23 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/client.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/client.rs @@ -15,6 +15,7 @@ use futures::{Future, future, Stream, stream}; use petstore_with_fake_endpoints_models_for_testing::{Api, ApiNoContext, Client, ContextWrapperExt, ApiError, TestSpecialTagsResponse, + Call123exampleResponse, FakeOuterBooleanSerializeResponse, FakeOuterCompositeSerializeResponse, FakeOuterNumberSerializeResponse, @@ -57,6 +58,8 @@ fn main() { .help("Sets the operation to run") .possible_values(&[ + "Call123example", + "FakeOuterBooleanSerialize", "FakeOuterCompositeSerialize", @@ -159,6 +162,13 @@ fn main() { }, */ + Some("Call123example") => { + let mut rt = tokio::runtime::Runtime::new().unwrap(); + let result = rt.block_on(client.call123example( + )); + println!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + Some("FakeOuterBooleanSerialize") => { let mut rt = tokio::runtime::Runtime::new().unwrap(); let result = rt.block_on(client.fake_outer_boolean_serialize( diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server_lib/mod.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server_lib/mod.rs index 756e0ad5016..2aa9ae502d2 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server_lib/mod.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server_lib/mod.rs @@ -18,6 +18,7 @@ use swagger::{Has, XSpanIdString}; use petstore_with_fake_endpoints_models_for_testing::{Api, ApiError, TestSpecialTagsResponse, + Call123exampleResponse, FakeOuterBooleanSerializeResponse, FakeOuterCompositeSerializeResponse, FakeOuterNumberSerializeResponse, @@ -75,6 +76,13 @@ impl Api for Server where C: Has{ } + fn call123example(&self, context: &C) -> Box + Send> { + let context = context.clone(); + println!("call123example() - X-Span-ID: {:?}", context.get().0.clone()); + Box::new(futures::failed("Generic failure".into())) + } + + fn fake_outer_boolean_serialize(&self, body: Option, context: &C) -> Box + Send> { let context = context.clone(); println!("fake_outer_boolean_serialize({:?}) - X-Span-ID: {:?}", body, context.get().0.clone()); 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 d7c671cf599..c790e4f4513 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 @@ -33,6 +33,7 @@ use serde_xml_rs; use {Api, TestSpecialTagsResponse, + Call123exampleResponse, FakeOuterBooleanSerializeResponse, FakeOuterCompositeSerializeResponse, FakeOuterNumberSerializeResponse, @@ -324,6 +325,77 @@ impl Api for Client where } + fn call123example(&self, context: &C) -> Box + Send> { + let mut uri = format!( + "{}/v2/fake/operation-with-numeric-id", + 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("GET") + .uri(uri) + .body(Body::empty()) { + Ok(req) => req, + Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", 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() { + 200 => { + let body = response.into_body(); + Box::new( + future::ok( + Call123exampleResponse::Success + ) + ) 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 fake_outer_boolean_serialize(&self, param_body: Option, context: &C) -> Box + Send> { let mut uri = format!( "{}/v2/fake/outer/boolean", @@ -351,7 +423,6 @@ impl Api for Client where Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e)))) }; - // Body parameter let body = param_body.map(|ref body| { serde_json::to_string(body).expect("impossible to fail to serialize") }); 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 cf3a9bd96f6..91307a293b6 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 @@ -85,6 +85,12 @@ pub enum TestSpecialTagsResponse { ( models::Client ) } +#[derive(Debug, PartialEq)] +pub enum Call123exampleResponse { + /// success + Success +} + #[derive(Debug, PartialEq)] pub enum FakeOuterBooleanSerializeResponse { /// Output boolean @@ -361,6 +367,9 @@ pub trait Api { fn test_special_tags(&self, body: models::Client, context: &C) -> Box + Send>; + fn call123example(&self, context: &C) -> Box + Send>; + + fn fake_outer_boolean_serialize(&self, body: Option, context: &C) -> Box + Send>; @@ -468,6 +477,9 @@ pub trait ApiNoContext { fn test_special_tags(&self, body: models::Client) -> Box + Send>; + fn call123example(&self) -> Box + Send>; + + fn fake_outer_boolean_serialize(&self, body: Option) -> Box + Send>; @@ -588,6 +600,11 @@ impl<'a, T: Api, C> ApiNoContext for ContextWrapper<'a, T, C> { } + fn call123example(&self) -> Box + Send> { + self.api().call123example(&self.context()) + } + + fn fake_outer_boolean_serialize(&self, body: Option) -> Box + Send> { self.api().fake_outer_boolean_serialize(body, &self.context()) } 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 8d02b06cd93..611e16204a3 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 @@ -24,6 +24,7 @@ pub use swagger::auth::Authorization; use {Api, TestSpecialTagsResponse, + Call123exampleResponse, FakeOuterBooleanSerializeResponse, FakeOuterCompositeSerializeResponse, FakeOuterNumberSerializeResponse, @@ -76,6 +77,7 @@ mod paths { r"^/v2/fake/hyphenParam/(?P[^/?#]*)$", r"^/v2/fake/inline-additionalProperties$", r"^/v2/fake/jsonFormData$", + r"^/v2/fake/operation-with-numeric-id$", r"^/v2/fake/outer/boolean$", r"^/v2/fake/outer/composite$", r"^/v2/fake/outer/number$", @@ -110,41 +112,42 @@ mod paths { } pub static ID_FAKE_INLINE_ADDITIONALPROPERTIES: usize = 4; pub static ID_FAKE_JSONFORMDATA: usize = 5; - pub static ID_FAKE_OUTER_BOOLEAN: usize = 6; - pub static ID_FAKE_OUTER_COMPOSITE: usize = 7; - pub static ID_FAKE_OUTER_NUMBER: usize = 8; - pub static ID_FAKE_OUTER_STRING: usize = 9; - pub static ID_FAKE_RESPONSE_WITH_NUMERICAL_DESCRIPTION: usize = 10; - pub static ID_FAKE_CLASSNAME_TEST: usize = 11; - pub static ID_PET: usize = 12; - pub static ID_PET_FINDBYSTATUS: usize = 13; - pub static ID_PET_FINDBYTAGS: usize = 14; - pub static ID_PET_PETID: usize = 15; + pub static ID_FAKE_OPERATION_WITH_NUMERIC_ID: usize = 6; + pub static ID_FAKE_OUTER_BOOLEAN: usize = 7; + pub static ID_FAKE_OUTER_COMPOSITE: usize = 8; + pub static ID_FAKE_OUTER_NUMBER: usize = 9; + pub static ID_FAKE_OUTER_STRING: usize = 10; + pub static ID_FAKE_RESPONSE_WITH_NUMERICAL_DESCRIPTION: usize = 11; + pub static ID_FAKE_CLASSNAME_TEST: usize = 12; + pub static ID_PET: usize = 13; + pub static ID_PET_FINDBYSTATUS: usize = 14; + pub static ID_PET_FINDBYTAGS: usize = 15; + pub static ID_PET_PETID: usize = 16; lazy_static! { pub static ref REGEX_PET_PETID: regex::Regex = regex::Regex::new(r"^/v2/pet/(?P[^/?#]*)$") .expect("Unable to create regex for PET_PETID"); } - pub static ID_PET_PETID_UPLOADIMAGE: usize = 16; + pub static ID_PET_PETID_UPLOADIMAGE: usize = 17; lazy_static! { pub static ref REGEX_PET_PETID_UPLOADIMAGE: regex::Regex = regex::Regex::new(r"^/v2/pet/(?P[^/?#]*)/uploadImage$") .expect("Unable to create regex for PET_PETID_UPLOADIMAGE"); } - pub static ID_STORE_INVENTORY: usize = 17; - pub static ID_STORE_ORDER: usize = 18; - pub static ID_STORE_ORDER_ORDER_ID: usize = 19; + pub static ID_STORE_INVENTORY: usize = 18; + pub static ID_STORE_ORDER: usize = 19; + pub static ID_STORE_ORDER_ORDER_ID: usize = 20; lazy_static! { pub static ref REGEX_STORE_ORDER_ORDER_ID: regex::Regex = regex::Regex::new(r"^/v2/store/order/(?P[^/?#]*)$") .expect("Unable to create regex for STORE_ORDER_ORDER_ID"); } - pub static ID_USER: usize = 20; - pub static ID_USER_CREATEWITHARRAY: usize = 21; - pub static ID_USER_CREATEWITHLIST: usize = 22; - pub static ID_USER_LOGIN: usize = 23; - pub static ID_USER_LOGOUT: usize = 24; - pub static ID_USER_USERNAME: usize = 25; + pub static ID_USER: usize = 21; + pub static ID_USER_CREATEWITHARRAY: usize = 22; + pub static ID_USER_CREATEWITHLIST: usize = 23; + pub static ID_USER_LOGIN: usize = 24; + pub static ID_USER_LOGOUT: usize = 25; + pub static ID_USER_USERNAME: usize = 26; lazy_static! { pub static ref REGEX_USER_USERNAME: regex::Regex = regex::Regex::new(r"^/v2/user/(?P[^/?#]*)$") @@ -319,6 +322,46 @@ where ) as Self::Future }, + // Call123example - GET /fake/operation-with-numeric-id + &hyper::Method::GET if path.matched(paths::ID_FAKE_OPERATION_WITH_NUMERIC_ID) => { + Box::new({ + {{ + Box::new( + api_impl.call123example( + &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 { + Call123exampleResponse::Success + + + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 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) + } + )) + }} + }) as Self::Future + }, + // FakeOuterBooleanSerialize - POST /fake/outer/boolean &hyper::Method::POST if path.matched(paths::ID_FAKE_OUTER_BOOLEAN) => { // Body parameters (note that non-required body parameters will ignore garbage @@ -3287,6 +3330,9 @@ impl RequestParser for ApiRequestParser { // TestSpecialTags - PATCH /another-fake/dummy &hyper::Method::PATCH if path.matched(paths::ID_ANOTHER_FAKE_DUMMY) => Ok("TestSpecialTags"), + // Call123example - GET /fake/operation-with-numeric-id + &hyper::Method::GET if path.matched(paths::ID_FAKE_OPERATION_WITH_NUMERIC_ID) => Ok("Call123example"), + // FakeOuterBooleanSerialize - POST /fake/outer/boolean &hyper::Method::POST if path.matched(paths::ID_FAKE_OUTER_BOOLEAN) => Ok("FakeOuterBooleanSerialize"),