diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java index fde0ae96d8b4..d778d2e31966 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java @@ -18,9 +18,11 @@ package org.openapitools.codegen.languages; import com.google.common.base.Strings; +import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.servers.Server; import io.swagger.v3.parser.util.SchemaTypeUtil; import org.openapitools.codegen.*; import org.openapitools.codegen.meta.features.*; @@ -503,6 +505,38 @@ public String toOperationId(String operationId) { return StringUtils.underscore(sanitizedOperationId); } + @Override + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List servers) { + CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers); + + // If this endpoint has a single binary body parameter, we want + // to accept a body argument with the trait bound Into. + // This requires a type parameter in the function definition, + // in advance of actual parameter, and is thus far easier to decide + // here than in the template. + if (REQWEST_LIBRARY.equals(getLibrary()) && op.bodyParams != null && op.bodyParams.size() == 1) { + CodegenParameter cp = op.bodyParams.get(0); + + if (cp.isBinary) { + cp.baseType = cp.dataType = "B"; + op.vendorExtensions.put("x-rust-type-parameter", "B: Into"); + + // A copy of the body parameter will appear somewhere in the + // allParams list. We need to doctor that one as well. + int seen = 0; + for (CodegenParameter ap : op.allParams) { + if (ap.isBinary && ap.isBodyParam) { + ap.baseType = ap.dataType = "B"; + seen++; + } + } + assert seen == 1; + } + } + + return op; + } + @Override public Map postProcessOperationsWithModels(Map objs, List allModels) { @SuppressWarnings("unchecked") diff --git a/modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache b/modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache index 8ff7ce8d99e6..235116d65342 100644 --- a/modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache +++ b/modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache @@ -88,7 +88,65 @@ pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration: {{/vendorExtensions.x-group-parameters}} {{^vendorExtensions.x-group-parameters}} -pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration: &configuration::Configuration, {{#allParams}}{{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}{{#isArray}}Vec<{{/isArray}}&str{{#isArray}}>{{/isArray}}{{/isString}}{{#isUuid}}{{#isArray}}Vec<{{/isArray}}&str{{#isArray}}>{{/isArray}}{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}{{#isBodyParam}}crate::models::{{/isBodyParam}}{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) -> Result<{{#supportMultipleResponses}}ResponseContent<{{{operationIdCamelCase}}}Success>{{/supportMultipleResponses}}{{^supportMultipleResponses}}{{^returnType}}(){{/returnType}}{{#returnType}}{{{returnType}}}{{/returnType}}{{/supportMultipleResponses}}, Error<{{{operationIdCamelCase}}}Error>> { +pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}{{! + }}{{#vendorExtensions.x-rust-type-parameter}}{{! + }}<{{{vendorExtensions.x-rust-type-parameter}}}>{{! + }}{{/vendorExtensions.x-rust-type-parameter}}{{! + }}( + configuration: &configuration::Configuration, +{{! + }}{{#allParams}} {{{paramName}}}: {{! + ! + ! If this is an optional parameter, or a required parameter that + ! is nullable, wrap the type in an Option: + ! + }}{{^required}}Option<{{/required}}{{! + }}{{#required}}{{! + }}{{#isNullable}}Option<{{/isNullable}}{{! + }}{{/required}}{{! + + ! + ! Represent a string as a string slice (&str). + ! TODO: Array should be a slice, not a Vector; i.e., &[&str]. + ! + }}{{#isString}}{{! + }}{{#isArray}}Vec<{{/isArray}}{{! + }}&str{{! + }}{{#isArray}}>{{/isArray}}{{! + }}{{/isString}}{{! + + ! + ! Represent a UUID as a string slice (&str). + ! TODO: Array should be a slice, not a Vector; i.e., &[&str]. + ! + }}{{#isUuid}}{{! + }}{{#isArray}}Vec<{{/isArray}}{{! + }}&str{{! + }}{{#isArray}}>{{/isArray}}{{! + }}{{/isUuid}}{{! + + }}{{^isString}}{{^isUuid}}{{! + }}{{^isPrimitiveType}}{{^isContainer}}{{#isBodyParam}}{{! + ! + ! Complex body parameters need a prefix to refer to the + ! struct we defined in the models module: + ! + }}crate::models::{{! + }}{{/isBodyParam}}{{/isContainer}}{{/isPrimitiveType}}{{! + }}{{{dataType}}}{{! + }}{{/isUuid}}{{/isString}}{{! + + ! + ! Close out the Option wrapper: + ! + }}{{^required}}>{{/required}}{{! + }}{{#required}}{{! + }}{{#isNullable}}>{{/isNullable}}{{! + }}{{/required}}{{! + }}, +{{! + }}{{/allParams}}{{! +}}) -> Result<{{#supportMultipleResponses}}ResponseContent<{{{operationIdCamelCase}}}Success>{{/supportMultipleResponses}}{{^supportMultipleResponses}}{{^returnType}}(){{/returnType}}{{#returnType}}{{{returnType}}}{{/returnType}}{{/supportMultipleResponses}}, Error<{{{operationIdCamelCase}}}Error>> { {{/vendorExtensions.x-group-parameters}} let local_var_client = &configuration.client; @@ -271,12 +329,33 @@ pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration: local_var_req_builder = local_var_req_builder.form(&local_var_form_params); {{/hasFormParams}} {{/isMultipart}} - {{#hasBodyParam}} - {{#bodyParams}} - local_var_req_builder = local_var_req_builder.json(&{{{paramName}}}); - {{/bodyParams}} - {{/hasBodyParam}} - +{{! + ! + ! Body parameter: + ! + !}}{{#hasBodyParam}}{{! + }}{{#bodyParams}}{{! + ! + ! If the body parameter is binary, we pass it to the reqwest body() + ! method. This requires the body parameter argument to this function + ! to be generic, and match the Into bound, allowing + ! a stream or a byte buffer to be used: + ! + !}}{{#isBinary}}{{! + }} local_var_req_builder = local_var_req_builder.body({{{paramName}}}); +{{! + }}{{/isBinary}}{{! + ! + ! Otherwise, we assume the parameter has the Serializable trait, and + ! pass it to the reqwest json() method: + ! + }}{{^isBinary}}{{! + }} local_var_req_builder = local_var_req_builder.json(&{{{paramName}}}); +{{! + }}{{/isBinary}}{{! + }}{{/bodyParams}}{{! + }}{{/hasBodyParam}}{{! +}} let local_var_req = local_var_req_builder.build()?; let {{^supportAsync}}mut {{/supportAsync}}local_var_resp = local_var_client.execute(local_var_req){{#supportAsync}}.await{{/supportAsync}}?; diff --git a/samples/client/petstore/rust/reqwest/petstore/src/apis/pet_api.rs b/samples/client/petstore/rust/reqwest/petstore/src/apis/pet_api.rs index 47cf47f1d59b..d0dceb32af17 100644 --- a/samples/client/petstore/rust/reqwest/petstore/src/apis/pet_api.rs +++ b/samples/client/petstore/rust/reqwest/petstore/src/apis/pet_api.rs @@ -82,7 +82,10 @@ pub enum UploadFileError { } -pub fn add_pet(configuration: &configuration::Configuration, body: crate::models::Pet) -> Result<(), Error> { +pub fn add_pet( + configuration: &configuration::Configuration, + body: crate::models::Pet, +) -> Result<(), Error> { let local_var_client = &configuration.client; @@ -112,7 +115,11 @@ pub fn add_pet(configuration: &configuration::Configuration, body: crate::models } } -pub fn delete_pet(configuration: &configuration::Configuration, pet_id: i64, api_key: Option<&str>) -> Result<(), Error> { +pub fn delete_pet( + configuration: &configuration::Configuration, + pet_id: i64, + api_key: Option<&str>, +) -> Result<(), Error> { let local_var_client = &configuration.client; @@ -145,7 +152,10 @@ pub fn delete_pet(configuration: &configuration::Configuration, pet_id: i64, api } /// Multiple status values can be provided with comma separated strings -pub fn find_pets_by_status(configuration: &configuration::Configuration, status: Vec) -> Result, Error> { +pub fn find_pets_by_status( + configuration: &configuration::Configuration, + status: Vec, +) -> Result, Error> { let local_var_client = &configuration.client; @@ -176,7 +186,10 @@ pub fn find_pets_by_status(configuration: &configuration::Configuration, status: } /// Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. -pub fn find_pets_by_tags(configuration: &configuration::Configuration, tags: Vec) -> Result, Error> { +pub fn find_pets_by_tags( + configuration: &configuration::Configuration, + tags: Vec, +) -> Result, Error> { let local_var_client = &configuration.client; @@ -207,7 +220,10 @@ pub fn find_pets_by_tags(configuration: &configuration::Configuration, tags: Vec } /// Returns a single pet -pub fn get_pet_by_id(configuration: &configuration::Configuration, pet_id: i64) -> Result> { +pub fn get_pet_by_id( + configuration: &configuration::Configuration, + pet_id: i64, +) -> Result> { let local_var_client = &configuration.client; @@ -241,7 +257,10 @@ pub fn get_pet_by_id(configuration: &configuration::Configuration, pet_id: i64) } } -pub fn update_pet(configuration: &configuration::Configuration, body: crate::models::Pet) -> Result<(), Error> { +pub fn update_pet( + configuration: &configuration::Configuration, + body: crate::models::Pet, +) -> Result<(), Error> { let local_var_client = &configuration.client; @@ -271,7 +290,12 @@ pub fn update_pet(configuration: &configuration::Configuration, body: crate::mod } } -pub fn update_pet_with_form(configuration: &configuration::Configuration, pet_id: i64, name: Option<&str>, status: Option<&str>) -> Result<(), Error> { +pub fn update_pet_with_form( + configuration: &configuration::Configuration, + pet_id: i64, + name: Option<&str>, + status: Option<&str>, +) -> Result<(), Error> { let local_var_client = &configuration.client; @@ -308,7 +332,12 @@ pub fn update_pet_with_form(configuration: &configuration::Configuration, pet_id } } -pub fn upload_file(configuration: &configuration::Configuration, pet_id: i64, additional_metadata: Option<&str>, file: Option) -> Result> { +pub fn upload_file( + configuration: &configuration::Configuration, + pet_id: i64, + additional_metadata: Option<&str>, + file: Option, +) -> Result> { let local_var_client = &configuration.client; diff --git a/samples/client/petstore/rust/reqwest/petstore/src/apis/store_api.rs b/samples/client/petstore/rust/reqwest/petstore/src/apis/store_api.rs index 898599f9b2fc..8d00aef93dca 100644 --- a/samples/client/petstore/rust/reqwest/petstore/src/apis/store_api.rs +++ b/samples/client/petstore/rust/reqwest/petstore/src/apis/store_api.rs @@ -50,7 +50,10 @@ pub enum PlaceOrderError { /// For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors -pub fn delete_order(configuration: &configuration::Configuration, order_id: &str) -> Result<(), Error> { +pub fn delete_order( + configuration: &configuration::Configuration, + order_id: &str, +) -> Result<(), Error> { let local_var_client = &configuration.client; @@ -77,7 +80,9 @@ pub fn delete_order(configuration: &configuration::Configuration, order_id: &str } /// Returns a map of status codes to quantities -pub fn get_inventory(configuration: &configuration::Configuration, ) -> Result<::std::collections::HashMap, Error> { +pub fn get_inventory( + configuration: &configuration::Configuration, +) -> Result<::std::collections::HashMap, Error> { let local_var_client = &configuration.client; @@ -112,7 +117,10 @@ pub fn get_inventory(configuration: &configuration::Configuration, ) -> Result<: } /// For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions -pub fn get_order_by_id(configuration: &configuration::Configuration, order_id: i64) -> Result> { +pub fn get_order_by_id( + configuration: &configuration::Configuration, + order_id: i64, +) -> Result> { let local_var_client = &configuration.client; @@ -138,7 +146,10 @@ pub fn get_order_by_id(configuration: &configuration::Configuration, order_id: i } } -pub fn place_order(configuration: &configuration::Configuration, body: crate::models::Order) -> Result> { +pub fn place_order( + configuration: &configuration::Configuration, + body: crate::models::Order, +) -> Result> { let local_var_client = &configuration.client; diff --git a/samples/client/petstore/rust/reqwest/petstore/src/apis/user_api.rs b/samples/client/petstore/rust/reqwest/petstore/src/apis/user_api.rs index 97f0f3c4e146..073312d55c07 100644 --- a/samples/client/petstore/rust/reqwest/petstore/src/apis/user_api.rs +++ b/samples/client/petstore/rust/reqwest/petstore/src/apis/user_api.rs @@ -84,7 +84,10 @@ pub enum UpdateUserError { /// This can only be done by the logged in user. -pub fn create_user(configuration: &configuration::Configuration, body: crate::models::User) -> Result<(), Error> { +pub fn create_user( + configuration: &configuration::Configuration, + body: crate::models::User, +) -> Result<(), Error> { let local_var_client = &configuration.client; @@ -111,7 +114,10 @@ pub fn create_user(configuration: &configuration::Configuration, body: crate::mo } } -pub fn create_users_with_array_input(configuration: &configuration::Configuration, body: Vec) -> Result<(), Error> { +pub fn create_users_with_array_input( + configuration: &configuration::Configuration, + body: Vec, +) -> Result<(), Error> { let local_var_client = &configuration.client; @@ -138,7 +144,10 @@ pub fn create_users_with_array_input(configuration: &configuration::Configuratio } } -pub fn create_users_with_list_input(configuration: &configuration::Configuration, body: Vec) -> Result<(), Error> { +pub fn create_users_with_list_input( + configuration: &configuration::Configuration, + body: Vec, +) -> Result<(), Error> { let local_var_client = &configuration.client; @@ -166,7 +175,10 @@ pub fn create_users_with_list_input(configuration: &configuration::Configuration } /// This can only be done by the logged in user. -pub fn delete_user(configuration: &configuration::Configuration, username: &str) -> Result<(), Error> { +pub fn delete_user( + configuration: &configuration::Configuration, + username: &str, +) -> Result<(), Error> { let local_var_client = &configuration.client; @@ -192,7 +204,10 @@ pub fn delete_user(configuration: &configuration::Configuration, username: &str) } } -pub fn get_user_by_name(configuration: &configuration::Configuration, username: &str) -> Result> { +pub fn get_user_by_name( + configuration: &configuration::Configuration, + username: &str, +) -> Result> { let local_var_client = &configuration.client; @@ -218,7 +233,11 @@ pub fn get_user_by_name(configuration: &configuration::Configuration, username: } } -pub fn login_user(configuration: &configuration::Configuration, username: &str, password: &str) -> Result> { +pub fn login_user( + configuration: &configuration::Configuration, + username: &str, + password: &str, +) -> Result> { let local_var_client = &configuration.client; @@ -246,7 +265,9 @@ pub fn login_user(configuration: &configuration::Configuration, username: &str, } } -pub fn logout_user(configuration: &configuration::Configuration, ) -> Result<(), Error> { +pub fn logout_user( + configuration: &configuration::Configuration, +) -> Result<(), Error> { let local_var_client = &configuration.client; @@ -273,7 +294,11 @@ pub fn logout_user(configuration: &configuration::Configuration, ) -> Result<(), } /// This can only be done by the logged in user. -pub fn update_user(configuration: &configuration::Configuration, username: &str, body: crate::models::User) -> Result<(), Error> { +pub fn update_user( + configuration: &configuration::Configuration, + username: &str, + body: crate::models::User, +) -> Result<(), Error> { let local_var_client = &configuration.client;