How can I generate an openapi definition which supports a polymorphic request body, and can generate client and server stubs accordingly?

Viewed 3822

Let's say I have a Spring Boot REST API with the following endpoint and models defined (getters/setters omitted for brevity)

@JsonTypeInfo( property = "type", include = JsonTypeInfo.As.PROPERTY, use = JsonTypeInfo.Id.NAME )
@JsonSubTypes( { @JsonSubTypes.Type( FooWidget.class ), @JsonSubTypes.Type( BarWidget.class ) } )
public interface Widget {}

public class BarWidget implements Widget { private String bar; }

public class FooWidget implements Widget { private String foo; }

public class WidgetGroup
{
    private List<Widget> widgets;
}

@RestController
public class WidgetController
{
    @PostMapping( "/widgets" )
    public void createWidgets( @RequestBody WidgetGroup widgets )
    {
    }
}

Is it possible to express this in an OpenAPI spec so that a generator could both

  • reproduce the above code as server stubs and models
  • produce a Javascript client which correctly represented the models and API

Having set this up and tried both springdoc and springfox to generate me a spec from the code, I've then not been able to reverse the process - the above code generates the following spec via Springdoc:

openapi: 3.0.1
info:
  title: OpenAPI definition
  version: v0
servers:
  - url: 'http://localhost:8080'
    description: Generated server url
paths:
  /widgets:
    post:
      tags:
        - widget-controller
      operationId: createWidgets
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WidgetGroup'
        required: true
      responses:
        '200':
          description: OK
components:
  schemas:
    BarWidget:
      type: object
      allOf:
        - $ref: '#/components/schemas/Widget'
        - type: object
          properties:
            bar:
              type: string
    FooWidget:
      type: object
      allOf:
        - $ref: '#/components/schemas/Widget'
        - type: object
          properties:
            foo:
              type: string
    Widget:
      required:
        - type
      type: object
      properties:
        type:
          type: string
      discriminator:
        propertyName: type
    WidgetGroup:
      type: object
      properties:
        widgets:
          type: array
          items:
            oneOf:
              - $ref: '#/components/schemas/BarWidget'
              - $ref: '#/components/schemas/FooWidget'

When using both Java and Javascript generators, the inheritance information seems to get lost and odd classes like "BarWidgetAllOf" get generated. Is this a limitation in the expressiveness of the OAS spec, or just a limitation in the implementations of the generators (I have tried both with the swagger-codegen and openapitools generators)?

1 Answers

The generated OpenAPI spec is correct regarding your code.

This is not a limitation, but there needs to be default generation which is commonly used.

If you want finer control of the generated spec, you can swagger @Schema annotation (without using JsonSubTypes), as explained in this two issues with examples:

Related