[BUG][Rust-Axum] Validation creates invalid code with certain schemas
Bug Report Checklist
- [x] Have you provided a full/minimal spec to reproduce the issue?
- [x] Have you validated the input using an OpenAPI validator (example)?
- [x] Have you tested with the latest master to confirm the issue still exists?
- [x] Have you searched for related issues/PRs?
- [x] What's the actual output vs expected output? Expected: code that compiles. Actual: code with a signature conflict.
- [ ] [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
A schema that defines a type with a validation pattern causes the code generation step to produce code that fails to compile:
|
29 | #[derive(validator::Validate)]
| ^^^^^^^^^^^^^^^^^^^ expected `&[u8]`, found `&Email`
...
32 | #[validate(custom(function = "validate_byte_mailputbodyvalidator"))]
| ------------------------------------ arguments to this function are incorrect
|
= note: expected reference `&[u8]`
found reference `&'a Email`
note: function defined here
--> output/rust-axum-validation-test/src/server/mod.rs:39:4
|
39 | fn validate_byte_mailputbodyvalidator(
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40 | b: &[u8],
| --------
= note: this error originates in the derive macro `validator::Validate` (in Nightly builds, run with -Z macro-backtrace for more info)
openapi-generator version
7.6.0-SNAPSHOT
OpenAPI declaration file content or url
openapi: 3.0.1
info:
title: Test to check that validation logic is not rendered when disabled.
version: 0.0.1
paths:
/mail:
put:
description: Updates the email.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Email"
responses:
"204":
description: OK.
components:
schemas:
Email:
type: string
pattern: '^[\w\-\.]+@([\w-]+\.)+[\w-]{2,}$'
example: [email protected]
Generation Details
This happens also when the CLI option disableValidator is set to true. This option makes the code generation step not call the function that causes the compilation error. But it still generates the faulty code so the project can not be compiled.
Steps to reproduce
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -i validation_example.yaml -g rust-axum -o out --additional-properties disableValidator=true
Suggest a fix
The first step is to not create the validation code at all when disableValidator is set to true. This is an easy fix that I can provide quickly.
The second step would be to create valid code when it needs to be created. Manually this can be solved with a different function signature and the implementation of a conversion trait, but I have not yet understood how to solve this generally in the code generation process.
Manual fix example:
Faulty:
#[derive(validator::Validate)]
#[allow(dead_code)]
struct MailPutBodyValidator<'a> {
#[validate(
custom(function = "validate_byte_mailputbodyvalidator"),
)]
body: &'a models::Email,
}
lazy_static::lazy_static! {
static ref RE_MAILPUTBODYVALIDATOR: regex::bytes::Regex = regex::bytes::Regex::new(r"^[\\w\\-\\.]+@([\\w-]+\\.)+[\\w-]{2,}$").unwrap();
}
fn validate_byte_mailputbodyvalidator(
b: &[u8]
) -> std::result::Result<(), validator::ValidationError> {
if !RE_MAILPUTBODYVALIDATOR.is_match(b) {
return Err(validator::ValidationError::new("Character not allowed"));
}
Ok(())
}
Fix:
#[derive(validator::Validate)]
#[allow(dead_code)]
struct MailPutBodyValidator<'a> {
#[validate(custom(function = "validate_byte_mailputbodyvalidator"))]
body: &'a models::Email,
}
lazy_static::lazy_static! {
static ref RE_MAILPUTBODYVALIDATOR: regex::bytes::Regex = regex::bytes::Regex::new(r"^[\\w\\-\\.]+@([\\w-]+\\.)+[\\w-]{2,}$").unwrap();
}
fn validate_byte_mailputbodyvalidator(
b: &models::Email, // <-- change signature
) -> std::result::Result<(), validator::ValidationError> {
let b = b.into(); // <-- call conversion
if !RE_MAILPUTBODYVALIDATOR.is_match(b) {
return Err(validator::ValidationError::new("Character not allowed"));
}
Ok(())
}
impl<'a> From<&'a models::Email> for &'a [u8] { // <-- implement conversion
fn from(value: &'a models::Email) -> Self {
value.as_bytes()
}
}
This manual solution fails as soon as the model to convert does not implement a as_bytes() method. So I am trying to figure out how to get to a more general solution.