Skip to content

Commit

Permalink
[Rust] Support for withAWSV4Signature option (#11690)
Browse files Browse the repository at this point in the history
* [rust] add support for withAWSV4Signature option in reqwest (#11193)

Signed-off-by: Jérôme Jutteau <[email protected]>

* [rust] add petstore sample for withAWSV4Signature option for reqwest (#11193)

Signed-off-by: Jérôme Jutteau <[email protected]>

* [rust] update all samples (#11193)

Signed-off-by: Jérôme Jutteau <[email protected]>
  • Loading branch information
jerome-jutteau authored Mar 1, 2022
1 parent 1b6ab63 commit 21f649e
Show file tree
Hide file tree
Showing 40 changed files with 2,654 additions and 0 deletions.
9 changes: 9 additions & 0 deletions bin/configs/rust-reqwest-petstore-awsv4signature.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
generatorName: rust
outputDir: samples/client/petstore/rust/reqwest/petstore-awsv4signature
library: reqwest
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/rust
additionalProperties:
supportAsync: false
packageName: petstore-reqwest-awsv4signature
withAWSV4Signature: true
1 change: 1 addition & 0 deletions docs/generators/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|supportAsync|If set, generate async function call instead. This option is for 'reqwest' library only| |true|
|supportMultipleResponses|If set, return type wraps an enum of all possible 2xx schemas. This option is for 'reqwest' library only| |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|
|withAWSV4Signature|whether to include AWS v4 signature support| |false|

## IMPORT MAPPING

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class RustClientCodegen extends DefaultCodegen implements CodegenConfig {
private boolean useSingleRequestParameter = false;
private boolean supportAsync = true;
private boolean supportMultipleResponses = false;
private boolean withAWSV4Signature = false;

public static final String PACKAGE_NAME = "packageName";
public static final String PACKAGE_VERSION = "packageVersion";
Expand Down Expand Up @@ -181,6 +182,8 @@ public RustClientCodegen() {
cliOptions.add(new CliOption(SUPPORT_MULTIPLE_RESPONSES, "If set, return type wraps an enum of all possible 2xx schemas. This option is for 'reqwest' library only", SchemaTypeUtil.BOOLEAN_TYPE)
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(CodegenConstants.ENUM_NAME_SUFFIX, CodegenConstants.ENUM_NAME_SUFFIX_DESC).defaultValue(this.enumSuffix));
cliOptions.add(new CliOption(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT, CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT_DESC, 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 @@ -249,6 +252,10 @@ public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
public void processOpts() {
super.processOpts();

if (additionalProperties.containsKey(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT)) {
withAWSV4Signature = Boolean.parseBoolean(additionalProperties.get(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT).toString());
}

if (additionalProperties.containsKey(CodegenConstants.ENUM_NAME_SUFFIX)) {
enumSuffix = additionalProperties.get(CodegenConstants.ENUM_NAME_SUFFIX).toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ version = "^0.11"
features = ["json", "multipart"]
{{/supportAsync}}
{{/reqwest}}
{{#withAWSV4Signature}}
aws-sigv4 = "0.3.0"
http = "0.2.5"
secrecy = "0.8.0"
{{/withAWSV4Signature}}

[dev-dependencies]
{{#hyper}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,30 @@ pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration:
{{/isApiKey}}
{{/authMethods}}
{{/hasAuthMethods}}
{{#hasAuthMethods}}
{{#withAWSV4Signature}}
if let Some(ref local_var_aws_v4_key) = local_var_configuration.aws_v4_key {
let local_var_new_headers = match local_var_aws_v4_key.sign(
&local_var_uri_str,
"{{{httpMethod}}}",
{{#hasBodyParam}}
{{#bodyParams}}
&serde_json::to_string(&{{{paramName}}}).expect("param should serialize to string"),
{{/bodyParams}}
{{/hasBodyParam}}
{{^hasBodyParam}}
&"",
{{/hasBodyParam}}
) {
Ok(new_headers) => new_headers,
Err(err) => return Err(Error::AWSV4SignatureError(err)),
};
for (local_var_name, local_var_value) in local_var_new_headers.iter() {
local_var_req_builder = local_var_req_builder.header(local_var_name.as_str(), local_var_value.as_str());
}
}
{{/withAWSV4Signature}}
{{/hasAuthMethods}}
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use std::error;
use std::fmt;
{{#withAWSV4Signature}}
use aws_sigv4;
{{/withAWSV4Signature}}

#[derive(Debug, Clone)]
pub struct ResponseContent<T> {
Expand All @@ -14,6 +17,9 @@ pub enum Error<T> {
Serde(serde_json::Error),
Io(std::io::Error),
ResponseError(ResponseContent<T>),
{{#withAWSV4Signature}}
AWSV4SignatureError(aws_sigv4::http_request::Error),
{{/withAWSV4Signature}}
}

impl <T> fmt::Display for Error<T> {
Expand All @@ -23,6 +29,9 @@ impl <T> fmt::Display for Error<T> {
Error::Serde(e) => ("serde", e.to_string()),
Error::Io(e) => ("IO", e.to_string()),
Error::ResponseError(e) => ("response", format!("status code {}", e.status)),
{{#withAWSV4Signature}}
Error::AWSV4SignatureError(e) => ("aws v4 signature", e.to_string()),
{{/withAWSV4Signature}}
};
write!(f, "error in {}: {}", module, e)
}
Expand All @@ -35,6 +44,9 @@ impl <T: fmt::Debug> error::Error for Error<T> {
Error::Serde(e) => e,
Error::Io(e) => e,
Error::ResponseError(_) => return None,
{{#withAWSV4Signature}}
Error::AWSV4SignatureError(_) => return None,
{{/withAWSV4Signature}}
})
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

use reqwest;

{{#withAWSV4Signature}}
use std::time::SystemTime;
use aws_sigv4::http_request::{sign, SigningSettings, SigningParams, SignableRequest};
use http;
use secrecy::{SecretString, ExposeSecret};
{{/withAWSV4Signature}}

#[derive(Debug, Clone)]
pub struct Configuration {
pub base_path: String,
Expand All @@ -11,6 +18,9 @@ pub struct Configuration {
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
{{#withAWSV4Signature}}
pub aws_v4_key: Option<AWSv4Key>,
{{/withAWSV4Signature}}
// TODO: take an oauth2 token source, similar to the go one
}

Expand All @@ -22,6 +32,45 @@ pub struct ApiKey {
pub key: String,
}

{{#withAWSV4Signature}}
#[derive(Debug, Clone)]
pub struct AWSv4Key {
pub access_key: String,
pub secret_key: SecretString,
pub region: String,
pub service: String,
}

impl AWSv4Key {
pub fn sign(&self, uri: &str, method: &str, body: &str) -> Result<Vec::<(String, String)>, aws_sigv4::http_request::Error> {
let request = http::Request::builder()
.uri(uri)
.method(method)
.body(body).unwrap();
let signing_settings = SigningSettings::default();
let signing_params = SigningParams::builder()
.access_key(self.access_key.as_str())
.secret_key(self.secret_key.expose_secret().as_str())
.region(self.region.as_str())
.service_name(self.service.as_str())
.time(SystemTime::now())
.settings(signing_settings)
.build()
.unwrap();
let signable_request = SignableRequest::from(&request);
let (mut signing_instructions, _signature) = sign(signable_request, &signing_params)?.into_parts();
let mut additional_headers = Vec::<(String, String)>::new();
if let Some(new_headers) = signing_instructions.take_headers() {
for (name, value) in new_headers.into_iter() {
additional_headers.push((name.expect("header should have name").to_string(),
value.to_str().expect("header value should be a string").to_string()));
}
}
return Ok(additional_headers);
}
}
{{/withAWSV4Signature}}

impl Configuration {
pub fn new() -> Configuration {
Configuration::default()
Expand All @@ -38,6 +87,7 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,
{{#withAWSV4Signature}} aws_v4_key: None,{{/withAWSV4Signature}}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use reqwest;


#[derive(Debug, Clone)]
pub struct Configuration {
pub base_path: String,
Expand All @@ -31,6 +32,7 @@ pub struct ApiKey {
pub key: String,
}


impl Configuration {
pub fn new() -> Configuration {
Configuration::default()
Expand All @@ -47,6 +49,7 @@ impl Default for Configuration {
oauth_access_token: None,
bearer_access_token: None,
api_key: None,

}
}
}
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 @@
6.0.0-SNAPSHOT
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
language: rust
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "petstore-reqwest-awsv4signature"
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 = "^2.2"
reqwest = "~0.9"
aws-sigv4 = "0.3.0"
http = "0.2.5"
secrecy = "0.8.0"

[dev-dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Rust API client for petstore-reqwest-awsv4signature

This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.


## Overview

This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://openapis.org) from a remote server, you can easily generate an API client.

- API version: 1.0.0
- Package version: 1.0.0
- Build package: `org.openapitools.codegen.languages.RustClientCodegen`

## Installation

Put the package under your project folder in a directory named `petstore-reqwest-awsv4signature` and add the following to `Cargo.toml` under `[dependencies]`:

```
petstore-reqwest-awsv4signature = { path = "./petstore-reqwest-awsv4signature" }
```

## Documentation for API Endpoints

All URIs are relative to *http://petstore.swagger.io/v2*

Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*PetApi* | [**add_pet**](docs/PetApi.md#add_pet) | **POST** /pet | Add a new pet to the store
*PetApi* | [**delete_pet**](docs/PetApi.md#delete_pet) | **DELETE** /pet/{petId} | Deletes a pet
*PetApi* | [**find_pets_by_status**](docs/PetApi.md#find_pets_by_status) | **GET** /pet/findByStatus | Finds Pets by status
*PetApi* | [**find_pets_by_tags**](docs/PetApi.md#find_pets_by_tags) | **GET** /pet/findByTags | Finds Pets by tags
*PetApi* | [**get_pet_by_id**](docs/PetApi.md#get_pet_by_id) | **GET** /pet/{petId} | Find pet by ID
*PetApi* | [**update_pet**](docs/PetApi.md#update_pet) | **PUT** /pet | Update an existing pet
*PetApi* | [**update_pet_with_form**](docs/PetApi.md#update_pet_with_form) | **POST** /pet/{petId} | Updates a pet in the store with form data
*PetApi* | [**upload_file**](docs/PetApi.md#upload_file) | **POST** /pet/{petId}/uploadImage | uploads an image
*StoreApi* | [**delete_order**](docs/StoreApi.md#delete_order) | **DELETE** /store/order/{orderId} | Delete purchase order by ID
*StoreApi* | [**get_inventory**](docs/StoreApi.md#get_inventory) | **GET** /store/inventory | Returns pet inventories by status
*StoreApi* | [**get_order_by_id**](docs/StoreApi.md#get_order_by_id) | **GET** /store/order/{orderId} | Find purchase order by ID
*StoreApi* | [**place_order**](docs/StoreApi.md#place_order) | **POST** /store/order | Place an order for a pet
*UserApi* | [**create_user**](docs/UserApi.md#create_user) | **POST** /user | Create user
*UserApi* | [**create_users_with_array_input**](docs/UserApi.md#create_users_with_array_input) | **POST** /user/createWithArray | Creates list of users with given input array
*UserApi* | [**create_users_with_list_input**](docs/UserApi.md#create_users_with_list_input) | **POST** /user/createWithList | Creates list of users with given input array
*UserApi* | [**delete_user**](docs/UserApi.md#delete_user) | **DELETE** /user/{username} | Delete user
*UserApi* | [**get_user_by_name**](docs/UserApi.md#get_user_by_name) | **GET** /user/{username} | Get user by user name
*UserApi* | [**login_user**](docs/UserApi.md#login_user) | **GET** /user/login | Logs user into the system
*UserApi* | [**logout_user**](docs/UserApi.md#logout_user) | **GET** /user/logout | Logs out current logged in user session
*UserApi* | [**update_user**](docs/UserApi.md#update_user) | **PUT** /user/{username} | Updated user


## Documentation For Models

- [ApiResponse](docs/ApiResponse.md)
- [Category](docs/Category.md)
- [Order](docs/Order.md)
- [Pet](docs/Pet.md)
- [Tag](docs/Tag.md)
- [User](docs/User.md)


To get access to the crate's generated documentation, use:

```
cargo doc --open
```

## Author



Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# ApiResponse

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**code** | Option<**i32**> | | [optional]
**_type** | Option<**String**> | | [optional]
**message** | Option<**String**> | | [optional]

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)


Loading

0 comments on commit 21f649e

Please sign in to comment.