Better support for polymorphism(replacement for discriminator)
See original GitHub issueMany people including myself asked for full support of JSON Schema.
But I totally understand why oneOf
& anyOf
are causing a lot of problems:
It was never intended to use for anything beyond validation.
discriminator
was good attempt to solve most of the common use cases.
We tried it with our customers and even have added support for it in our documentation engine.
But we have discovered a few issues that limit usability of discriminator
:
- The value of
discriminator
field should match one of the keys indefinitions
object. If you use multiplediscriminator
inside multiple payloads you will experience name clashes. It also breaks namestyle, since a lot of people name schema in camelcase and field values using underscores. And with #634 merged(schema names limited toa-zA-Z0-9.-_\
) it creates a big problem for non-English field values. - There is no support for the default value of
discriminator
. - Limited support in tooling; IMHO limiting factor is that it very hard to detect which types are inherited.
You need to go through all schemas and inspect
allOf
s and it becomes especially problematic when inherited schemas exist in separate files. - I’m not aware of any validator that supports
discriminator
. A solution would be to provide translator ofdiscriminator
intooneOf
and use standard JSON Schema validator afterwards. But translation is hard to implement because of the third point.
My proposal is to replace discriminator
with a new valueSwitch
keyword.
Here is modifiend discriminator example:
definitions:
Pet:
type: object
properties:
name:
type: string
petType:
type: string
required:
- name
- petType
# Proposed keyword
valueSwitch:
# Name of the property which values are used to determinate apropriate subschema
property: petType
# Map of property values on Schema Objects
values:
Cat:
$ref: '#/definitions/CatMixin'
Dog:
$ref: '#/definitions/DogMixin'
# Schema which should be used when property is missing or
# it's value doesn't match any key from `values` object
default:
description: Use specified pet type
properties:
ICZN:
description: International Code of Zoological Nomenclature
type: string
required:
- ICZN
CatMixin:
description: A representation of a cat
type: object
properties:
huntingSkill:
type: string
description: The measured skill for hunting
default: lazy
enum:
- clueless
- lazy
- adventurous
- aggressive
required:
- huntingSkill
DogMixin:
description: A representation of a dog
type: object
properties:
packSize:
type: integer
format: int32
description: the size of the pack the dog is from
default: 0
minimum: 0
required:
- packSize
In the example I also added support for user-defined petType to illustrate usage of default
keyword.
And here is how it solves problems mentioned above:
- field values from payload are used only as keys of
values
object. - Support for
default
, see above example. - To fully understand schema you need to go only through schema itself and all schemas referenced from it.
- You can translate above
valueSwitch
into pure JSON Schema Draft4 using straightforward algorithm, for example:
oneOf:
- type: object
required:
- petType
properties:
petType:
enum:
- Cat
allOf:
- $ref: '#/definitions/CatMixin'
- type: object
required:
- petType
properties:
petType:
enum:
- Dog
allOf:
- $ref: '#/definitions/DogMixin'
- properties:
petType:
not:
enum:
- Cat
- Dog
allOf:
description: Use specified pet type
properties:
ICZN:
description: International Code of Zoological Nomenclature
type: string
required:
- ICZN
Moreover it is possible to convert discriminator
into valueSwitch
for all existing Swagger specs.
Issue Analytics
- State:
- Created 7 years ago
- Reactions:5
- Comments:7 (5 by maintainers)
Top GitHub Comments
@ralfhandl You just need to use
allOf
for it:values
has normal Schema Objects as values, so you can use everything that Swagger support:allOf
,$ref
,type
, etc. You can even add nestedvalueSwitch
😄@wparad It possible to implement in all typed-languages I know of, most of them natively support polymorphism and the rest support “union”-like types. You can even implement it in pure C, using
union
type. What’s important you always have access to property used for switching,petType
in above example. On implementation side it very simple you just add singleswitch
which executed in runtime and it exactly the same as currentdiscriminator
.In really most of the time developers used only two patterns for dynamic data in JSON:
typeSwitch
keyword.To handle exotic cases you need to add something very similar to
oneOf
and that’s clearly not going to happen. So instead of creating some theoretical all in one solution let’s solve real-life problems without introducing too much complexity into tooling and the spec itself.I’d like to suggest another approach to handling the general idea here. How about we get some examples of different modeling challenges and then put together a comprehensive solution from them? Maybe it’s been done but It would be great to start linking to them here.