Skip to content

Commit

Permalink
[Rust][reqwest] add async support (#6464)
Browse files Browse the repository at this point in the history
* fix rust sync client

* update doc
  • Loading branch information
wing328 committed May 28, 2020
1 parent f7f4141 commit bde0d77
Show file tree
Hide file tree
Showing 51 changed files with 1,860 additions and 63 deletions.
32 changes: 32 additions & 0 deletions bin/rust-petstore-reqwest-async.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh

SCRIPT="$0"
echo "# START SCRIPT: $SCRIPT"

while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done

if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi

executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"

if [ ! -f "$executable" ]
then
mvn -B clean package
fi

# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties $@"
ags="generate -t modules/openapi-generator/src/main/resources/rust -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g rust --library reqwest -o samples/client/petstore/rust/reqwest/petstore-async --additional-properties supportAsync=true,packageName=petstore-reqwest-async $@"

java $JAVA_OPTS -jar $executable $ags
1 change: 1 addition & 0 deletions docs/generators/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ sidebar_label: rust
|library|library template (sub-template) to use.|<dl><dt>**hyper**</dt><dd>HTTP client: Hyper.</dd><dt>**reqwest**</dt><dd>HTTP client: Reqwest.</dd></dl>|hyper|
|packageName|Rust package name (convention: lowercase).| |openapi|
|packageVersion|Rust package version.| |1.0.0|
|supportAsync|If set, generate async function call instead| |false|
|useSingleRequestParameter|Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.| |false|

## IMPORT MAPPING
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@
public class RustClientCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(RustClientCodegen.class);
private boolean useSingleRequestParameter = false;
private boolean supportAsync = false;

public static final String PACKAGE_NAME = "packageName";
public static final String PACKAGE_VERSION = "packageVersion";

public static final String HYPER_LIBRARY = "hyper";
public static final String REQWEST_LIBRARY = "reqwest";
public static final String SUPPORT_ASYNC = "supportAsync";

protected String packageName = "openapi";
protected String packageVersion = "1.0.0";
Expand Down Expand Up @@ -172,6 +173,8 @@ public RustClientCodegen() {
.defaultValue(Boolean.TRUE.toString()));
cliOptions.add(new CliOption(CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, CodegenConstants.USE_SINGLE_REQUEST_PARAMETER_DESC, SchemaTypeUtil.BOOLEAN_TYPE)
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(SUPPORT_ASYNC, "If set, generate async function call instead", SchemaTypeUtil.BOOLEAN_TYPE)
.defaultValue(Boolean.FALSE.toString()));

supportedLibraries.put(HYPER_LIBRARY, "HTTP client: Hyper.");
supportedLibraries.put(REQWEST_LIBRARY, "HTTP client: Reqwest.");
Expand Down Expand Up @@ -257,6 +260,11 @@ public void processOpts() {
}
writePropertyBack(CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, getUseSingleRequestParameter());

if (additionalProperties.containsKey(SUPPORT_ASYNC)) {
this.setSupportAsync(convertPropertyToBoolean(SUPPORT_ASYNC));
}
writePropertyBack(SUPPORT_ASYNC, getSupportAsync());

additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);

Expand Down Expand Up @@ -284,13 +292,22 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("lib.mustache", "src", "lib.rs"));
supportingFiles.add(new SupportingFile("Cargo.mustache", "", "Cargo.toml"));

supportingFiles.add(new SupportingFile(getLibrary() + "/api_mod.mustache", apiFolder, "mod.rs"));
supportingFiles.add(new SupportingFile(getLibrary() + "/configuration.mustache", apiFolder, "configuration.rs"));
if (HYPER_LIBRARY.equals(getLibrary())) {
supportingFiles.add(new SupportingFile("request.rs", apiFolder, "request.rs"));
}
if (!getSupportAsync()) { // for sync only
supportingFiles.add(new SupportingFile(getLibrary() + "/client.mustache", apiFolder, "client.rs"));
}
}

supportingFiles.add(new SupportingFile(getLibrary() + "/configuration.mustache", apiFolder, "configuration.rs"));
supportingFiles.add(new SupportingFile(getLibrary() + "/client.mustache", apiFolder, "client.rs"));
supportingFiles.add(new SupportingFile(getLibrary() + "/api_mod.mustache", apiFolder, "mod.rs"));
private boolean getSupportAsync() {
return supportAsync;
}

private void setSupportAsync(boolean supportAsync) {
this.supportAsync = supportAsync;
}

private boolean getUseSingleRequestParameter() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "{{{packageName}}}"
version = "{{{packageVersion}}}"
authors = ["OpenAPI Generator team and contributors"]
edition = "2018"

