openapi-generator icon indicating copy to clipboard operation
openapi-generator copied to clipboard

[BUG][RUST-AXUM] rust-axum generator does not handle uuid::Uuid in headerParams

Open myz-dev opened this issue 1 year ago • 0 comments

Version used

openapi-generator version: 7.6.0-SNAPSHOT

Description

The rust-axum generator has the following issue: It is smart enough to detect the format: uuid specifier in openAPI types and map those parameters to the Rust type uuid::Uuid. Problem: When the openAPI type is within a header, the generated Rust code fails to convert the header value string into a uuid::Uuid because of a missing impl TryFrom<HeaderValue> for IntoHeaderValue<uuid::Uuid> implementation.

This makes generated code like this invalid:

// in src/server/mod.rs
Some(v) => match header::IntoHeaderValue::<uuid::Uuid>::try_from((*v).clone()) {

Specification

This is my minimal openAPI spec that reproduces the issue:

openapi: 3.0.0
info:
  title: Sample API
  version: 0.1.9
paths:
  /users:
    post:
      summary: Create a user.
      description: Adds a user to the users database table.
      parameters: 
        - $ref: "#/components/parameters/CorrelatonIdHeaderParam"
      responses:
        "201": # status code
          description: Added row to table!
          content:
            application/json:
              schema:
                type: number 
components:
  schemas: 
      CorrelationId:
        type: string
        format: uuid
        example: a9f5a638-728c-479d-af9b-016eb8049ab6
  parameters: 
    CorrelatonIdHeaderParam:
      name: some_uid
      in: header
      required: true
      description: lets say we need this.
      schema:
        $ref: "#/components/schemas/CorrelationId"

Generation details:

I just call the CLI with these options: java -jar openapi-generator-cli.jar generate -i minimal.yaml -g rust-axum -o out

Suggestion:

A very easy fix would be to add this to the end of the modules/openapi-generator/src/main/resources/rust-axum/header.mustache file unconditionally:

//  uuid::Uuid

impl TryFrom<HeaderValue> for IntoHeaderValue<uuid::Uuid> {
    type Error = String;

    fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> {
        match hdr_value.to_str() {
            Ok(hdr_value) => match uuid::Uuid::from_str(hdr_value) {
                Ok(uuid) => Ok(IntoHeaderValue(uuid)),
                Err(e) => Err(format!("Unable to parse: {} as uuid - {}", hdr_value, e)),
            },
            Err(e) => Err(format!(
                "Unable to convert header {:?} to string {}",
                hdr_value, e
            )),
        }
    }
}

impl TryFrom<IntoHeaderValue<uuid::Uuid>> for HeaderValue {
    type Error = String;

    fn try_from(hdr_value: IntoHeaderValue<uuid::Uuid>) -> Result<Self, Self::Error> {
        match HeaderValue::from_bytes(hdr_value.0.as_bytes()) {
            Ok(hdr_value) => Ok(hdr_value),
            Err(e) => Err(format!(
                "Unable to convert {:?} to a header: {}",
                hdr_value, e
            )),
        }
    }
}

I wanted to add this code in conditionally, when there is at least one header parameter, with the format set to uuid. I tried to implement this idea but I neither have any Java experience nor do I understand the flow of the generator program at the moment. What I have tried so far: Within RustAxumServerCodegen.java in the public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List<Server> servers) { function I have collected all the parameters in a list:

private List<String> typesWithinHeader = new ArrayList<>();
// later within public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List<Server> servers) 
typesWithinHeader = op.headerParams.stream().map(CodegenParameter::getDataType).collect(Collectors.toList()); 

Now I would like to add the suggested fix above to headers.mustache only when this array is not empty. In a further step the contents of this array could be used to also add conversion implementations for other types than uuid::Uuid that might break the generated code in the future (I cannot think of any right now).

Also just trying to loop over all header parameters in the header.mustache file does not produce any output at all. I wonder if the template is populated without passing any parameters to it:

{{#headerParams}}
This is not included in the final `header.rs` even though there are `headerParams` in the resulting `CodegenOperation` structure
{{/headerParams}}

myz-dev avatar May 02 '24 09:05 myz-dev