Forum Discussion

AlexeyNezhdanov's avatar
AlexeyNezhdanov
Occasional Contributor
5 years ago

Can I have a polymorphic property that is not of type "Object"?

Hello.

 

I am trying to come up with a single openapi.yaml that would serve for both code generation and API documentation.
However, I'm having troubles with reaching both goals with a single file because of a polymorphism.

Every time I try I either get ugly "Example Values" in the online documentation or just blunt "Object" types in generated classes or both.

Let me illustrate: I have two endpoints, one of which returns a single polymorphic object and other returns a list of these.
That is "GET /allPets" - would yield a list of Pets and Dogs and "GET /randomPet" would return a single Pet.

If I would be writing my classes in a plain Java, then Pet would be an abstract class or an interface and Cat and Dog would inherit from/implement it. Therefore this abstract type would be used for both endpoints.

However, this is not something I achieve with OpenAPI. May be I am just approaching the problem from the wrong end.


Here is the definition:

 

openapi: "3.0.0"
info:
  version: 1.0.0
  title: PetStore
paths:
  /randomPet:
    get:
      responses:
        '200':
          description: "a single random pet"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SinglePetResponse'
  /allPets:
    get:
      responses:
        '200':
          description: "a single random pet"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AllPetsResponse'
components:
  schemas:
    SinglePetResponse:
      type: object
      properties:
        pet:
          oneOf:
            - $ref: "#/components/schemas/Dog"
            - $ref: "#/components/schemas/Cat"
          discriminator:
            propertyName: pet_type
    AllPetsResponse:
      type: array
      items:
        oneOf:
          - $ref: "#/components/schemas/Dog"
          - $ref: "#/components/schemas/Cat"
        discriminator:
          propertyName: pet_type
    Pet:
      type: object
      required:
        - pet_type
      properties:
        pet_type:
          type: string
      discriminator:
        propertyName: pet_type
    Dog:     # "Dog" is a value for the pet_type property (the discriminator value)
      allOf: # Combines the main `Pet` schema with `Dog`-specific properties 
        - $ref: '#/components/schemas/Pet'
        - type: object
          # all other properties specific to a `Dog`
          properties:
            bark:
              type: boolean
            breed:
              type: string
              enum: [Dingo, Husky, Retriever, Shepherd]
    Cat:     # "Cat" is a value for the pet_type property (the discriminator value)
      allOf: # Combines the main `Pet` schema with `Cat`-specific properties 
        - $ref: '#/components/schemas/Pet'
        - type: object
          # all other properties specific to a `Cat`
          properties:
            hunts:
              type: boolean
            age:
              type: integer

The classes I end up with essentially boil down to:

public class SinglePetResponse   {
  private @Valid Object pet = null;
}

and

 

public class AllPetsResponse extends ArrayList<Object>  {
}

On top of that the "SinglePetResponse" is rendered as an empty object in the UI.

 

It is important for me to nest these properties under other objects - because in the real system the responses are much more than just a list of objects - they have other fields, too.

 

What I would like to see is the "Pet" class used instead of "Object" and a better rendering in the UI (a random type or just a first time would suffice). A nice, but not required property would be the Pet class being abstract.

 

Is there a way to achieve this with OpenAPI 3?

 

Best regards,

Alexey Nezhdanov

 

 

8 Replies