Support for discriminator tag lookup in referenced schemas
What version of Ajv you are you using? 8.12.0
What problem do you want to solve? If the discrimantor property needs to be evaluated in a object which contains a allOf instead of direct properties, the discriminator can not be evaluated. Also the mapping param should be used if one exists.
Example of such a mapping:
Song:
description: A song
type: object
oneOf:
- $ref: '#/components/schemas/InstrumentalSongObject'
- $ref: '#/components/schemas/PopSongObject'
discriminator:
propertyName: type
mapping:
INSTRUMENTAL: '#/components/schemas/InstrumentalSongObject'
POP: '#/components/schemas/PopSongObject'
BaseSong:
description: Base object
type: object
required:
- title
properties:
title:
description: The title
type: string
InstrumentalSong:
description: 'Instrumental Song'
required:
- type
type: object
properties:
type:
type: string
description: Song type
enum:
- INSTRUMENTAL
example: INSTRUMENTAL
band:
description: The band
type: string
PopSong:
description: 'Pop song'
required:
- type
type: object
properties:
type:
type: string
description: Song type
enum:
- POP
example: POP
artist:
description: The artist
type: string
InstrumentalSongObject:
description: A instrumental song
type: object
allOf:
- $ref: '#/components/schemas/BaseSong'
- $ref: '#/components/schemas/InstrumentalSong'
PopSongObject:
description: A pop song
type: object
allOf:
- $ref: '#/components/schemas/BaseSong'
- $ref: '#/components/schemas/PopSong'
What do you think is the correct solution to problem? the getMapping function in the package discriminator needs to be extended tu support allOf for evaluation of the discriminator in the props of these subobjects.
Will you be able to implement it? yes, PR will follow
Semantics of discriminator mean that oneOf should be used, not anyOf. Why is it needed?
Discriminator in itself is no-op, but it is used as an optimisation for faster oneOf validation, requiring that the schema itself is consistent with "discriminator" semantics - that only one of the branches can be valid, and each branch requires a specific different value of discriminator tag.
I see, the issue is not named correctly - it's about looking up the name in the referenced schemas.
I don't think that it needs to be supported to be honest given the complexity. A simple workaround is to either construct the schema programmatically, so that it's included as the whole object, or to repeat the tag value on the top level.
but happy to look at PR, if it's simple enough it might be ok... The traversal would simply stop then at the first schema that defines the tag value.
The problem comes from the practices, that this is a valid schema definition for OAS. Repeating the "Base" object properties instead of using allOf would work, but results later in ugly code from the code generators based on this schema. This, because polymorphism then can not be used anymore and all objects get generated as own interface definitions. That's why such practices (combine oneOf with allOf) are preferred.
Hi team,
I'd like to see this (mapping) supported also. In trivial examples, working around mapping is straightforward. When handling an OAS it's a little more complicated as the referenced schemas can't just be renamed. At the very least, it would make it difficult to present useful errors back to users as the schema would have been transformed.
Is the PR https://github.com/ajv-validator/ajv/pull/2262 something you would consider and does it address the problem?
Hi @epoberezkin, supporting OAS mapping would be really helpful because it becomes more and more common application in the projects that I participated in. I will vote for it as well.
I'm also interested in this issue. Here's a very simplified schema to reproduce. I just want my instance object to be oneOf a few different sub-types(schemas), where each sub-schema "extends" properties from another (not shown below for simplicity)
{
"components": {
"schemas": {
"MySchema": {
"type": "object",
"oneOf": [
{
"$ref": "#/components/schemas/FooSubschema"
}
],
"discriminator": {
"propertyName": "myType"
}
},
"FooSubschema": {
"type": "object",
"allOf": [
// { } imagine a $ref here
{
"properties": {
"myType": {
"type": "string",
"enum": [
"fooType"
]
}
}
}
],
"additionalProperties": false,
"required": [
"myType"
]
}
}
}
}