1
1
// Copyright (c) Microsoft Corporation. All rights reserved.
2
2
// Licensed under the MIT license.
3
3
4
- using Microsoft . OpenApi . Any ;
5
4
using Microsoft . OpenApi . Models ;
6
5
using Microsoft . OpenApi . Properties ;
7
6
using System . Collections . Generic ;
@@ -11,7 +10,6 @@ namespace Microsoft.OpenApi.Validations.Rules
11
10
/// <summary>
12
11
/// The validation rules for <see cref="OpenApiSchema"/>.
13
12
/// </summary>
14
-
15
13
[ OpenApiRule ]
16
14
public static class OpenApiSchemaRules
17
15
{
@@ -70,50 +68,77 @@ public static class OpenApiSchemaRules
70
68
71
69
if ( schema . Reference != null && schema . Discriminator != null )
72
70
{
73
- if ( ! schema . Required . Contains ( schema . Discriminator ? . PropertyName ) )
71
+ var discriminator = schema . Discriminator ? . PropertyName ;
72
+ var schemaReferenceId = schema . Reference . Id ;
73
+
74
+ if ( ! ValidateChildSchemaAgainstDiscriminator ( schema , discriminator , schemaReferenceId , context ) )
74
75
{
75
- // check schema.OneOf, schema.AnyOf or schema.AllOf
76
- if ( schema . OneOf . Count != 0 )
77
- {
78
- ValidateDiscriminatorAgainstChildSchema ( schema . OneOf , schema , context ) ;
79
- }
80
- else if ( schema . AnyOf . Count != 0 )
81
- {
82
- ValidateDiscriminatorAgainstChildSchema ( schema . AnyOf , schema , context ) ;
83
- }
84
- else if ( schema . AllOf . Count != 0 )
85
- {
86
- ValidateDiscriminatorAgainstChildSchema ( schema . AllOf , schema , context ) ;
87
- }
88
- else
89
- {
90
- context . CreateError ( nameof ( ValidateSchemaDiscriminator ) ,
91
- string . Format ( SRResource . Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator ,
92
- schema . Reference . Id , schema . Discriminator . PropertyName ) ) ;
93
- }
76
+ context . CreateError ( nameof ( ValidateSchemaDiscriminator ) ,
77
+ string . Format ( SRResource . Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator ,
78
+ schemaReferenceId , discriminator ) ) ;
94
79
}
95
80
}
96
-
81
+
97
82
context . Exit ( ) ;
98
83
} ) ;
99
84
100
85
/// <summary>
101
86
/// Validates the property name in the discriminator against the ones present in the children schema
102
87
/// </summary>
103
- /// <param name="childSchema">The derived schema.</param>
104
88
/// <param name="schema">The parent schema.</param>
89
+ /// <param name="discriminator">Adds support for polymorphism. The discriminator is an object name that is used to differentiate
90
+ /// between other schemas which may satisfy the payload description.</param>
91
+ /// <param name="schemaReferenceId"></param>
105
92
/// <param name="context">A validation context.</param>
106
- public static void ValidateDiscriminatorAgainstChildSchema ( IList < OpenApiSchema > childSchema , OpenApiSchema schema , IValidationContext context )
93
+ public static bool ValidateChildSchemaAgainstDiscriminator ( OpenApiSchema schema , string discriminator , string schemaReferenceId , IValidationContext context )
107
94
{
108
- foreach ( var schemaItem in childSchema )
95
+ bool containsDiscriminator = false ;
96
+
97
+ if ( ! schema . Required . Contains ( discriminator ) )
109
98
{
110
- if ( ! schemaItem . Properties . Keys . Contains ( schema . Discriminator ? . PropertyName ) )
99
+ // recursively check nested schema.OneOf, schema.AnyOf or schema.AllOf and their required fields for the discriminator
100
+ if ( schema . OneOf . Count != 0 )
101
+ {
102
+ return TraverseSchemaElements ( discriminator , schema . OneOf , schemaReferenceId , context , containsDiscriminator ) ;
103
+ }
104
+ if ( schema . AnyOf . Count != 0 )
111
105
{
112
- context . CreateError ( nameof ( ValidateSchemaDiscriminator ) ,
113
- string . Format ( SRResource . Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator ,
114
- schema . Reference . Id , schema . Discriminator . PropertyName ) ) ;
106
+ return TraverseSchemaElements ( discriminator , schema . AnyOf , schemaReferenceId , context , containsDiscriminator ) ;
115
107
}
116
- }
108
+ if ( schema . AllOf . Count != 0 )
109
+ {
110
+ return TraverseSchemaElements ( discriminator , schema . AllOf , schemaReferenceId , context , containsDiscriminator ) ;
111
+ }
112
+ }
113
+
114
+ return containsDiscriminator ;
115
+ }
116
+
117
+ /// <summary>
118
+ /// Traverses the schema elements and checks whether the schema contains the discriminator.
119
+ /// </summary>
120
+ /// <param name="discriminator">Adds support for polymorphism. The discriminator is an object name that is used to differentiate
121
+ /// between other schemas which may satisfy the payload description.</param>
122
+ /// <param name="childSchema">The child schema.</param>
123
+ /// <param name="schemaReferenceId"> The schema reference Id.</param>
124
+ /// <param name="context"> A validation context.</param>
125
+ /// <param name="containsDiscriminator">Tracks whether the discriminator is present.</param>
126
+ /// <returns></returns>
127
+ public static bool TraverseSchemaElements ( string discriminator , IList < OpenApiSchema > childSchema , string schemaReferenceId , IValidationContext context , bool containsDiscriminator )
128
+ {
129
+ foreach ( var childItem in childSchema )
130
+ {
131
+ if ( ! childItem . Properties . ContainsKey ( discriminator ) && ! childItem . Required . Contains ( discriminator ) )
132
+ {
133
+ return ValidateChildSchemaAgainstDiscriminator ( childItem , discriminator , schemaReferenceId , context ) ;
134
+ }
135
+ else
136
+ {
137
+ return containsDiscriminator = true ;
138
+ }
139
+ }
140
+
141
+ return containsDiscriminator ;
117
142
}
118
143
}
119
144
}
0 commit comments