openapi-generatorで生成したRustのコードで数値からEnumへのDeserializeができない

前提

  • openapi-generator
    • generator-cli
      • version: 7.11.0
    • generatorName: rust

経緯

今まで対向APIのOpenAPI Specがなかったので自身のプロジェクトで書いていたが、対向APIを開発しているチームからOpenAPI Specが提供されるようになった。 そのため、提供されたOpenAPI Specを使ってopenapi-generatorでRustコードを生成した。

生成されたコードを使ってユニットテストを実行するとFAILするようになった。 エラーを読んでみると、対向APIJSONレスポンスをDeserializeするときにエラーになっていた。

試してみた

提供されたOpenAPI Specは以下のような感じ。

paths:
  /example/user:
    get:
      response:
        200:
          content:
            application/json:  
              schema:
                allOf:
                  $ref: '#/components/schemas/personal_info'
                ...
components:
  schemas:
    personal_info:
      type: object
      properties:
        gender:
          type: integer
          format: int64
          enum:
            - 1
            - 2

生成されたEnumは以下のとおり。 #[serde(rename = "1")] のようなattributeを使うと文字列のマッピングが行われるので、数値からDeserializeできずにエラーになってしまう。 期待するのは数値からEnumに変換できるコードだ。

#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]  
pub enum Gender {  
    #[serde(rename = "1")]  
    Variant1,  
    #[serde(rename = "2")]  
    Variant2,  
}

openapi-generatorのrustのテンプレートをみてみると #isInteger の場合に #[repr(i64)] を付けてくれそう。 https://github.com/OpenAPITools/openapi-generator/blob/v7.11.0/modules/openapi-generator/src/main/resources/rust/model.mustache#L19-L22

でも、現状は以下の部分でEnumが生成されていそう。 https://github.com/OpenAPITools/openapi-generator/blob/v7.11.0/modules/openapi-generator/src/main/resources/rust/model.mustache#L178-L188

ということで、修正したのが以下のOpenAPI Spec。

paths:
  /example/user:
    get:
      response:
        200:
          content:
            application/json:  
              schema:
                allOf:
                  $ref: '#/components/schemas/personal_info'
                ...
components:
  schemas:
    personal_info:
      type: object
      properties:
        gender:
          $ref: '#/components/schemas/gender' # 変更点
        ...
   gender: # genderをschemaに切り出した
     type: integer
     format: int32
     enum:
       - 1
       - 2

上記のOpenAPI Specからコードを再生成すると以下のような期待するコードになった。

#[repr(i64)]  
#[derive(  
    Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize_repr, Deserialize_repr,)]  
pub enum Gender {  
    Variant1 = 1,  
    Variant2 = 2,
}

format: int32 なのに #[repr(i64)] なのが、少しモヤりポイント。 openapi-generator側のバグなのかわからないので、そこらへんはまだ調査中。