[Rust Server] Fix up merge conflicts

This commit is contained in:
Richard Whitehouse 2020-04-20 18:29:05 +01:00
parent c1cea7f2fb
commit 3ad1646f2e
6 changed files with 41 additions and 930 deletions

View File

@ -556,11 +556,8 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
private boolean isMimetypeXml(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith(xmlMimeType) ||
<<<<<<< HEAD
mimetype.toLowerCase(Locale.ROOT).startsWith(problemXmlMimeType);
=======
mimetype.toLowerCase(Locale.ROOT).startsWith(problemXmlMimeType) ||
mimetype.toLowerCase(Locale.ROOT).startsWith(textXmlMimeType);
>>>>>>> origin/master
}
private boolean isMimetypeJson(String mimetype) {
@ -611,8 +608,6 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
Map<String, Schema> definitions = ModelUtils.getSchemas(this.openAPI);
CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers);
<<<<<<< HEAD
=======
// TODO: 5.0: Remove the camelCased vendorExtension below and ensure templates use the newer property naming.
once(LOGGER).warn("4.3.0 has deprecated the use of vendor extensions which don't follow lower-kebab casing standards with x- prefix.");
@ -626,7 +621,6 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
}
op.vendorExtensions.put("x-path-format-string", pathFormatString);
>>>>>>> origin/master
// The Rust code will need to contain a series of regular expressions.
// For performance, we'll construct these at start-of-day and re-use
// them. That means we need labels for them.
@ -738,22 +732,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
pathSetEntry.put("pathRegEx", regex + "$");
pathSetMap.put(pathId, pathSetEntry);
}
<<<<<<< HEAD
op.vendorExtensions.put("operation_id", underscore(op.operationId));
op.vendorExtensions.put("uppercase_operation_id", underscore(op.operationId).toUpperCase(Locale.ROOT));
op.vendorExtensions.put("path", op.path.replace("{", ":").replace("}", ""));
op.vendorExtensions.put("x-path-format-string", formatPath);
op.vendorExtensions.put("formatPath", formatPath);
op.vendorExtensions.put("PATH_ID", pathId);
op.vendorExtensions.put("hasPathParams", hasPathParams);
op.vendorExtensions.put("HttpMethod", op.httpMethod.toUpperCase(Locale.ROOT));
if (!op.vendorExtensions.containsKey("x-mustUseResponse")) {
// If there's more than one response, than by default the user must explicitly handle them
op.vendorExtensions.put("x-mustUseResponse", op.responses.size() > 1);
}
=======
String underscoredOperationId = underscore(op.operationId);
op.vendorExtensions.put("operation_id", underscoredOperationId); // TODO: 5.0 Remove
op.vendorExtensions.put("x-operation-id", underscoredOperationId);
@ -766,11 +745,18 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
op.vendorExtensions.put("x-path-id", pathId);
op.vendorExtensions.put("hasPathParams", !op.pathParams.isEmpty()); // TODO: 5.0 Remove
op.vendorExtensions.put("x-has-path-params", !op.pathParams.isEmpty());
op.vendorExtensions.put("hasPathParams", hasPathParams); // TODO: 5.0 Remove
op.vendorExtensions.put("x-path-format-string", formatPath);
String vendorExtensionHttpMethod = Character.toUpperCase(op.httpMethod.charAt(0)) + op.httpMethod.substring(1).toLowerCase(Locale.ROOT);
String vendorExtensionHttpMethod = op.httpMethod.toUpperCase(Locale.ROOT);
op.vendorExtensions.put("HttpMethod", vendorExtensionHttpMethod); // TODO: 5.0 Remove
op.vendorExtensions.put("x-http-method", vendorExtensionHttpMethod);
>>>>>>> origin/master
// TODO: 5.0 Fix formatting
if (!op.vendorExtensions.containsKey("x-mustUseResponse")) {
// If there's more than one response, than by default the user must explicitly handle them
op.vendorExtensions.put("x-mustUseResponse", op.responses.size() > 1);
}
for (CodegenParameter param : op.allParams) {
processParam(param, op);
@ -998,11 +984,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");
// TODO: 5.0: Remove the camelCased vendorExtension below and ensure templates use the newer property naming.
once(LOGGER).warn("4.3.0 has deprecated the use of vendor extensions which don't follow lower-kebab casing standards with x- prefix.");
for (CodegenOperation op : operationList) {
<<<<<<< HEAD
postProcessOperationWithModels(op, allModels);
}
@ -1013,6 +995,9 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
boolean consumesPlainText = false;
boolean consumesXml = false;
// TODO: 5.0: Remove the camelCased vendorExtension below and ensure templates use the newer property naming.
once(LOGGER).warn("4.3.0 has deprecated the use of vendor extensions which don't follow lower-kebab casing standards with x- prefix.");
if (op.consumes != null) {
for (Map<String, String> consume : op.consumes) {
if (consume.get("mediaType") != null) {
@ -1026,51 +1011,19 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
} else if (isMimetypeWwwFormUrlEncoded(mediaType)) {
additionalProperties.put("usesUrlEncodedForm", true);
} else if (isMimetypeMultipartFormData(mediaType)) {
op.vendorExtensions.put("consumesMultipart", true);
op.vendorExtensions.put("consumesMultipart", true); // TODO Remove: 5.0 Remove
op.vendorExtensions.put("x-consumes-multipart", true);
additionalProperties.put("apiUsesMultipartFormData", true);
additionalProperties.put("apiUsesMultipart", true);
} else if (isMimetypeMultipartRelated(mediaType)) {
op.vendorExtensions.put("consumesMultipartRelated", true);
additionalProperties.put("apiUsesMultipartRelated", true);
additionalProperties.put("apiUsesMultipart", true);
=======
boolean consumesPlainText = false;
boolean consumesXml = false;
if (op.consumes != null) {
for (Map<String, String> consume : op.consumes) {
if (consume.get("mediaType") != null) {
String mediaType = consume.get("mediaType");
if (isMimetypeXml(mediaType)) {
additionalProperties.put("usesXml", true);
consumesXml = true;
} else if (isMimetypePlain(mediaType)) {
consumesPlainText = true;
} else if (isMimetypeWwwFormUrlEncoded(mediaType)) {
additionalProperties.put("usesUrlEncodedForm", true);
} else if (isMimetypeMultipartFormData(mediaType)) {
op.vendorExtensions.put("consumesMultipart", true); // TODO: 5.0 Remove
op.vendorExtensions.put("x-consumes-multipart", true);
additionalProperties.put("apiUsesMultipart", true);
}
>>>>>>> origin/master
}
}
}
}
<<<<<<< HEAD
if (op.bodyParam != null) {
// Default to consuming json
op.bodyParam.vendorExtensions.put("uppercase_operation_id", underscore(op.operationId).toUpperCase(Locale.ROOT));
if (consumesXml) {
op.bodyParam.vendorExtensions.put("consumesXml", true);
} else if (consumesPlainText) {
op.bodyParam.vendorExtensions.put("consumesPlainText", true);
} else {
op.bodyParam.vendorExtensions.put("consumesJson", true);
=======
String underscoredOperationId = underscore(op.operationId).toUpperCase(Locale.ROOT);
if (op.bodyParam != null) {
// Default to consuming json
@ -1086,24 +1039,11 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
op.bodyParam.vendorExtensions.put("consumesJson", true); // TODO: 5.0 Remove
op.bodyParam.vendorExtensions.put("x-consumes-json", true);
}
>>>>>>> origin/master
}
}
for (CodegenParameter param : op.bodyParams) {
processParam(param, op);
<<<<<<< HEAD
param.vendorExtensions.put("uppercase_operation_id", underscore(op.operationId).toUpperCase(Locale.ROOT));
// Default to producing json if nothing else is specified
if (consumesXml) {
param.vendorExtensions.put("consumesXml", true);
} else if (consumesPlainText) {
param.vendorExtensions.put("consumesPlainText", true);
} else {
param.vendorExtensions.put("consumesJson", true);
=======
param.vendorExtensions.put("uppercase_operation_id", underscoredOperationId); // TODO: 5.0 Remove
param.vendorExtensions.put("x-uppercase-operation-id", underscoredOperationId);
@ -1118,8 +1058,6 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
param.vendorExtensions.put("consumesJson", true); // TODO: 5.0 Remove
param.vendorExtensions.put("x-consumes-json", true);
}
>>>>>>> origin/master
}
}
for (CodegenParameter param : op.formParams) {
@ -1138,37 +1076,24 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
header.nameInLowerCase = header.baseName.toLowerCase(Locale.ROOT);
}
<<<<<<< HEAD
if (op.authMethods != null) {
boolean headerAuthMethods = false;
=======
for (CodegenSecurity s : op.authMethods) {
if (s.isApiKey && s.isKeyInHeader) {
s.vendorExtensions.put("x-apiKeyName", toModelName(s.keyParamName)); // TODO: 5.0 Remove
s.vendorExtensions.put("x-api-key-name", toModelName(s.keyParamName));
headerAuthMethods = true;
}
>>>>>>> origin/master
for (CodegenSecurity s : op.authMethods) {
if (s.isApiKey && s.isKeyInHeader) {
s.vendorExtensions.put("x-apiKeyName", toModelName(s.keyParamName));
headerAuthMethods = true;
}
<<<<<<< HEAD
if (s.isBasicBasic || s.isBasicBearer || s.isOAuth) {
headerAuthMethods = true;
=======
}
}
if (headerAuthMethods) {
op.vendorExtensions.put("hasHeaderAuthMethods", "true"); // TODO: 5.0 Remove
op.vendorExtensions.put("x-has-header-auth-methods", "true");
>>>>>>> origin/master
}
}
if (headerAuthMethods) {
op.vendorExtensions.put("hasHeaderAuthMethods", "true");
}
}
@ -1678,17 +1603,12 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
additionalProperties.put("apiUsesUuid", true);
}
<<<<<<< HEAD
if (Boolean.TRUE.equals(param.isFreeFormObject)) {
param.vendorExtensions.put("formatString", "{:?}");
example = null;
} else if (param.isString) {
param.vendorExtensions.put("formatString", "\\\"{}\\\"");
=======
if (param.isString) {
param.vendorExtensions.put("formatString", "\\\"{}\\\""); // TODO: 5.0 Remove
param.vendorExtensions.put("x-format-string", "\\\"{}\\\""); // TODO: 5.0 Remove
>>>>>>> origin/master
example = "\"" + ((param.example != null) ? param.example : "") + "\".to_string()";
} else if (param.isPrimitiveType) {
if ((param.isByteArray) || (param.isBinary)) {

View File

@ -177,317 +177,7 @@ impl<F> Client<F>
}
}
<<<<<<< HEAD
/// Error type failing to create a Client
=======
impl<F, C> Api<C> for Client<F> where
F: Future<Item=hyper::Response, Error=hyper::Error> + 'static,
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<AuthData>>{{/hasAuthMethods}}{
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(&self{{#allParams}}, param_{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError>> {
let mut uri = format!(
"{}{{{basePathWithoutHost}}}{{{vendorExtensions.x-path-format-string}}}",
self.base_path{{#pathParams}}, {{{paramName}}}=utf8_percent_encode(&param_{{{paramName}}}.to_string(), ID_ENCODE_SET){{/pathParams}}
);
let mut query_string = self::url::form_urlencoded::Serializer::new("".to_owned());
{{#queryParams}}{{#required}} query_string.append_pair("{{{baseName}}}", &param_{{{paramName}}}{{#isListContainer}}.join(","){{/isListContainer}}{{^isListContainer}}.to_string(){{/isListContainer}});{{/required}}
{{^required}} if let Some({{{paramName}}}) = param_{{{paramName}}} {
query_string.append_pair("{{{baseName}}}", &{{{paramName}}}{{#isListContainer}}.join(","){{/isListContainer}}{{^isListContainer}}.to_string(){{/isListContainer}});
}{{/required}}{{/queryParams}}
{{#authMethods}}{{#isApiKey}}{{#isKeyInQuery}} if let Some(auth_data) = (context as &dyn Has<Option<AuthData>>).get().as_ref() {
if let AuthData::ApiKey(ref api_key) = *auth_data {
query_string.append_pair("{{keyParamName}}", api_key);
}
}{{/isKeyInQuery}}{{/isApiKey}}{{/authMethods}}
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(futures::done(Err(ApiError(format!("Unable to build URI: {}", err))))),
};
let mut request = hyper::Request::new(hyper::Method::{{#vendorExtensions}}{{{HttpMethod}}}{{/vendorExtensions}}, uri);
{{#vendorExtensions}}
{{#consumesMultipart}}
let mut multipart = Multipart::new();
{{#vendorExtensions}}
{{#formParams}}
{{#-first}}
// For each parameter, encode as appropriate and add to the multipart body as a stream.
{{/-first}}
{{^isByteArray}}
{{#jsonSchema}}
let {{{paramName}}}_str = match serde_json::to_string(&param_{{{paramName}}}) {
Ok(str) => str,
Err(e) => return Box::new(futures::done(Err(ApiError(format!("Unable to parse {{{paramName}}} to string: {}", e))))),
};
let {{{paramName}}}_vec = {{{paramName}}}_str.as_bytes().to_vec();
let {{{paramName}}}_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse");
let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec);
multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, None as Option<&str>, Some({{{paramName}}}_mime));
{{/jsonSchema}}
{{/isByteArray}}
{{#isByteArray}}
let {{{paramName}}}_vec = param_{{{paramName}}}.to_vec();
let {{{paramName}}}_mime = match mime::Mime::from_str("application/octet-stream") {
Ok(mime) => mime,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to get mime type: {:?}", err))))),
};
let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec);
let filename = None as Option<&str> ;
multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, filename, Some({{{paramName}}}_mime));
{{/isByteArray}}
{{#-last}}
{{/-last}}
{{/formParams}}
{{/vendorExtensions}}
let mut fields = match multipart.prepare() {
Ok(fields) => fields,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build request: {}", err))))),
};
let mut body_string = String::new();
fields.to_body().read_to_string(&mut body_string).unwrap();
let boundary = fields.boundary();
let multipart_header = match Mime::from_str(&format!("multipart/form-data;boundary={}", boundary)) {
Ok(multipart_header) => multipart_header,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build multipart header: {:?}", err))))),
};
request.set_body(body_string.into_bytes());
request.headers_mut().set(ContentType(multipart_header));
{{/consumesMultipart}}
{{/vendorExtensions}}
{{#vendorExtensions}}
{{^consumesMultipart}}
{{#vendorExtensions}}
{{#formParams}}
{{#-first}}
let params = &[
{{/-first}}
("{{{baseName}}}", {{#vendorExtensions}}{{#required}}Some({{#isString}}param_{{{paramName}}}{{/isString}}{{^isString}}format!("{:?}", param_{{{paramName}}}){{/isString}}){{/required}}{{^required}}{{#isString}}param_{{{paramName}}}{{/isString}}{{^isString}}param_{{{paramName}}}.map(|param| format!("{:?}", param)){{/isString}}{{/required}}),{{/vendorExtensions}}
{{#-last}}
];
let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize");
request.headers_mut().set(ContentType(mimetypes::requests::{{#vendorExtensions}}{{{uppercase_operation_id}}}{{/vendorExtensions}}.clone()));
request.set_body(body.into_bytes());
{{/-last}}
{{/formParams}}
{{/vendorExtensions}}
{{#bodyParam}}
{{#-first}}
// Body parameter
{{/-first}}
{{#vendorExtensions}}
{{#consumesPlainText}}
{{#isByteArray}}
let body = param_{{{paramName}}}.0;
{{/isByteArray}}
{{^isByteArray}}
let body = param_{{{paramName}}};
{{/isByteArray}}
{{/consumesPlainText}}
{{#required}}
{{#consumesXml}}
let body = param_{{{paramName}}}.to_xml();
{{/consumesXml}}
{{#consumesJson}}
let body = serde_json::to_string(&param_{{{paramName}}}).expect("impossible to fail to serialize");
{{/consumesJson}}
{{/required}}
{{^required}}
let body = param_{{{paramName}}}.map(|ref body| {
{{#consumesXml}}
body.to_xml()
{{/consumesXml}}
{{#consumesJson}}
serde_json::to_string(body).expect("impossible to fail to serialize")
{{/consumesJson}}
});
{{/required}}
{{/vendorExtensions}}
{{^required}}
if let Some(body) = body {
{{/required}}
request.set_body(body);
{{^required}}
}
{{/required}}
request.headers_mut().set(ContentType(mimetypes::requests::{{#vendorExtensions}}{{{uppercase_operation_id}}}{{/vendorExtensions}}.clone()));
{{/bodyParam}}
{{/consumesMultipart}}
{{/vendorExtensions}}
request.headers_mut().set(XSpanId((context as &dyn Has<XSpanIdString>).get().0.clone()));
{{#vendorExtensions.x-has-header-auth-methods}}
(context as &dyn Has<Option<AuthData>>).get().as_ref().map(|auth_data| {
// Currently only authentication with Basic, API Key, and Bearer are supported
match auth_data {
{{#authMethods}}
{{#isApiKey}}
{{#isKeyInHeader}}
&AuthData::ApiKey(ref api_key) => {
header! { ({{#vendorExtensions}}{{x-apiKeyName}}{{/vendorExtensions}}, "{{keyParamName}}") => [String] }
request.headers_mut().set(
{{#vendorExtensions}}{{x-apiKeyName}}{{/vendorExtensions}}(api_key.to_string())
)
},
{{/isKeyInHeader}}
{{/isApiKey}}
{{#isBasicBasic}}
&AuthData::Basic(ref basic_header) => {
request.headers_mut().set(hyper::header::Authorization(
basic_header.clone(),
))
},
{{/isBasicBasic}}
{{#isBasicBearer}}
&AuthData::Bearer(ref bearer_header) => {
request.headers_mut().set(hyper::header::Authorization(
bearer_header.clone(),
))
},
{{/isBasicBearer}}
{{#isOAuth}}
{{^isBasicBearer}}
&AuthData::Bearer(ref bearer_header) => {
request.headers_mut().set(hyper::header::Authorization(
bearer_header.clone(),
))
},
{{/isBasicBearer}}
{{/isOAuth}}
{{/authMethods}}
_ => {}
}
});
{{/vendorExtensions.x-has-header-auth-methods}}
{{#headerParams}}
{{#-first}}
// Header parameters
{{/-first}}{{^isMapContainer}} header! { (Request{{vendorExtensions.x-type-name}}, "{{{baseName}}}") => {{#isListContainer}}({{{baseType}}})*{{/isListContainer}}{{^isListContainer}}[{{{dataType}}}]{{/isListContainer}} }
{{#required}} request.headers_mut().set(Request{{vendorExtensions.x-type-name}}(param_{{{paramName}}}{{#isListContainer}}.clone(){{/isListContainer}}));
{{/required}}{{^required}} param_{{{paramName}}}.map(|header| request.headers_mut().set(Request{{vendorExtensions.x-type-name}}(header{{#isListContainer}}.clone(){{/isListContainer}})));
{{/required}}{{/isMapContainer}}{{#isMapContainer}} let param_{{{paramName}}}: Option<{{{dataType}}}> = None;
{{/isMapContainer}}
{{/headerParams}}
Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
match response.status().as_u16() {
{{#responses}}
{{{code}}} => {
{{#headers}} header! { (Response{{{nameInCamelCase}}}, "{{{baseName}}}") => [{{{datatype}}}] }
let response_{{{name}}} = match response.headers().safe_get::<Response{{{nameInCamelCase}}}>() {
Some(response_{{{name}}}) => response_{{{name}}}.0.clone(),
None => return Box::new(future::err(ApiError(String::from("Required response header {{{baseName}}} for response {{{code}}} was not found.")))) as Box<dyn Future<Item=_, Error=_>>,
};
{{/headers}}
let body = response.body();
Box::new(
{{#dataType}}
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
.and_then(|body|
{{#vendorExtensions}}
{{#producesBytes}}
Ok(swagger::ByteArray(body.to_vec()))
{{/producesBytes}}
{{^producesBytes}}
str::from_utf8(&body)
.map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))
.and_then(|body|
{{#producesXml}}
// ToDo: this will move to swagger-rs and become a standard From conversion trait
// once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
serde_xml_rs::from_str::<{{{dataType}}}>(body)
.map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))
{{/producesXml}}
{{#producesJson}}
serde_json::from_str::<{{{dataType}}}>(body)
.map_err(|e| e.into())
{{/producesJson}}
{{#producesPlainText}}
Ok(body.to_string())
{{/producesPlainText}}
)
{{/producesBytes}}
{{/vendorExtensions}}
)
.map(move |body| {
{{{operationId}}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}{{^headers}}(body){{/headers}}{{#headers}}{{#-first}}{ body: body, {{/-first}}{{{name}}}: response_{{{name}}}{{^-last}}, {{/-last}}{{#-last}} }{{/-last}}{{/headers}}
})
{{/dataType}}{{^dataType}}
future::ok(
{{{operationId}}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}
{{#headers}}
{{#-first}}
{
{{/-first}}
{{{name}}}: response_{{{name}}},
{{#-last}}
}
{{/-last}}
{{/headers}}
)
{{/dataType}}
) as Box<dyn Future<Item=_, Error=_>>
},
{{/responses}}
code => {
let headers = response.headers().clone();
Box::new(response.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!("<Body was not UTF8: {:?}>", e)),
},
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
})))
)
) as Box<dyn Future<Item=_, Error=_>>
}
}
}))
}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
}
>>>>>>> origin/master
#[derive(Debug)]
pub enum ClientInitError {
/// Invalid URL Scheme

View File

@ -63,17 +63,13 @@ impl std::convert::From<{{{dataType}}}> for {{{classname}}} {
}
}
<<<<<<< HEAD
{{#vendorExtensions.isString}}
{{#vendorExtensions.x-is-string}}
impl std::string::ToString for {{{classname}}} {
fn to_string(&self) -> String {
self.0.to_string()
}
}
=======
{{#vendorExtensions.x-is-string}}
>>>>>>> origin/master
impl std::str::FromStr for {{{classname}}} {
type Err = std::string::ParseError;
fn from_str(x: &str) -> std::result::Result<Self, Self::Err> {

View File

@ -22,488 +22,7 @@ pub mod callbacks;
{{#pathSet}}
_ if path.matched(paths::ID_{{PATH_ID}}) => method_not_allowed(),
{{/pathSet}}
<<<<<<< HEAD
{{>server-service-footer}}
=======
]).unwrap();
}
{{#pathSet}}
pub static ID_{{{PATH_ID}}}: usize = {{{index}}};
{{#hasPathParams}}
lazy_static! {
pub static ref REGEX_{{{PATH_ID}}}: regex::Regex = regex::Regex::new(r"^{{{basePathWithoutHost}}}{{{pathRegEx}}}").unwrap();
}
{{/hasPathParams}}
{{/pathSet}}
}
pub struct NewService<T, C> {
api_impl: Arc<T>,
marker: PhantomData<C>,
}
impl<T, C> NewService<T, C>
where
T: Api<C> + Clone + 'static,
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + 'static
{
pub fn new<U: Into<Arc<T>>>(api_impl: U) -> NewService<T, C> {
NewService{api_impl: api_impl.into(), marker: PhantomData}
}
}
impl<T, C> hyper::server::NewService for NewService<T, C>
where
T: Api<C> + Clone + 'static,
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + 'static
{
type Request = (Request, C);
type Response = Response;
type Error = Error;
type Instance = Service<T, C>;
fn new_service(&self) -> Result<Self::Instance, io::Error> {
Ok(Service::new(self.api_impl.clone()))
}
}
pub struct Service<T, C> {
api_impl: Arc<T>,
marker: PhantomData<C>,
}
impl<T, C> Service<T, C>
where
T: Api<C> + Clone + 'static,
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + 'static {
pub fn new<U: Into<Arc<T>>>(api_impl: U) -> Service<T, C> {
Service{api_impl: api_impl.into(), marker: PhantomData}
}
}
impl<T, C> hyper::server::Service for Service<T, C>
where
T: Api<C> + Clone + 'static,
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + 'static
{
type Request = (Request, C);
type Response = Response;
type Error = Error;
type Future = Box<dyn Future<Item=Response, Error=Error>>;
fn call(&self, (req, mut context): Self::Request) -> Self::Future {
let api_impl = self.api_impl.clone();
let (method, uri, _, headers, body) = req.deconstruct();
let path = paths::GLOBAL_REGEX_SET.matches(uri.path());
// This match statement is duplicated below in `parse_operation_id()`.
// Please update both places if changing how this code is autogenerated.
match &method {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
// {{{operationId}}} - {{{httpMethod}}} {{{path}}}
&hyper::Method::{{vendorExtensions.x-http-method}} if path.matched(paths::ID_{{vendorExtensions.x-path-id}}) => {
{{#hasAuthMethods}}
{
let authorization = match (&context as &dyn Has<Option<Authorization>>).get() {
&Some(ref authorization) => authorization,
&None => return Box::new(future::ok(Response::new()
.with_status(StatusCode::Forbidden)
.with_body("Unauthenticated"))),
};
{{#authMethods}}
{{#isOAuth}}
// Authorization
if let Scopes::Some(ref scopes) = authorization.scopes {
let required_scopes: BTreeSet<String> = vec![
{{#scopes}}
"{{{scope}}}".to_string(), // {{{description}}}
{{/scopes}}
].into_iter().collect();
if !required_scopes.is_subset(scopes) {
let missing_scopes = required_scopes.difference(scopes);
return Box::new(future::ok(Response::new()
.with_status(StatusCode::Forbidden)
.with_body(missing_scopes.fold(
"Insufficient authorization, missing scopes".to_string(),
|s, scope| format!("{} {}", s, scope)
))
));
}
}
{{/isOAuth}}
{{/authMethods}}
}
{{/hasAuthMethods}}
{{#vendorExtensions}}
{{#consumesMultipart}}
let boundary = match multipart_boundary(&headers) {
Some(boundary) => boundary,
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Couldn't find valid multipart body"))),
};
{{/consumesMultipart}}
{{#hasPathParams}}
// Path parameters
let path = uri.path().to_string();
let path_params =
paths::REGEX_{{{PATH_ID}}}
.captures(&path)
.unwrap_or_else(||
panic!("Path {} matched RE {{{PATH_ID}}} in set but failed match against \"{}\"", path, paths::REGEX_{{{PATH_ID}}}.as_str())
);
{{/hasPathParams}}
{{/vendorExtensions}}
{{#pathParams}}
let param_{{{paramName}}} = match percent_encoding::percent_decode(path_params["{{{paramName}}}"].as_bytes()).decode_utf8() {
Ok(param_{{{paramName}}}) => match param_{{{paramName}}}.parse::<{{{dataType}}}>() {
Ok(param_{{{paramName}}}) => param_{{{paramName}}},
Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse path parameter {{{baseName}}}: {:?}", e)))),
},
Err(_) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["{{{paramName}}}"]))))
};
{{/pathParams}}
{{#headerParams}}
{{#-first}}
// Header parameters
{{/-first}}
header! { (Request{{vendorExtensions.x-type-name}}, "{{{baseName}}}") => {{#isListContainer}}({{{baseType}}})*{{/isListContainer}}{{^isListContainer}}[{{{dataType}}}]{{/isListContainer}} }
{{#required}}
let param_{{{paramName}}} = match headers.get::<Request{{vendorExtensions.x-type-name}}>() {
Some(param_{{{paramName}}}) => param_{{{paramName}}}.0.clone(),
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing or invalid required header {{{baseName}}}"))),
};
{{/required}}
{{^required}}
let param_{{{paramName}}} = headers.safe_get::<Request{{vendorExtensions.x-type-name}}>().map(|header| header.0.clone());
{{/required}}
{{/headerParams}}
{{#queryParams}}
{{#-first}}
// Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response)
let query_params = form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect::<Vec<_>>();
{{/-first}}
let param_{{{paramName}}} = query_params.iter().filter(|e| e.0 == "{{{baseName}}}").map(|e| e.1.to_owned())
{{#isListContainer}}
.filter_map(|param_{{{paramName}}}| param_{{{paramName}}}.parse::<{{{baseType}}}>().ok())
.collect::<Vec<_>>();
{{^required}}
let param_{{{paramName}}} = if !param_{{{paramName}}}.is_empty() {
Some(param_{{{paramName}}})
} else {
None
};
{{/required}}
{{/isListContainer}}
{{^isListContainer}}
.nth(0);
{{#required}}
let param_{{{paramName}}} = match param_{{{paramName}}} {
Some(param_{{{paramName}}}) => match param_{{{paramName}}}.parse::<{{{dataType}}}>() {
Ok(param_{{{paramName}}}) => param_{{{paramName}}},
Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse query parameter {{{baseName}}} - doesn't match schema: {}", e)))),
},
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required query parameter {{{baseName}}}"))),
};
{{/required}}{{^required}}
let param_{{{paramName}}} = param_{{{paramName}}}.and_then(|param_{{{paramName}}}| param_{{{paramName}}}.parse::<{{{baseType}}}>().ok());
{{/required}}
{{/isListContainer}}
{{/queryParams}}
{{#vendorExtensions}}
{{^consumesMultipart}}
{{#bodyParams}}
{{#-first}}
// Body parameters (note that non-required body parameters will ignore garbage
// values, rather than causing a 400 response). Produce warning header and logs for
// any unused fields.
Box::new(body.concat2()
.then(move |result| -> Box<dyn Future<Item=Response, Error=Error>> {
match result {
Ok(body) => {
{{#vendorExtensions}}
{{^consumesPlainText}}
let mut unused_elements = Vec::new();
{{/consumesPlainText}}
let param_{{{paramName}}}: Option<{{{dataType}}}> = if !body.is_empty() {
{{#consumesXml}}
let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body);
{{/consumesXml}}
{{#consumesJson}}
let deserializer = &mut serde_json::Deserializer::from_slice(&*body);
{{/consumesJson}}
{{^consumesPlainText}}
match serde_ignored::deserialize(deserializer, |path| {
warn!("Ignoring unknown field in body: {}", path);
unused_elements.push(path.to_string());
}) {
Ok(param_{{{paramName}}}) => param_{{{paramName}}},
{{#required}}
Err(e) => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't parse body parameter {{{baseName}}} - doesn't match schema: {}", e)))),
{{/required}}
{{^required}}
Err(_) => None,
{{/required}}
}
{{/consumesPlainText}}
{{#consumesPlainText}}
{{#isByteArray}}
Some(swagger::ByteArray(body.to_vec()))
{{/isByteArray}}
{{#isString}}
Some(String::from_utf8(body.to_vec()).unwrap())
{{/isString}}
{{/consumesPlainText}}
{{/vendorExtensions}}
} else {
None
};
{{#required}}
let param_{{{paramName}}} = match param_{{{paramName}}} {
Some(param_{{{paramName}}}) => param_{{{paramName}}},
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body("Missing required body parameter {{{baseName}}}"))),
};
{{/required}}
{{/-first}}
{{/bodyParams}}
{{/consumesMultipart}}
{{#consumesMultipart}}
{{^bodyParams}}
{{#vendorExtensions}}
// Form Body parameters (note that non-required body parameters will ignore garbage
// values, rather than causing a 400 response). Produce warning header and logs for
// any unused fields.
Box::new(body.concat2()
.then(move |result| -> Box<dyn Future<Item=Response, Error=Error>> {
match result {
Ok(body) => {
// Read Form Parameters from body
let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary).save().temp() {
SaveResult::Full(entries) => {
entries
},
_ => {
return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Unable to process all message parts"))))
},
};
{{#formParams}}{{#-first}}{{/-first}}
{{#isByteArray}}
let file_{{{paramName}}} = entries.files.remove("{{{paramName}}}");
{{#required}}
let param_{{{paramName}}} = match file_{{{paramName}}} {
Some(file) => {
let path = &file[0].path;
let {{{paramName}}}_str = fs::read_to_string(path).unwrap();
swagger::ByteArray({{{paramName}}}_str.as_bytes().to_vec())
}
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Missing required form parameter {{{paramName}}}")))),
};
{{/required}}
{{^required}}
let param_{{{paramName}}} = match file_{{{paramName}}} {
Some(file) => {
let path = &file[0].path;
let {{{paramName}}}_str = fs::read_to_string(path).unwrap();
Some(swagger::ByteArray({{{paramName}}}_str.as_bytes().to_vec()))
}
None => None,
};
{{/required}}
{{/isByteArray}}
{{^isByteArray}}{{#jsonSchema}}
let file_{{{paramName}}} = entries.files.remove("{{{paramName}}}");
{{#required}}
let param_{{{paramName}}} = match file_{{{paramName}}} {
Some(file) => {
let path = &file[0].path;
let {{{paramName}}}_str = fs::read_to_string(path).expect("Reading saved String should never fail");
let {{{paramName}}}_model: {{{dataType}}} = match serde_json::from_str(&{{{paramName}}}_str) {
Ok(model) => model,
Err(e) => {
return Box::new(future::ok(
Response::new()
.with_status(StatusCode::BadRequest)
.with_body(format!("{{{paramName}}} data does not match API definition: {}", e))))
}
};
{{{paramName}}}_model
}
None => return Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Missing required form parameter {{{paramName}}}")))),
};
{{/required}}
{{^required}}
let param_{{{paramName}}} = match file_{{{paramName}}} {
Some(file) => {
let path = &file[0].path;
let {{{paramName}}}_str = fs::read_to_string(path).unwrap();
let {{{paramName}}}_model: {{{dataType}}} = serde_json::from_str(&{{{paramName}}}_str).expect("Impossible to fail to serialise");
Some({{{paramName}}}_model)
}
None => None,
};
{{/required}}
{{/jsonSchema}}{{/isByteArray}}
{{/formParams}}
{{/vendorExtensions}}
{{/bodyParams}}
{{/consumesMultipart}}
{{^consumesMultipart}}
{{^bodyParams}}
{{#vendorExtensions}}
Box::new({
{{
{{#formParams}}
{{#-first}}
// Form parameters
{{/-first}}
let param_{{{paramName}}} = {{^isContainer}}{{#vendorExtensions}}{{{example}}};{{/vendorExtensions}}{{/isContainer}}{{#isListContainer}}{{#required}}Vec::new();{{/required}}{{^required}}None;{{/required}}{{/isListContainer}}{{#isMapContainer}}None;{{/isMapContainer}}
{{/formParams}}
{{/vendorExtensions}}
{{/bodyParams}}
{{/consumesMultipart}}
{{/vendorExtensions}}
Box::new(api_impl.{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}param_{{{paramName}}}{{#isListContainer}}.as_ref(){{/isListContainer}}, {{/allParams}}&context)
.then(move |result| {
let mut response = Response::new();
response.headers_mut().set(XSpanId((&context as &dyn Has<XSpanIdString>).get().0.to_string()));
{{#bodyParams}}{{#vendorExtensions}}{{^consumesPlainText}}
if !unused_elements.is_empty() {
response.headers_mut().set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements)));
}
{{/consumesPlainText}}{{/vendorExtensions}}{{/bodyParams}}
match result {
Ok(rsp) => match rsp {
{{#responses}}
{{{operationId}}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}
{{#dataType}}{{^headers}}
(body)
{{/headers}}{{#headers}}
{{#-first}}
{
body,
{{/-first}}
{{{name}}}{{^-last}}, {{/-last}}
{{#-last}}
}
{{/-last}}
{{/headers}}{{/dataType}}
{{^dataType}}{{#headers}}{{#-first}}
{
{{/-first}}
{{{name}}}{{^-last}}, {{/-last}}
{{#-last}}
}
{{/-last}}
{{/headers}}{{/dataType}}
=> {
response.set_status(StatusCode::try_from({{{code}}}).unwrap());
{{#headers}}
header! { (Response{{{nameInCamelCase}}}, "{{{baseName}}}") => [{{{dataType}}}] }
response.headers_mut().set(Response{{{nameInCamelCase}}}({{{name}}}));
{{/headers}}
{{#produces}}{{#-first}}{{#dataType}}
response.headers_mut().set(ContentType(mimetypes::responses::{{#vendorExtensions}}{{{uppercase_operation_id}}}_{{x-uppercaseResponseId}}{{/vendorExtensions}}.clone()));
{{/dataType}}{{/-first}}{{/produces}}
{{#dataType}}
{{#vendorExtensions}}
{{#producesXml}}
{{^has_namespace}}
let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize");
{{/has_namespace}}
{{#has_namespace}}
let mut namespaces = BTreeMap::new();
// An empty string is used to indicate a global namespace in xmltree.
namespaces.insert("".to_string(), {{{dataType}}}::NAMESPACE.to_string());
let body = serde_xml_rs::to_string_with_namespaces(&body, namespaces).expect("impossible to fail to serialize");
{{/has_namespace}}
{{/producesXml}}
{{#producesJson}}
let body = serde_json::to_string(&body).expect("impossible to fail to serialize");
{{/producesJson}}
{{#producesBytes}}
let body = body.0;
{{/producesBytes}}
{{#producesPlainText}}
let body = body;
{{/producesPlainText}}
{{/vendorExtensions}}
response.set_body(body);
{{/dataType}}
},
{{/responses}}
},
Err(_) => {
// Application code returned an error. This should not happen, as the implementation should
// return a valid response.
response.set_status(StatusCode::InternalServerError);
response.set_body("An internal error occurred");
},
}
future::ok(response)
}
))
{{#vendorExtensions}}
{{^consumesMultipart}}
{{^bodyParams}}
}}
}) as Box<dyn Future<Item=Response, Error=Error>>
{{/bodyParams}}
{{/consumesMultipart}}
{{/vendorExtensions}}
{{#bodyParams}}
{{#-first}}
},
Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read body parameter {{{baseName}}}: {}", e)))),
}
})
) as Box<dyn Future<Item=Response, Error=Error>>
{{/-first}}
{{/bodyParams}}
{{#vendorExtensions}}
{{#consumesMultipart}}
{{^bodyParams}}
as Box<dyn Future<Item=Response, Error=Error>>
},
Err(e) => Box::new(future::ok(Response::new().with_status(StatusCode::BadRequest).with_body(format!("Couldn't read multipart body")))),
}
})
)
{{/bodyParams}}
{{/consumesMultipart}}
{{/vendorExtensions}}
},
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
_ => Box::new(future::ok(Response::new().with_status(StatusCode::NotFound))) as Box<dyn Future<Item=Response, Error=Error>>,
}
}
}
impl<T, C> Clone for Service<T, C>
{
fn clone(&self) -> Self {
Service {
api_impl: self.api_impl.clone(),
marker: self.marker.clone(),
}
}
}
{{#apiUsesMultipart}}
/// Utility function to get the multipart boundary marker (if any) from the Headers.
fn multipart_boundary(headers: &Headers) -> Option<String> {
headers.safe_get::<ContentType>().and_then(|content_type| {
let ContentType(mime) = content_type;
if mime.type_() == hyper::mime::MULTIPART && mime.subtype() == hyper::mime::FORM_DATA {
mime.get_param(hyper::mime::BOUNDARY).map(|x| x.as_str().to_string())
} else {
None
}
})
}
{{/apiUsesMultipart}}
>>>>>>> origin/master
/// Request parser for `Api`.
pub struct ApiRequestParser;
impl<T> RequestParser<T> for ApiRequestParser {
@ -515,17 +34,12 @@ impl<T> RequestParser<T> for ApiRequestParser {
{{#operations}}
{{#operation}}
// {{{operationId}}} - {{{httpMethod}}} {{{path}}}
<<<<<<< HEAD
&hyper::Method::{{{vendorExtensions.HttpMethod}}} if path.matched(paths::ID_{{{vendorExtensions.PATH_ID}}}) => Ok("{{{operationId}}}"),
&hyper::Method::{{{vendorExtensions.x-http-method}}} if path.matched(paths::ID_{{{vendorExtensions.x-path-id}}}) => Ok("{{{operationId}}}"),
{{/operation}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
_ => Err(()),
=======
&hyper::Method::{{{vendorExtensions.x-http-method}}} if path.matched(paths::ID_{{{vendorExtensions.x-path-id}}}) => Ok("{{{operationId}}}"),
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} _ => Err(()),
>>>>>>> origin/master
}
}
}

View File

@ -1,5 +1,5 @@
// {{{operationId}}} - {{{httpMethod}}} {{{path}}}
&hyper::Method::{{vendorExtensions.HttpMethod}} if path.matched(paths::ID_{{vendorExtensions.PATH_ID}}) => {
&hyper::Method::{{vendorExtensions.x-http-method}} if path.matched(paths::ID_{{vendorExtensions.x-path-id}}) => {
{{#hasAuthMethods}}
{
let authorization = match (&context as &dyn Has<Option<Authorization>>).get() {
@ -52,10 +52,10 @@
// Path parameters
let path: &str = &uri.path().to_string();
let path_params =
paths::REGEX_{{{PATH_ID}}}
paths::REGEX_{{{x-path-id}}}
.captures(&path)
.unwrap_or_else(||
panic!("Path {} matched RE {{{PATH_ID}}} in set but failed match against \"{}\"", path, paths::REGEX_{{{PATH_ID}}}.as_str())
panic!("Path {} matched RE {{{x-path-id}}} in set but failed match against \"{}\"", path, paths::REGEX_{{{x-path-id}}}.as_str())
);
{{/hasPathParams}}

View File

@ -341,15 +341,6 @@ paths:
responses:
"204":
description: Success.
/merge-patch-json:
get:
responses:
200:
description: merge-patch+json-encoded response
content:
application/merge-patch+json:
schema:
$ref: "#/components/schemas/anotherXmlObject"
/complex-query-param:
get:
parameters: