springdoc-openapi用于支持带有泛型的继承的规范生成

huangapple go评论114阅读模式
英文:

springdoc-openapi spec generation for inheritance witth generics

问题

以下是您要翻译的内容:

我有一个Spring Boot(Kotlin)项目,我使用springdoc-openapi生成OpenApi 3规范。我的数据模型如下所示:

open class Animal
data class Cat(val catName: String) : Animal()
data class Dog(val dogName: String) : Animal()

open class Food<T : Animal>
class CatFood : Food<Cat>()
class DogFood : Food<Dog>()

以及一个简单的控制器如下:

@GetMapping("/test")
fun test(): Food<out Animal> = DogFood()

生成的YAML如下:

openapi: 3.0.1
info:
  title: OpenAPI definition
  version: v0
servers:
- url: http://localhost:8085
paths:
  /test:
    get:
      tags:
      - test-controller
      operationId: test
      responses:
        "200":
          description: default response
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/FoodAnimal'
components:
  schemas:
    FoodAnimal:
      type: object

问题在于我的控制器可以返回DogFoodCatFood,并且这在返回类型中指定。我希望生成的模式如下:

openapi: 3.0.1
info:
  title: OpenAPI definition
  version: v0
servers:
- url: http://localhost:8085
paths:
  /test:
    get:
      tags:
      - test-controller
      operationId: test
      responses:
        "200":
          description: default response
          content:
            '*/*':
              schema:
                oneOf:
                  - $ref: '#/components/schemas/FoodAnimal'
                  - $ref: '#/components/schemas/DogFood'
                  - $ref: '#/components/schemas/CatFood'
                
components:
  schemas:
    FoodAnimal:
      type: object
    CatFood:
      allOf:
        - $ref: '#/components/schemas/FoodAnimal'
      type: object
    DogFood:
      allOf:
        - $ref: '#/components/schemas/FoodAnimal'
      type: object

有没有办法实现这一点?

英文:

I have a Spring Boot (kotlin) project for which I use springdoc-openapi to generate OpenApi 3 spec. My data model looks like so:

open class Animal
data class Cat(val catName: String) : Animal()
data class Dog(val dogName: String) : Animal()

open class Food&lt;T : Animal&gt;
class CatFood : Food&lt;Cat&gt;()
class DogFood : Food&lt;Dog&gt;()

and a simple controller like so:

@GetMapping(&quot;/test&quot;)
fun test(): Food&lt;out Animal&gt; = DogFood()

for which the generated yaml is:

openapi: 3.0.1
info:
  title: OpenAPI definition
  version: v0
servers:
- url: http://localhost:8085
paths:
  /test:
    get:
      tags:
      - test-controller
      operationId: test
      responses:
        &quot;200&quot;:
          description: default response
          content:
            &#39;*/*&#39;:
              schema:
                $ref: &#39;#/components/schemas/FoodAnimal&#39;
components:
  schemas:
    FoodAnimal:
      type: object

The problem here is that my controller can return either DogFood or CatFood, and that is specified in the return type. The schema I would expect to be generated is:

openapi: 3.0.1
info:
  title: OpenAPI definition
  version: v0
servers:
- url: http://localhost:8085
paths:
  /test:
    get:
      tags:
      - test-controller
      operationId: test
      responses:
        &quot;200&quot;:
          description: default response
          content:
            &#39;*/*&#39;:
              schema:
                oneOf:
                  - $ref: &#39;#/components/schemas/FoodAnimal&#39;
                  - $ref: &#39;#/components/schemas/DogFood&#39;
                  - $ref: &#39;#/components/schemas/CatFood&#39;
                
components:
  schemas:
    FoodAnimal:
      type: object
    CatFood:
      allOf:
        - $ref: &#39;#/components/schemas/FoodAnimal&#39;
      type: object
    DogFood:
      allOf:
        - $ref: &#39;#/components/schemas/FoodAnimal&#39;
      type: object

Is there some way to achieve this?

答案1

得分: 13

对于继承,您只需要在父类上添加@Schema注释:

@Schema(
    type = "object",
    title = "Food",
    subTypes = [CatFood::class, DogFood::class]
)
open class Food<T : Animal>
class CatFood : Food<Cat>()
class DogFood : Food<Dog>()

如果您需要使用oneOf获取响应,您将需要添加@Response:

@GetMapping("/test")
@ApiResponse(content = [Content(mediaType = "*/*", schema = Schema(oneOf = [Food::class, CatFood::class, DogFood::class]))])
fun test(): Food<out Animal> = DogFood()
英文:

For inheritance, you just need to add @Schema annotation, on your parent class:

@Schema(
		type = &quot;object&quot;,
		title = &quot;Food&quot;,
		subTypes = [CatFood::class, DogFood::class]
)
open class Food&lt;T : Animal&gt;
class CatFood : Food&lt;Cat&gt;()
class DogFood : Food&lt;Dog&gt;()

If you need a reponse using oneOf, you will have to add @Response:

@GetMapping(&quot;/test&quot;)
@ApiResponse(content = [Content(mediaType = &quot;*/*&quot;, schema = Schema(oneOf = [Food::class, CatFood::class,DogFood::class]))])
fun test(): Food&lt;out Animal&gt; = DogFood()

答案2

得分: 2

我在使用OpenApi时在嵌套属性的继承方面遇到了问题。

我使用了JsonSubtype注解和泛型作为一种解决方法。

data class AnimalResponse<FoodResponse>(
    val id: UUID,
    val eats: FoodResponse
)

@JsonSubTypes(value = [
    JsonSubTypes.Type(
        value = CatFoodResponse::class,
        name = "CAT_FOOD"
    ), JsonSubTypes.Type(
        value = DogFoodResponse::class,
        name = "DOG_FOOD"
    )])
interface FoodResponse

这将在AnimalResponse模式中显示所有类型的FoodResponses。

英文:

I had problems using OpenApi with inheritance for nested properties.

I used JsonSubtype annotations and generics as a workaround.

data class AnimalResponse&lt;FoodResponse&gt;(
    val id: UUID,
    val eats: FoodResponse
)

@JsonSubTypes(value = [
    JsonSubTypes.Type(
        value = CatFoodResponse::class,
        name = &quot;CAT_FOOD&quot;
    ), JsonSubTypes.Type(
        value = DogFoodResponse::class,
        name = &quot;DOG_FOOD&quot;
    )])
interface FoodResponse

This will show all types of FoodResponses in AnimalResponse Schema.

huangapple
  • 本文由 发表于 2020年1月3日 15:34:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/59574788.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定