Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,10 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
processParam(param, op);
}

for (CodegenParameter param : op.queryParams) {
processParam(param, op);
}

// We keep track of the 'default' model type for this API. If there are
// *any* XML responses, then we set the default to XML, otherwise we
// let the default be JSON. It would be odd for an API to want to use
Expand Down Expand Up @@ -1064,6 +1068,25 @@ public CodegenParameter fromRequestBody(RequestBody body, Set<String> imports, S
return codegenParameter;
}

@Override
public void setParameterExampleValue(CodegenParameter codegenParameter, Parameter parameter) {
// Check whether the spec provides an example before calling super, which
// will fall back to auto-generating one from the param name/type.
boolean hasSpecExample =
parameter.getExample() != null ||
(parameter.getExamples() != null && !parameter.getExamples().isEmpty()) ||
(parameter.getSchema() != null && parameter.getSchema().getExample() != null);

super.setParameterExampleValue(codegenParameter, parameter);

if (!hasSpecExample) {
// Null out the auto-generated example so processParam can detect
// required params with no user-provided example and disable the
// client example stub accordingly.
codegenParameter.example = null;
}
}

@Override
public String getTypeDeclaration(String name) {
return "models::" + name;
Expand Down Expand Up @@ -1675,15 +1698,30 @@ private void processParam(CodegenParameter param, CodegenOperation op) {
example = (param.example != null) ? "&vec![\"" + param.example + "\".to_string()]" : "&Vec::new()";
} else if (param.isString) {
param.vendorExtensions.put("x-format-string", "\\\"{}\\\"");
example = "\"" + ((param.example != null) ? param.example : "") + "\".to_string()";
if (param.example != null) {
example = "\"" + param.example + "\".to_string()";
}
} else if (param.isPrimitiveType) {
if ((param.isByteArray) || (param.isBinary)) {
// Binary primitive types don't implement `Display`.
param.vendorExtensions.put("x-format-string", "{:?}");
example = "swagger::ByteArray(Vec::from(\"" + ((param.example != null) ? param.example : "") + "\"))";
} else if (param.isBoolean) {
param.vendorExtensions.put("x-format-string", "{}");
example = (param.example != null) ? param.example : "true";
} else {
param.vendorExtensions.put("x-format-string", "{}");
example = (param.example != null) ? param.example : "";
if (param.example != null) {
example = param.example;
} else if (param.isFloat || param.isDouble) {
// No example in spec: use the type zero value. This appears only in
// generated client example code.
example = "0.0";
} else if (param.isInteger || param.isLong || param.isShort || param.isNumber) {
// No example in spec: use the type zero value. This appears only in
// generated client example code.
example = "0";
}
}
} else if (param.isArray) {
param.vendorExtensions.put("x-format-string", "{:?}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,19 @@ fn main() {
let matches = Command::new("client")
.arg(Arg::new("operation")
.help("Sets the operation to run")
.value_parser([
.value_parser(Vec::<&str>::from([
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{#operation}}
{{^exts.x-no-client-example}}
"{{{operationId}}}",
{{/exts.x-no-client-example}}
{{/operation}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
])
]))
.required(true)
.index(1))
.arg(Arg::new("https")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,16 @@ impl serde_valid::validation::ValidateCompositedMinLength for {{{classname}}} {
Ok(())
}
}

#[cfg(feature = "validate")]
impl serde_valid::validation::ValidateCompositedMaxLength for {{{classname}}} {
fn validate_composited_max_length(
&self,
_max_length: usize,
) -> Result<(), serde_valid::validation::Composited<serde_valid::validation::error::MaxLengthError>> {
Ok(())
}
}
{{/hasConflictingModelNames}}
{{#exts.x-to-string-support}}
{{#exts.x-is-string}}
Expand Down Expand Up @@ -432,6 +442,28 @@ pub struct {{{classname}}} {
{{/vars}}
}

{{^hasConflictingModelNames}}
#[cfg(feature = "validate")]
impl serde_valid::validation::ValidateCompositedMinLength for {{{classname}}} {
fn validate_composited_min_length(
&self,
_min_length: usize,
) -> Result<(), serde_valid::validation::Composited<serde_valid::validation::error::MinLengthError>> {
Ok(())
}
}

#[cfg(feature = "validate")]
impl serde_valid::validation::ValidateCompositedMaxLength for {{{classname}}} {
fn validate_composited_max_length(
&self,
_max_length: usize,
) -> Result<(), serde_valid::validation::Composited<serde_valid::validation::error::MaxLengthError>> {
Ok(())
}
}
{{/hasConflictingModelNames}}

{{#vars}}
{{#hasValidation}}
{{#pattern}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,27 @@ public void testIntegerParameterTypeFitting() throws IOException {
// Clean up
target.toFile().deleteOnExit();
}

/**
* Test that required query params without examples disable the client example.
*/
@Test
public void testRequiredQueryParamWithoutExampleDisablesClientExample() throws IOException {
Path target = Files.createTempDirectory("test");
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("rust-server")
.setInputSpec("src/test/resources/3_0/rust-server/openapi-v3.yaml")
.setSkipOverwrite(false)
.setOutputDir(target.toAbsolutePath().toString().replace("\\", "/"));
List<File> files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate();
files.forEach(File::deleteOnExit);

Path exampleClientMain = Path.of(target.toString(), "/examples/client/main.rs");
TestUtils.assertFileExists(exampleClientMain);
TestUtils.assertFileContains(exampleClientMain, "Disabled because there's no example.");
TestUtils.assertFileContains(exampleClientMain, "Some(\"QueryExampleGet\")");

// Clean up
target.toFile().deleteOnExit();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/allOfObject'

parameters:
nested_response:
name: nested_response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,26 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/anotherXmlObject"
/query-example:
get:
summary: Test required query params with and without examples
operationId: queryExampleGet
parameters:
- name: required_no_example
in: query
required: true
schema:
type: string
- name: required_with_example
in: query
required: true
example: 42
schema:
type: integer
format: int32
responses:
200:
description: OK
/multiget:
get:
summary: Get some stuff.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ cargo run --example openapi-v3-client MultipleAuthSchemeGet
cargo run --example openapi-v3-client OneOfGet
cargo run --example openapi-v3-client OverrideServerGet
cargo run --example openapi-v3-client ParamgetGet
cargo run --example openapi-v3-client QueryExampleGet
cargo run --example openapi-v3-client ReadonlyAuthSchemeGet
cargo run --example openapi-v3-client RegisterCallbackPost
cargo run --example openapi-v3-client RequiredOctetStreamPut
Expand Down Expand Up @@ -166,6 +167,7 @@ Method | HTTP request | Description
[****](docs/default_api.md#) | **GET** /one-of |
[****](docs/default_api.md#) | **GET** /override-server |
[****](docs/default_api.md#) | **GET** /paramget | Get some stuff with parameters.
[**queryExampleGet**](docs/default_api.md#queryExampleGet) | **GET** /query-example | Test required query params with and without examples
[****](docs/default_api.md#) | **GET** /readonly_auth_scheme |
[****](docs/default_api.md#) | **POST** /register-callback |
[****](docs/default_api.md#) | **PUT** /required_octet_stream |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,30 @@ paths:
$ref: "#/components/schemas/anotherXmlObject"
description: JSON rsp
summary: Get some stuff with parameters.
/query-example:
get:
operationId: queryExampleGet
parameters:
- explode: true
in: query
name: required_no_example
required: true
schema:
type: string
style: form
- example: 42
explode: true
in: query
name: required_with_example
required: true
schema:
format: int32
type: integer
style: form
responses:
"200":
description: OK
summary: Test required query params with and without examples
/multiget:
get:
responses:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use openapi_v3::{
OneOfGetResponse,
OverrideServerGetResponse,
ParamgetGetResponse,
QueryExampleGetResponse,
ReadonlyAuthSchemeGetResponse,
RegisterCallbackPostResponse,
RequiredOctetStreamPutResponse,
Expand Down Expand Up @@ -151,6 +152,11 @@ enum Operation {
#[structopt(parse(try_from_str = parse_json), long)]
some_list: Option<Vec<models::MyId>>,
},
/// Test required query params with and without examples
QueryExampleGet {
required_no_example: String,
required_with_example: i32,
},
ReadonlyAuthSchemeGet {
},
RegisterCallbackPost {
Expand Down Expand Up @@ -546,6 +552,24 @@ async fn main() -> Result<()> {
&serde_json::to_string_pretty(&body)?,
}
}
Operation::QueryExampleGet {
required_no_example,
required_with_example,
} => {
info!("Performing a QueryExampleGet request");

let result = client.query_example_get(
required_no_example,
required_with_example,
).await?;
debug!("Result: {:?}", result);

match result {
QueryExampleGetResponse::OK
=> "OK\n".to_string()
,
}
}
Operation::ReadonlyAuthSchemeGet {
} => {
info!("Performing a ReadonlyAuthSchemeGet request");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Method | HTTP request | Description
****](default_api.md#) | **GET** /one-of |
****](default_api.md#) | **GET** /override-server |
****](default_api.md#) | **GET** /paramget | Get some stuff with parameters.
**queryExampleGet**](default_api.md#queryExampleGet) | **GET** /query-example | Test required query params with and without examples
****](default_api.md#) | **GET** /readonly_auth_scheme |
****](default_api.md#) | **POST** /register-callback |
****](default_api.md#) | **PUT** /required_octet_stream |
Expand Down Expand Up @@ -412,6 +413,32 @@ No authorization required

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

# **queryExampleGet**
> queryExampleGet(required_no_example, required_with_example)
Test required query params with and without examples

### Required Parameters

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**required_no_example** | **String**| |
**required_with_example** | **i32**| |

### Return type

(empty response body)

### Authorization

No authorization required

### HTTP request headers

- **Content-Type**: Not defined
- **Accept**: Not defined

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

# ****
> (ctx, )

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use openapi_v3::{Api, ApiNoContext, Claims, Client, ContextWrapperExt, models,
OneOfGetResponse,
OverrideServerGetResponse,
ParamgetGetResponse,
QueryExampleGetResponse,
ReadonlyAuthSchemeGetResponse,
RegisterCallbackPostResponse,
RequiredOctetStreamPutResponse,
Expand Down Expand Up @@ -79,6 +80,7 @@ fn main() {
"OneOfGet",
"OverrideServerGet",
"ParamgetGet",
"QueryExampleGet",
"ReadonlyAuthSchemeGet",
"RegisterCallbackPost",
"RequiredOctetStreamPut",
Expand Down Expand Up @@ -254,6 +256,13 @@ fn main() {
));
info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has<XSpanIdString>).get().clone());
},
Some("QueryExampleGet") => {
let result = rt.block_on(client.query_example_get(
"required_no_example_example".to_string(),
42
));
info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has<XSpanIdString>).get().clone());
},
Some("ReadonlyAuthSchemeGet") => {
let result = rt.block_on(client.readonly_auth_scheme_get(
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ use openapi_v3::{
OneOfGetResponse,
OverrideServerGetResponse,
ParamgetGetResponse,
QueryExampleGetResponse,
ReadonlyAuthSchemeGetResponse,
RegisterCallbackPostResponse,
RequiredOctetStreamPutResponse,
Expand Down Expand Up @@ -255,6 +256,16 @@ impl<C> Api<C> for Server<C> where C: Has<XSpanIdString> + Send + Sync
info!("paramget_get({:?}, {:?}, {:?}) - X-Span-ID: {:?}", uuid, some_object, some_list, context.get().0.clone());
Err(ApiError("Api-Error: Operation is NOT implemented".into()))
}
/// Test required query params with and without examples
async fn query_example_get(
&self,
required_no_example: String,
required_with_example: i32,
context: &C) -> Result<QueryExampleGetResponse, ApiError>
{
info!("query_example_get(\"{}\", {}) - X-Span-ID: {:?}", required_no_example, required_with_example, context.get().0.clone());
Err(ApiError("Api-Error: Operation is NOT implemented".into()))
}
async fn readonly_auth_scheme_get(
&self,
context: &C) -> Result<ReadonlyAuthSchemeGetResponse, ApiError>
Expand Down
Loading
Loading