[rust-server] asynchronous support via hyper v0.11 (#7896)

* End use of deprecated openssl method

* Enhance rust-server to use hyper 0.11 to support handling operations asynchronously

The changes are complete and working (at least for microservices tested within Metaswitch).  This isn't completely compatible with the (previous/current) synchronous swagger-codegen.  Specifically,

*   `Client` is no longer `Send + Sync`
*   Api implementations used by Server are no longer expected to be `Send + Sync` (which is good, because it's quite hard if `Client` isn't)
*   the code to create `Client`s and `Server`s, and hook them into `hyper` or `tokio` is different.

Importantly, though, the business logic itself should be unchanged.

* Re-adds the `basePath` element to all server endpoints. This mean clients and servers can talk to each other again.

* Fix multipart formdata codegen

* Fix up handling of multipart messages
* Fix server -> client multipart message response
* Correct handling of optional file types

* Add authorization header to requests with basic auth

* Add client support for `application/x-www-form-urlencoded`

* Import uuid library if headers use UUID type

* Add BASE_PATH to the server module.

* Wrap client connector

* Support both query and body parameters on the same operation
This commit is contained in:
Benjamin Gill
2018-04-02 03:32:45 +01:00
committed by William Cheng
parent c8650d0e34
commit 6c7813e79c
31 changed files with 7543 additions and 5801 deletions

View File

@@ -7,8 +7,20 @@ mod errors {
}
pub use self::errors::*;
use std::io;
use hyper;
use petstore_api;
/// Instantiate a new server.
pub fn server() -> Result<server::Server> {
Ok(server::Server {})
pub struct NewService;
impl hyper::server::NewService for NewService {
type Request = (hyper::Request, petstore_api::Context);
type Response = hyper::Response;
type Error = hyper::Error;
type Instance = petstore_api::server::Service<server::Server>;
/// Instantiate a new server.
fn new_service(&self) -> io::Result<Self::Instance> {
Ok(petstore_api::server::Service::new(server::Server))
}
}

View File

@@ -7,10 +7,12 @@ use chrono;
use futures::Stream;
use std::collections::HashMap;
use std::io::Error;
use swagger;
use petstore_api::{Api, ApiError, Context,
TestSpecialTagsResponse,
TestBodyWithQueryParamsResponse,
FakeOuterBooleanSerializeResponse,
FakeOuterCompositeSerializeResponse,
FakeOuterNumberSerializeResponse,
@@ -50,133 +52,140 @@ pub struct Server;
impl Api for Server {
/// To test special tags
fn test_special_tags(&self, body: models::Client, context: &Context) -> Box<Future<Item=TestSpecialTagsResponse, Error=ApiError> + Send> {
fn test_special_tags(&self, body: models::Client, context: &Context) -> Box<Future<Item=TestSpecialTagsResponse, Error=ApiError>> {
let context = context.clone();
println!("test_special_tags({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
fn fake_outer_boolean_serialize(&self, body: Option<models::OuterBoolean>, context: &Context) -> Box<Future<Item=FakeOuterBooleanSerializeResponse, Error=ApiError> + Send> {
fn test_body_with_query_params(&self, body: models::User, query: String, context: &Context) -> Box<Future<Item=TestBodyWithQueryParamsResponse, Error=ApiError>> {
let context = context.clone();
println!("test_body_with_query_params({:?}, \"{}\") - X-Span-ID: {:?}", body, query, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
fn fake_outer_boolean_serialize(&self, body: Option<models::OuterBoolean>, context: &Context) -> Box<Future<Item=FakeOuterBooleanSerializeResponse, Error=ApiError>> {
let context = context.clone();
println!("fake_outer_boolean_serialize({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
fn fake_outer_composite_serialize(&self, body: Option<models::OuterComposite>, context: &Context) -> Box<Future<Item=FakeOuterCompositeSerializeResponse, Error=ApiError> + Send> {
fn fake_outer_composite_serialize(&self, body: Option<models::OuterComposite>, context: &Context) -> Box<Future<Item=FakeOuterCompositeSerializeResponse, Error=ApiError>> {
let context = context.clone();
println!("fake_outer_composite_serialize({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
fn fake_outer_number_serialize(&self, body: Option<models::OuterNumber>, context: &Context) -> Box<Future<Item=FakeOuterNumberSerializeResponse, Error=ApiError> + Send> {
fn fake_outer_number_serialize(&self, body: Option<models::OuterNumber>, context: &Context) -> Box<Future<Item=FakeOuterNumberSerializeResponse, Error=ApiError>> {
let context = context.clone();
println!("fake_outer_number_serialize({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
fn fake_outer_string_serialize(&self, body: Option<models::OuterString>, context: &Context) -> Box<Future<Item=FakeOuterStringSerializeResponse, Error=ApiError> + Send> {
fn fake_outer_string_serialize(&self, body: Option<models::OuterString>, context: &Context) -> Box<Future<Item=FakeOuterStringSerializeResponse, Error=ApiError>> {
let context = context.clone();
println!("fake_outer_string_serialize({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// To test \"client\" model
fn test_client_model(&self, body: models::Client, context: &Context) -> Box<Future<Item=TestClientModelResponse, Error=ApiError> + Send> {
fn test_client_model(&self, body: models::Client, context: &Context) -> Box<Future<Item=TestClientModelResponse, Error=ApiError>> {
let context = context.clone();
println!("test_client_model({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트
fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, integer: Option<i32>, int32: Option<i32>, int64: Option<i64>, float: Option<f32>, string: Option<String>, binary: Option<swagger::ByteArray>, date: Option<chrono::DateTime<chrono::Utc>>, date_time: Option<chrono::DateTime<chrono::Utc>>, password: Option<String>, callback: Option<String>, context: &Context) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError> + Send> {
fn test_endpoint_parameters(&self, number: f64, double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, integer: Option<i32>, int32: Option<i32>, int64: Option<i64>, float: Option<f32>, string: Option<String>, binary: Option<swagger::ByteArray>, date: Option<chrono::DateTime<chrono::Utc>>, date_time: Option<chrono::DateTime<chrono::Utc>>, password: Option<String>, callback: Option<String>, context: &Context) -> Box<Future<Item=TestEndpointParametersResponse, Error=ApiError>> {
let context = context.clone();
println!("test_endpoint_parameters({}, {}, \"{}\", {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", number, double, pattern_without_delimiter, byte, integer, int32, int64, float, string, binary, date, date_time, password, callback, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// To test enum parameters
fn test_enum_parameters(&self, enum_form_string_array: Option<&Vec<String>>, enum_form_string: Option<String>, enum_header_string_array: Option<&Vec<String>>, enum_header_string: Option<String>, enum_query_string_array: Option<&Vec<String>>, enum_query_string: Option<String>, enum_query_integer: Option<i32>, enum_query_double: Option<f64>, context: &Context) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError> + Send> {
fn test_enum_parameters(&self, enum_form_string_array: Option<&Vec<String>>, enum_form_string: Option<String>, enum_header_string_array: Option<&Vec<String>>, enum_header_string: Option<String>, enum_query_string_array: Option<&Vec<String>>, enum_query_string: Option<String>, enum_query_integer: Option<i32>, enum_query_double: Option<f64>, context: &Context) -> Box<Future<Item=TestEnumParametersResponse, Error=ApiError>> {
let context = context.clone();
println!("test_enum_parameters({:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", enum_form_string_array, enum_form_string, enum_header_string_array, enum_header_string, enum_query_string_array, enum_query_string, enum_query_integer, enum_query_double, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// test inline additionalProperties
fn test_inline_additional_properties(&self, param: object, context: &Context) -> Box<Future<Item=TestInlineAdditionalPropertiesResponse, Error=ApiError> + Send> {
fn test_inline_additional_properties(&self, param: object, context: &Context) -> Box<Future<Item=TestInlineAdditionalPropertiesResponse, Error=ApiError>> {
let context = context.clone();
println!("test_inline_additional_properties({:?}) - X-Span-ID: {:?}", param, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// test json serialization of form data
fn test_json_form_data(&self, param: String, param2: String, context: &Context) -> Box<Future<Item=TestJsonFormDataResponse, Error=ApiError> + Send> {
fn test_json_form_data(&self, param: String, param2: String, context: &Context) -> Box<Future<Item=TestJsonFormDataResponse, Error=ApiError>> {
let context = context.clone();
println!("test_json_form_data(\"{}\", \"{}\") - X-Span-ID: {:?}", param, param2, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// To test class name in snake case
fn test_classname(&self, body: models::Client, context: &Context) -> Box<Future<Item=TestClassnameResponse, Error=ApiError> + Send> {
fn test_classname(&self, body: models::Client, context: &Context) -> Box<Future<Item=TestClassnameResponse, Error=ApiError>> {
let context = context.clone();
println!("test_classname({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Add a new pet to the store
fn add_pet(&self, body: models::Pet, context: &Context) -> Box<Future<Item=AddPetResponse, Error=ApiError> + Send> {
fn add_pet(&self, body: models::Pet, context: &Context) -> Box<Future<Item=AddPetResponse, Error=ApiError>> {
let context = context.clone();
println!("add_pet({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Deletes a pet
fn delete_pet(&self, pet_id: i64, api_key: Option<String>, context: &Context) -> Box<Future<Item=DeletePetResponse, Error=ApiError> + Send> {
fn delete_pet(&self, pet_id: i64, api_key: Option<String>, context: &Context) -> Box<Future<Item=DeletePetResponse, Error=ApiError>> {
let context = context.clone();
println!("delete_pet({}, {:?}) - X-Span-ID: {:?}", pet_id, api_key, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Finds Pets by status
fn find_pets_by_status(&self, status: &Vec<String>, context: &Context) -> Box<Future<Item=FindPetsByStatusResponse, Error=ApiError> + Send> {
fn find_pets_by_status(&self, status: &Vec<String>, context: &Context) -> Box<Future<Item=FindPetsByStatusResponse, Error=ApiError>> {
let context = context.clone();
println!("find_pets_by_status({:?}) - X-Span-ID: {:?}", status, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Finds Pets by tags
fn find_pets_by_tags(&self, tags: &Vec<String>, context: &Context) -> Box<Future<Item=FindPetsByTagsResponse, Error=ApiError> + Send> {
fn find_pets_by_tags(&self, tags: &Vec<String>, context: &Context) -> Box<Future<Item=FindPetsByTagsResponse, Error=ApiError>> {
let context = context.clone();
println!("find_pets_by_tags({:?}) - X-Span-ID: {:?}", tags, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Find pet by ID
fn get_pet_by_id(&self, pet_id: i64, context: &Context) -> Box<Future<Item=GetPetByIdResponse, Error=ApiError> + Send> {
fn get_pet_by_id(&self, pet_id: i64, context: &Context) -> Box<Future<Item=GetPetByIdResponse, Error=ApiError>> {
let context = context.clone();
println!("get_pet_by_id({}) - X-Span-ID: {:?}", pet_id, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Update an existing pet
fn update_pet(&self, body: models::Pet, context: &Context) -> Box<Future<Item=UpdatePetResponse, Error=ApiError> + Send> {
fn update_pet(&self, body: models::Pet, context: &Context) -> Box<Future<Item=UpdatePetResponse, Error=ApiError>> {
let context = context.clone();
println!("update_pet({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Updates a pet in the store with form data
fn update_pet_with_form(&self, pet_id: i64, name: Option<String>, status: Option<String>, context: &Context) -> Box<Future<Item=UpdatePetWithFormResponse, Error=ApiError> + Send> {
fn update_pet_with_form(&self, pet_id: i64, name: Option<String>, status: Option<String>, context: &Context) -> Box<Future<Item=UpdatePetWithFormResponse, Error=ApiError>> {
let context = context.clone();
println!("update_pet_with_form({}, {:?}, {:?}) - X-Span-ID: {:?}", pet_id, name, status, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// uploads an image
fn upload_file(&self, pet_id: i64, additional_metadata: Option<String>, file: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>, context: &Context) -> Box<Future<Item=UploadFileResponse, Error=ApiError> + Send> {
fn upload_file(&self, pet_id: i64, additional_metadata: Option<String>, file: Box<Future<Item=Option<Box<Stream<Item=Vec<u8>, Error=Error> + Send>>, Error=Error> + Send>, context: &Context) -> Box<Future<Item=UploadFileResponse, Error=ApiError>> {
let context = context.clone();
println!("upload_file({}, {:?}, ) - X-Span-ID: {:?}", pet_id, additional_metadata, context.x_span_id.unwrap_or(String::from("<none>")).clone());
let _ = file; //Suppresses unused param warning
@@ -184,84 +193,84 @@ impl Api for Server {
}
/// Delete purchase order by ID
fn delete_order(&self, order_id: String, context: &Context) -> Box<Future<Item=DeleteOrderResponse, Error=ApiError> + Send> {
fn delete_order(&self, order_id: String, context: &Context) -> Box<Future<Item=DeleteOrderResponse, Error=ApiError>> {
let context = context.clone();
println!("delete_order(\"{}\") - X-Span-ID: {:?}", order_id, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Returns pet inventories by status
fn get_inventory(&self, context: &Context) -> Box<Future<Item=GetInventoryResponse, Error=ApiError> + Send> {
fn get_inventory(&self, context: &Context) -> Box<Future<Item=GetInventoryResponse, Error=ApiError>> {
let context = context.clone();
println!("get_inventory() - X-Span-ID: {:?}", context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Find purchase order by ID
fn get_order_by_id(&self, order_id: i64, context: &Context) -> Box<Future<Item=GetOrderByIdResponse, Error=ApiError> + Send> {
fn get_order_by_id(&self, order_id: i64, context: &Context) -> Box<Future<Item=GetOrderByIdResponse, Error=ApiError>> {
let context = context.clone();
println!("get_order_by_id({}) - X-Span-ID: {:?}", order_id, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Place an order for a pet
fn place_order(&self, body: models::Order, context: &Context) -> Box<Future<Item=PlaceOrderResponse, Error=ApiError> + Send> {
fn place_order(&self, body: models::Order, context: &Context) -> Box<Future<Item=PlaceOrderResponse, Error=ApiError>> {
let context = context.clone();
println!("place_order({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Create user
fn create_user(&self, body: models::User, context: &Context) -> Box<Future<Item=CreateUserResponse, Error=ApiError> + Send> {
fn create_user(&self, body: models::User, context: &Context) -> Box<Future<Item=CreateUserResponse, Error=ApiError>> {
let context = context.clone();
println!("create_user({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Creates list of users with given input array
fn create_users_with_array_input(&self, body: &Vec<models::User>, context: &Context) -> Box<Future<Item=CreateUsersWithArrayInputResponse, Error=ApiError> + Send> {
fn create_users_with_array_input(&self, body: &Vec<models::User>, context: &Context) -> Box<Future<Item=CreateUsersWithArrayInputResponse, Error=ApiError>> {
let context = context.clone();
println!("create_users_with_array_input({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Creates list of users with given input array
fn create_users_with_list_input(&self, body: &Vec<models::User>, context: &Context) -> Box<Future<Item=CreateUsersWithListInputResponse, Error=ApiError> + Send> {
fn create_users_with_list_input(&self, body: &Vec<models::User>, context: &Context) -> Box<Future<Item=CreateUsersWithListInputResponse, Error=ApiError>> {
let context = context.clone();
println!("create_users_with_list_input({:?}) - X-Span-ID: {:?}", body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Delete user
fn delete_user(&self, username: String, context: &Context) -> Box<Future<Item=DeleteUserResponse, Error=ApiError> + Send> {
fn delete_user(&self, username: String, context: &Context) -> Box<Future<Item=DeleteUserResponse, Error=ApiError>> {
let context = context.clone();
println!("delete_user(\"{}\") - X-Span-ID: {:?}", username, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Get user by user name
fn get_user_by_name(&self, username: String, context: &Context) -> Box<Future<Item=GetUserByNameResponse, Error=ApiError> + Send> {
fn get_user_by_name(&self, username: String, context: &Context) -> Box<Future<Item=GetUserByNameResponse, Error=ApiError>> {
let context = context.clone();
println!("get_user_by_name(\"{}\") - X-Span-ID: {:?}", username, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Logs user into the system
fn login_user(&self, username: String, password: String, context: &Context) -> Box<Future<Item=LoginUserResponse, Error=ApiError> + Send> {
fn login_user(&self, username: String, password: String, context: &Context) -> Box<Future<Item=LoginUserResponse, Error=ApiError>> {
let context = context.clone();
println!("login_user(\"{}\", \"{}\") - X-Span-ID: {:?}", username, password, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Logs out current logged in user session
fn logout_user(&self, context: &Context) -> Box<Future<Item=LogoutUserResponse, Error=ApiError> + Send> {
fn logout_user(&self, context: &Context) -> Box<Future<Item=LogoutUserResponse, Error=ApiError>> {
let context = context.clone();
println!("logout_user() - X-Span-ID: {:?}", context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))
}
/// Updated user
fn update_user(&self, username: String, body: models::User, context: &Context) -> Box<Future<Item=UpdateUserResponse, Error=ApiError> + Send> {
fn update_user(&self, username: String, body: models::User, context: &Context) -> Box<Future<Item=UpdateUserResponse, Error=ApiError>> {
let context = context.clone();
println!("update_user(\"{}\", {:?}) - X-Span-ID: {:?}", username, body, context.x_span_id.unwrap_or(String::from("<none>")).clone());
Box::new(futures::failed("Generic failure".into()))