Skip to content

Commit e3f3d89

Browse files
fall back to "defaultMapping" in discriminator
...when the propertyName is not present in the data payload This keyword is new in 3.2.0, allowing the property named by the propertyName keyword (still required!) to be absent in the payload see also OAI/OpenAPI-Specification#5227
1 parent 7fb2c9f commit e3f3d89

3 files changed

Lines changed: 38 additions & 6 deletions

File tree

Changes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Revision history for OpenAPI-Modern
22

33
{{$NEXT}}
4+
- support "defaultMapping" in the 3.2.0 discriminator object
45

56
0.128 2026-02-21 23:11:29Z
67
- header parameters now support Unicode header names and

lib/JSON/Schema/Modern/Vocabulary/OpenAPI.pm

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,18 @@ sub _eval_keyword_discriminator ($self, $data, $schema, $state) {
5959
# Note: the spec is unclear of the expected behaviour when the data instance is not an object
6060
return 1 if not is_type('object', $data);
6161

62+
# v3.1.2 §4.8.25.1: "This property SHOULD be required in the payload schema, as the behavior when
63+
# the property is absent is undefined."
64+
# v3.2.0 §4.25.1: "The discriminating property MAY be defined as required or optional, but when
65+
# defined as optional the Discriminator Object MUST include a defaultMapping field that specifies
66+
# which schema is expected to validate the structure of the model when the discriminating property
67+
# is not present."
6268
my $discriminator_key = $schema->{discriminator}{propertyName};
69+
return E($state, 'missing required discriminator property "%s" and no defaultMapping present',
70+
$discriminator_key)
71+
if not exists $data->{$discriminator_key} and not exists $schema->{discriminator}{defaultMapping};
6372

64-
# property with name <propertyName> MUST be present in the data payload
65-
return E($state, 'missing required discriminator property "%s"', $discriminator_key)
66-
if not exists $data->{$discriminator_key};
67-
68-
my $discriminator_value = $data->{$discriminator_key};
73+
my $discriminator_value = $data->{$discriminator_key} // $schema->{discriminator}{defaultMapping};
6974

7075
if (exists $schema->{discriminator}{mapping} and exists $schema->{discriminator}{mapping}{$discriminator_value}) {
7176
# use 'mapping' to determine which schema to use.

t/discriminator.t

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ YAML
6363
instanceLocation => '',
6464
keywordLocation => '/discriminator',
6565
absoluteKeywordLocation => $doc_uri.'#/components/schemas/pet/discriminator',
66-
error => 'missing required discriminator property "petType"',
66+
error => 'missing required discriminator property "petType" and no defaultMapping present',
6767
},
6868
],
6969
},
@@ -171,6 +171,32 @@ YAML
171171
},
172172
'no mapping for petType found',
173173
);
174+
175+
176+
my $schema = $openapi->openapi_schema;
177+
$schema->{components}{schemas}{pet}{discriminator}{defaultMapping} = 'generic_pet';
178+
$schema->{components}{schemas}{pet}{anyOf}[2] = { '$ref' => '#/components/schemas/generic_pet' };
179+
$schema->{components}{schemas}{generic_pet} = {
180+
properties => {
181+
swims => { const => false },
182+
meow => { const => false },
183+
},
184+
};
185+
186+
$openapi = OpenAPI::Modern->new(openapi_uri => $doc_uri, openapi_schema => $schema);
187+
188+
cmp_result(
189+
$openapi->evaluator->evaluate(
190+
{
191+
# petType not provided - use defaultMapping
192+
meow => false,
193+
swims => false,
194+
},
195+
$doc_uri->clone->fragment('/components/schemas/pet'),
196+
)->TO_JSON,
197+
{ valid => true },
198+
'defaultMapping is used as a fallback',
199+
);
174200
};
175201

176202
subtest 'discriminator in a parent definition' => sub {

0 commit comments

Comments
 (0)