[dependencies]
serde = "^1.0"
Expand All @@ -15,7 +16,15 @@ base64 = "~0.7.0"
futures = "0.1.23"
{{/hyper}}
{{#reqwest}}
{{^supportAsync}}
reqwest = "~0.9"
{{/supportAsync}}
{{#supportAsync}}
[dependencies.reqwest]
version = "^0.10"
default-features = false
features = ["json"]
{{/supportAsync}}
{{/reqwest}}

[dev-dependencies]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{{>partial_header}}
#[allow(unused_imports)]
use std::rc::Rc;
use std::borrow::Borrow;
#[allow(unused_imports)]
use std::option::Option;

use reqwest;

use super::{Error, configuration};

{{^supportAsync}}
pub struct {{{classname}}}Client {
configuration: Rc<configuration::Configuration>,
}
Expand All @@ -20,6 +21,7 @@ impl {{{classname}}}Client {
}
}

{{/supportAsync}}
{{#operations}}
{{#operation}}
{{#vendorExtensions.x-group-parameters}}
Expand All @@ -42,6 +44,7 @@ pub struct {{{classname}}}{{{operationIdCamelCase}}}Params {
{{/operation}}
{{/operations}}

{{^supportAsync}}
pub trait {{{classname}}} {
{{#operations}}
{{#operation}}
Expand All @@ -56,20 +59,23 @@ pub trait {{{classname}}} {
}

impl {{{classname}}} for {{{classname}}}Client {
{{/supportAsync}}
{{#operations}}
{{#operation}}
{{#vendorExtensions.x-group-parameters}}
fn {{{operationId}}}(&self{{#allParams}}{{#-first}}, params: {{{classname}}}{{{operationIdCamelCase}}}Params{{/-first}}{{/allParams}}) -> Result<{{^returnType}}(){{/returnType}}{{#returnType}}{{{returnType}}}{{/returnType}}, Error> {
{{#supportAsync}}pub async {{/supportAsync}}fn {{{operationId}}}({{^supportAsync}}&self{{/supportAsync}}{{#supportAsync}}configuration: &configuration::Configuration{{/supportAsync}}{{#allParams}}{{#-first}}, params: {{{classname}}}{{{operationIdCamelCase}}}Params{{/-first}}{{/allParams}}) -> Result<{{^returnType}}(){{/returnType}}{{#returnType}}{{{returnType}}}{{/returnType}}, Error> {
// unbox the parameters
{{#allParams}}
let {{paramName}} = params.{{paramName}};
{{/allParams}}

{{/vendorExtensions.x-group-parameters}}
{{^vendorExtensions.x-group-parameters}}
fn {{{operationId}}}(&self, {{#allParams}}{{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}&str{{/isString}}{{#isUuid}}&str{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}crate::models::{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) -> Result<{{^returnType}}(){{/returnType}}{{#returnType}}{{{returnType}}}{{/returnType}}, Error> {
{{#supportAsync}}pub async {{/supportAsync}}fn {{{operationId}}}({{^supportAsync}}&self{{/supportAsync}}{{#supportAsync}}configuration: &configuration::Configuration{{/supportAsync}}, {{#allParams}}{{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}&str{{/isString}}{{#isUuid}}&str{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}crate::models::{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) -> Result<{{^returnType}}(){{/returnType}}{{#returnType}}{{{returnType}}}{{/returnType}}, Error> {
{{/vendorExtensions.x-group-parameters}}
{{^supportAsync}}
let configuration: &configuration::Configuration = self.configuration.borrow();
{{/supportAsync}}
let client = &configuration.client;

let uri_str = format!("{}{{{path}}}", configuration.base_path{{#pathParams}}, {{{baseName}}}={{#isString}}crate::apis::urlencode({{/isString}}{{{paramName}}}{{^required}}.unwrap(){{/required}}{{#required}}{{#isNullable}}.unwrap(){{/isNullable}}{{/required}}{{#isListContainer}}.join(",").as_ref(){{/isListContainer}}{{#isString}}){{/isString}}{{/pathParams}});
Expand Down Expand Up @@ -162,6 +168,7 @@ impl {{{classname}}} for {{{classname}}}Client {
let mut form = reqwest::multipart::Form::new();
{{#formParams}}
{{#isFile}}
{{^supportAsync}}
{{#required}}
{{^isNullable}}
form = form.file("{{{baseName}}}", {{{paramName}}})?;
Expand All @@ -178,6 +185,10 @@ impl {{{classname}}} for {{{classname}}}Client {
form = form.file("{{{baseName}}}", param_value)?;
}
{{/required}}
{{/supportAsync}}
{{#supportAsync}}
// TODO: support file upload for '{{{baseName}}}' parameter
{{/supportAsync}}
{{/isFile}}
{{^isFile}}
{{#required}}
Expand Down Expand Up @@ -251,18 +262,23 @@ impl {{{classname}}} for {{{classname}}}Client {
{{/bodyParams}}
{{/hasBodyParam}}

// send request
let req = req_builder.build()?;

{{^returnType}}
client.execute(req)?.error_for_status()?;
client.execute(req){{#supportAsync}}.await{{/supportAsync}}?.error_for_status()?;
Ok(())
{{/returnType}}
{{#returnType}}
{{#supportAsync}}
Ok(client.execute(req).await?.error_for_status()?.json::<{{{.}}}>().await?)
{{/supportAsync}}
{{^supportAsync}}
Ok(client.execute(req)?.error_for_status()?.json()?)
{{/supportAsync}}
{{/returnType}}
}

{{/operation}}
{{/operations}}
{{^supportAsync}}
}
{{/supportAsync}}
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@ pub fn urlencode<T: AsRef<str>>(s: T) -> String {
mod {{{classFilename}}};
{{#operations}}
{{#operation}}
{{^supportAsync}}
{{#-first}}
pub use self::{{{classFilename}}}::{ {{{classname}}}, {{{classname}}}Client };
{{/-first}}
{{/supportAsync}}
{{#supportAsync}}
pub use self::{{{classFilename}}}::{ {{{operationId}}} };
{{/supportAsync}}
{{#vendorExtensions.x-group-parameters}}
{{#allParams}}
{{#-first}}
Expand All @@ -50,5 +55,7 @@ pub use self::{{{classFilename}}}::{ {{{classname}}}{{{operationIdCamelCase}}}Pa
{{/apis}}
{{/apiInfo}}

pub mod configuration;
{{^supportAsync}}
pub mod client;
{{/supportAsync}}
pub mod configuration;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "fileResponseTest-hyper"
version = "1.0.0"
authors = ["OpenAPI Generator team and contributors"]
edition = "2018"

[dependencies]
serde = "^1.0"
Expand Down
1 change: 1 addition & 0 deletions samples/client/petstore/rust/hyper/petstore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "petstore-hyper"
version = "1.0.0"
authors = ["OpenAPI Generator team and contributors"]
edition = "2018"

[dependencies]
serde = "^1.0"
Expand Down
1 change: 1 addition & 0 deletions samples/client/petstore/rust/hyper/rust-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "rust-test-hyper"
version = "1.0.0"
authors = ["OpenAPI Generator team and contributors"]
edition = "2018"

[dependencies]
serde = "^1.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "fileResponseTest-reqwest"
version = "1.0.0"
authors = ["OpenAPI Generator team and contributors"]
edition = "2018"

[dependencies]
serde = "^1.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
* Generated by: https://openapi-generator.tech
*/

#[allow(unused_imports)]
use std::rc::Rc;
use std::borrow::Borrow;
#[allow(unused_imports)]
use std::option::Option;

use reqwest;
Expand Down Expand Up @@ -46,9 +46,7 @@ impl DefaultApi for DefaultApiClient {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}

// send request
let req = req_builder.build()?;

Ok(client.execute(req)?.error_for_status()?.json()?)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ pub fn urlencode<T: AsRef<str>>(s: T) -> String {
mod default_api;
pub use self::default_api::{ DefaultApi, DefaultApiClient };

pub mod configuration;
pub mod client;
pub mod configuration;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target/
**/*.rs.bk
Cargo.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.gitignore
.travis.yml
Cargo.toml
README.md
docs/ApiResponse.md
docs/Category.md
docs/Order.md
docs/Pet.md
docs/PetApi.md
docs/StoreApi.md
docs/Tag.md
docs/User.md
docs/UserApi.md
git_push.sh
src/apis/configuration.rs
src/apis/mod.rs
src/apis/pet_api.rs
src/apis/store_api.rs
src/apis/user_api.rs
src/lib.rs
src/models/api_response.rs
src/models/category.rs
src/models/mod.rs
src/models/order.rs
src/models/pet.rs
src/models/tag.rs
src/models/user.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5.0.0-SNAPSHOT
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
language: rust
17 changes: 17 additions & 0 deletions samples/client/petstore/rust/reqwest/petstore-async/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "petstore-reqwest-async"
version = "1.0.0"
authors = ["OpenAPI Generator team and contributors"]
edition = "2018"

[dependencies]
serde = "^1.0"
serde_derive = "^1.0"
serde_json = "^1.0"
url = "1.5"
[dependencies.reqwest]
version = "^0.10"
default-features = false
features = ["json"]

[dev-dependencies]
Loading

0 comments on commit bde0d77

Please sign in to comment.