Implementation of 'discriminator' in current schema is unable to produce inheritance tree of api models (also defunct serialiser annotation)
For our development we use code generators supplied by OpenApi tools.
Using the current release schema as the input to this tooling we observe unexpected results in the expected api model hierarchy - in fact there is no inheritance of models applied.
For example consider the NetworkService response described by this yaml snippet:
NetworkService:
description: Polymorphic Network Services
discriminator:
mapping:
cloud_vc: '#/components/schemas/CloudNetworkService'
exchange_lan: '#/components/schemas/ExchangeLanNetworkService'
mp2mp_vc: '#/components/schemas/MP2MPNetworkService'
p2mp_vc: '#/components/schemas/P2MPNetworkService'
p2p_vc: '#/components/schemas/P2PNetworkService'
propertyName: type
oneOf:
- $ref: '#/components/schemas/ExchangeLanNetworkService'
- $ref: '#/components/schemas/P2PNetworkService'
- $ref: '#/components/schemas/P2MPNetworkService'
- $ref: '#/components/schemas/MP2MPNetworkService'
- $ref: '#/components/schemas/CloudNetworkService'
title: NetworkService
When openapi tooling is applied to this schema, it results in no common base class(or interface) for the schemas(classes) found in the oneOf
listing. Instead we observe a class which has an aggregation of fields found in the schemas(classes) in the oneOf
listing. There is an attempt by the tooling to apply serialisation annotation (related to Netwonsoft.Json) in order to materialise the polymorphism described in the yaml but it fails as there is no direct linkage of the oneOf
listings with the NetworkService schema (ie there is no explicit inheritance of NetworkService with sub-schemas via allOf
directives).
The problem has further complication due to there being a default *Partial schema for each expected api model which materialises as base class after the tooling has been applied.
For example:
ExchangeLanNetworkService:
allOf:
- $ref: '#/components/schemas/ExchangeLanNetworkServicePartial'
Most robust Object-Oriented languages would side-step the problem of multiple inheritance (ie not allow it) so in this way it may cause difficulty for tooling to produce a base class - as in this case ExchangeLanNetworkService
cannot both be a NetworkService
and ExchangeLanNetworkServicePartial
so this may be causing an issue with the expected generation of api model inheritance for these schemas(classes).
Our internal investigations has deduced that the OpenApi specification has provided a secondary usage of discriminators for polymorphic class trees - please see here
The first section pertains to the current mechanism utilising oneOf
with a discriminator mapping - however further reading of this section highlights a method which correctly outputs polymorphic modes via openapi tooling.
Taken directly from the spec is this yaml snippet which to our understanding can be utilised in place of oneOf
+ discriminator
notation and correctly renders polymorphic models with correct json serialiser attributes applied.
components:
schemas:
Pet:
type: object
required:
- petType
properties:
petType:
type: string
discriminator:
propertyName: petType
mapping:
dog: Dog
cat: Cat
lizard: Lizard
Cat:
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
# all other properties specific to a `Cat`
properties:
name:
type: string
Dog:
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
# all other properties specific to a `Dog`
properties:
bark:
type: string
Lizard:
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
# all other properties specific to a `Lizard`
properties:
lovesRocks:
type: boolean
Consider the generated base class Pet
of this schema.
[DataContract]
[JsonConverter(typeof(JsonSubtypes), "PetType")]
[JsonSubtypes.KnownSubType(typeof(Cat), "cat")]
[JsonSubtypes.KnownSubType(typeof(Dog), "dog")]
[JsonSubtypes.KnownSubType(typeof(Lizard), "lizard")]
public partial class Pet : IEquatable<Pet>, IValidatableObject
{
...
[DataMember(Name="petType", EmitDefaultValue=false)]
public string PetType { get; set; }
...
}
This appears correctly to give us a discriminator that is integrated and usable with the serialisation library (Newtonsoft.Json).
It also results in inheritance applied to classes generated from sub-schema.
[DataContract]
public partial class Lizard : Pet, IEquatable<Lizard>, IValidatableObject{
...
}
We would clearly like to leverage both effective polymorphism of models and integrated (de)serialisation of models with the serialisation library as the above schema -> code example provides us.
Further to note that when we have applied the openapi code-gen tooling to other langauage output (python/java/..) - none have shown an effective inheritance tree of api models.
After this analysis the questions are:
- What is the intended usage and inclusion of *Partial schemas in the current release/staging schemas
- is it not possible to encapsulate the Partial schema and the non-Partial schema in 1 schema
- Can it be considered that the current
oneOf
implementation could be erroneous or not to be in line with the intentions of the maintainers of the schema? - Is the tooling the issue?
- How can the open api documentation describe the discriminator usage in 2 different ways and yet produce different outputs after code-gen?
Thanks in advance for your review and response.