問題
フロントエンドでOpenAPIから生成した型を使用したところ、response.itemのフィールドが想定と異なり、productCodeを参照できませんでした。
response.item.productCode;
// productCodeが存在しないという型エラー
バックエンドのレスポンスは正しく、生成された型定義だけが一致していませんでした。
原因
原因は、OpenAPI生成処理がネストrecordを識別する際、外側のクラスを含む完全修飾名ではなく、単純な型名をスキーマ名として使用していたことです。
public record CreateOrderResponse(Item item) {
public record Item(String productCode) {}
}
public record CancelOrderResponse(Item item) {
public record Item(String reason) {}
}
Javaではそれぞれ別の型ですが、OpenAPIではどちらも同じItemスキーマとして登録されていました。
["components"]["schemas"]["Item"]
スキーマ名が重複したことで、一方の定義が正しく登録されず、productCodeまたはreasonの片方しかOpenAPIに反映されませんでした。これが、Swagger UIに実際のJavaコードと異なるフィールドが表示された原因です。
対処法
ネストrecordの名前が重複しないよう、それぞれに固有の名前を付けました。
public record CreateOrderResponse(CreateOrderItem item) {
public record CreateOrderItem(String productCode) {}
}
public record CancelOrderResponse(CancelOrderItem item) {
public record CancelOrderItem(String reason) {}
}
これにより別々のスキーマとして生成され、各フィールドが正しくOpenAPIへ反映されました。修正後はOpenAPIを再生成し、フロントエンドの型定義も更新しました。
さらに再発を防ぐなら、ネストrecordを独立したファイルに定義する方法も有効です。型名の重複に気づきやすくなり、同様のスキーマ名衝突を防ぎやすくなります。
まとめ
同名のネストrecordはOpenAPI生成時にスキーマの衝突を引き起こすことがあるため、公開する型には固有の名前を付け、生成結果まで確認することが重要です。