xref: /aosp_15_r20/external/json-schema-validator/doc/openapi-discriminators.md (revision 78c4dd6aa35290980cdcd1623a7e337e8d021c7c)
1*78c4dd6aSAndroid Build Coastguard Worker[//]: # (Copyright 2021, Oracle and/or its affiliates.)
2*78c4dd6aSAndroid Build Coastguard Worker
3*78c4dd6aSAndroid Build Coastguard Worker## OpenAPI 3.x discriminator support
4*78c4dd6aSAndroid Build Coastguard Worker
5*78c4dd6aSAndroid Build Coastguard WorkerStarting with `1.0.51`, `json-schema-validator` partly supports the use of the [`discriminator`](https://github.com/OAI/OpenAPI-Specification/blob/7cc8f4c4e742a20687fa65ace54ed32fcb8c6df0/versions/3.1.0.md#discriminator-object) keyword.
6*78c4dd6aSAndroid Build Coastguard Worker
7*78c4dd6aSAndroid Build Coastguard WorkerNote that the use of the `discriminator` keyword does not affect the validation of `anyOf` or `oneOf`. The use of `discriminator` is not equivalent to having a `if`/`then` with the `discriminator` propertyName.
8*78c4dd6aSAndroid Build Coastguard Worker
9*78c4dd6aSAndroid Build Coastguard WorkerWhen a `discriminator` is used, the assertions generated by `anyOf` or `oneOf` will only be the assertions generated from the schema that the discriminator applies to. An assertion will be generated if a `discriminator` is used but there is no matching schema that maps to the value in the `propertyName`.
10*78c4dd6aSAndroid Build Coastguard Worker
11*78c4dd6aSAndroid Build Coastguard Worker## How to use
12*78c4dd6aSAndroid Build Coastguard Worker
13*78c4dd6aSAndroid Build Coastguard Worker1. Configure `SchemaValidatorsConfig` accordingly:
14*78c4dd6aSAndroid Build Coastguard Worker   ```java
15*78c4dd6aSAndroid Build Coastguard Worker   class Demo{
16*78c4dd6aSAndroid Build Coastguard Worker     void demo() {
17*78c4dd6aSAndroid Build Coastguard Worker        SchemaValidatorsConfig config = new SchemaValidatorsConfig();
18*78c4dd6aSAndroid Build Coastguard Worker        config.setOpenAPI3StyleDiscriminators(true); // defaults to false
19*78c4dd6aSAndroid Build Coastguard Worker     }
20*78c4dd6aSAndroid Build Coastguard Worker   }
21*78c4dd6aSAndroid Build Coastguard Worker   ```
22*78c4dd6aSAndroid Build Coastguard Worker2. Use the configured `SchemaValidatorsConfig` with the `JsonSchemaFactory` when creating the `JsonSchema`
23*78c4dd6aSAndroid Build Coastguard Worker   ```java
24*78c4dd6aSAndroid Build Coastguard Worker   class Demo{
25*78c4dd6aSAndroid Build Coastguard Worker     void demo() {
26*78c4dd6aSAndroid Build Coastguard Worker        SchemaValidatorsConfig config = new SchemaValidatorsConfig();
27*78c4dd6aSAndroid Build Coastguard Worker        config.setOpenAPI3StyleDiscriminators(true); // defaults to false
28*78c4dd6aSAndroid Build Coastguard Worker        JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012);
29*78c4dd6aSAndroid Build Coastguard Worker        JsonSchema schema = factory.getSchema(schemaURI, schemaJacksonJsonNode, config);
30*78c4dd6aSAndroid Build Coastguard Worker     }
31*78c4dd6aSAndroid Build Coastguard Worker   }
32*78c4dd6aSAndroid Build Coastguard Worker   ```
33*78c4dd6aSAndroid Build Coastguard Worker3. Ensure that the type field that you want to use as discriminator `propertyName` is required in your schema
34*78c4dd6aSAndroid Build Coastguard Worker
35*78c4dd6aSAndroid Build Coastguard Worker## Scope of Support
36*78c4dd6aSAndroid Build Coastguard Worker
37*78c4dd6aSAndroid Build Coastguard WorkerDiscriminators are unfortunately somewhat vague in their definition, especially in regard to JSON Schema validation. So, only
38*78c4dd6aSAndroid Build Coastguard Workerthose parts that are indisputable are considered at this moment.
39*78c4dd6aSAndroid Build Coastguard Worker
40*78c4dd6aSAndroid Build Coastguard Worker### Supported:
41*78c4dd6aSAndroid Build Coastguard Worker
42*78c4dd6aSAndroid Build Coastguard Worker* Polymorphism using `allOf` and `anyOf` with implicit and explicit `mapping`
43*78c4dd6aSAndroid Build Coastguard Worker* `discriminator` on base types and types derived
44*78c4dd6aSAndroid Build Coastguard Worker  thereof `A(with base discriminator) -> B(with optional additive discriminator) -> C(with optional additive discriminator)`
45*78c4dd6aSAndroid Build Coastguard Worker
46*78c4dd6aSAndroid Build Coastguard Worker### Not supported:
47*78c4dd6aSAndroid Build Coastguard Worker
48*78c4dd6aSAndroid Build Coastguard Worker* `propertyName` redefinition is prohibited on additive discriminators
49*78c4dd6aSAndroid Build Coastguard Worker* `mapping` key redefinition is also prohibited on additive discriminators
50*78c4dd6aSAndroid Build Coastguard Worker* the specification indicates that inline properties should be ignored.
51*78c4dd6aSAndroid Build Coastguard Worker  So, this example would respect `foo`
52*78c4dd6aSAndroid Build Coastguard Worker    ```yaml
53*78c4dd6aSAndroid Build Coastguard Worker    allOf:
54*78c4dd6aSAndroid Build Coastguard Worker        - $ref: otherSchema
55*78c4dd6aSAndroid Build Coastguard Worker        - type: object
56*78c4dd6aSAndroid Build Coastguard Worker          properties:
57*78c4dd6aSAndroid Build Coastguard Worker            foo:
58*78c4dd6aSAndroid Build Coastguard Worker            type: string
59*78c4dd6aSAndroid Build Coastguard Worker          required: ["foo"]
60*78c4dd6aSAndroid Build Coastguard Worker    ```
61*78c4dd6aSAndroid Build Coastguard Worker  while
62*78c4dd6aSAndroid Build Coastguard Worker    ```yaml
63*78c4dd6aSAndroid Build Coastguard Worker    properties:
64*78c4dd6aSAndroid Build Coastguard Worker      foo:
65*78c4dd6aSAndroid Build Coastguard Worker        type: string
66*78c4dd6aSAndroid Build Coastguard Worker    required: ["foo"]
67*78c4dd6aSAndroid Build Coastguard Worker    allOf:
68*78c4dd6aSAndroid Build Coastguard Worker      - $ref: otherSchema
69*78c4dd6aSAndroid Build Coastguard Worker    ```
70*78c4dd6aSAndroid Build Coastguard Worker  should ignore `foo`. **Ignoring `foo` in the second example is currently not implemented**
71*78c4dd6aSAndroid Build Coastguard Worker* You won't get a warning if your `discriminator` uses a field for `propertyName` that is not `required`
72*78c4dd6aSAndroid Build Coastguard Worker
73*78c4dd6aSAndroid Build Coastguard Worker## Schema Examples
74*78c4dd6aSAndroid Build Coastguard Worker
75*78c4dd6aSAndroid Build Coastguard WorkerMore examples in https://github.com/networknt/json-schema-validator/blob/master/src/test/resources/openapi3/discriminator.json
76*78c4dd6aSAndroid Build Coastguard Worker
77*78c4dd6aSAndroid Build Coastguard Worker### Base type and extended type (the `anyOf` forward references are required)
78*78c4dd6aSAndroid Build Coastguard Worker
79*78c4dd6aSAndroid Build Coastguard Worker#### Example:
80*78c4dd6aSAndroid Build Coastguard Worker
81*78c4dd6aSAndroid Build Coastguard Worker```json
82*78c4dd6aSAndroid Build Coastguard Worker{
83*78c4dd6aSAndroid Build Coastguard Worker    "anyOf": [
84*78c4dd6aSAndroid Build Coastguard Worker        {
85*78c4dd6aSAndroid Build Coastguard Worker            "$ref": "#/components/schemas/Room"
86*78c4dd6aSAndroid Build Coastguard Worker        },
87*78c4dd6aSAndroid Build Coastguard Worker        {
88*78c4dd6aSAndroid Build Coastguard Worker            "$ref": "#/components/schemas/BedRoom"
89*78c4dd6aSAndroid Build Coastguard Worker        }
90*78c4dd6aSAndroid Build Coastguard Worker    ],
91*78c4dd6aSAndroid Build Coastguard Worker    "components": {
92*78c4dd6aSAndroid Build Coastguard Worker        "schemas": {
93*78c4dd6aSAndroid Build Coastguard Worker            "Room": {
94*78c4dd6aSAndroid Build Coastguard Worker                "type": "object",
95*78c4dd6aSAndroid Build Coastguard Worker                "properties": {
96*78c4dd6aSAndroid Build Coastguard Worker                    "@type": {
97*78c4dd6aSAndroid Build Coastguard Worker                        "type": "string"
98*78c4dd6aSAndroid Build Coastguard Worker                    },
99*78c4dd6aSAndroid Build Coastguard Worker                    "floor": {
100*78c4dd6aSAndroid Build Coastguard Worker                        "type": "integer"
101*78c4dd6aSAndroid Build Coastguard Worker                    }
102*78c4dd6aSAndroid Build Coastguard Worker                },
103*78c4dd6aSAndroid Build Coastguard Worker                "required": [
104*78c4dd6aSAndroid Build Coastguard Worker                    "@type"
105*78c4dd6aSAndroid Build Coastguard Worker                ],
106*78c4dd6aSAndroid Build Coastguard Worker                "discriminator": {
107*78c4dd6aSAndroid Build Coastguard Worker                    "propertyName": "@type"
108*78c4dd6aSAndroid Build Coastguard Worker                }
109*78c4dd6aSAndroid Build Coastguard Worker            },
110*78c4dd6aSAndroid Build Coastguard Worker            "BedRoom": {
111*78c4dd6aSAndroid Build Coastguard Worker                "type": "object",
112*78c4dd6aSAndroid Build Coastguard Worker                "allOf": [
113*78c4dd6aSAndroid Build Coastguard Worker                    {
114*78c4dd6aSAndroid Build Coastguard Worker                        "$ref": "#/components/schemas/Room"
115*78c4dd6aSAndroid Build Coastguard Worker                    },
116*78c4dd6aSAndroid Build Coastguard Worker                    {
117*78c4dd6aSAndroid Build Coastguard Worker                        "type": "object",
118*78c4dd6aSAndroid Build Coastguard Worker                        "properties": {
119*78c4dd6aSAndroid Build Coastguard Worker                            "numberOfBeds": {
120*78c4dd6aSAndroid Build Coastguard Worker                                "type": "integer"
121*78c4dd6aSAndroid Build Coastguard Worker                            }
122*78c4dd6aSAndroid Build Coastguard Worker                        },
123*78c4dd6aSAndroid Build Coastguard Worker                        "required": [
124*78c4dd6aSAndroid Build Coastguard Worker                            "numberOfBeds"
125*78c4dd6aSAndroid Build Coastguard Worker                        ]
126*78c4dd6aSAndroid Build Coastguard Worker                    }
127*78c4dd6aSAndroid Build Coastguard Worker                ]
128*78c4dd6aSAndroid Build Coastguard Worker            }
129*78c4dd6aSAndroid Build Coastguard Worker        }
130*78c4dd6aSAndroid Build Coastguard Worker    }
131*78c4dd6aSAndroid Build Coastguard Worker}
132*78c4dd6aSAndroid Build Coastguard Worker```
133*78c4dd6aSAndroid Build Coastguard Worker
134*78c4dd6aSAndroid Build Coastguard Worker#### Here the default mapping key for `BedRoom` is overridden with `bed` from `Room`
135*78c4dd6aSAndroid Build Coastguard Worker
136*78c4dd6aSAndroid Build Coastguard Worker```json
137*78c4dd6aSAndroid Build Coastguard Worker{
138*78c4dd6aSAndroid Build Coastguard Worker    "anyOf": [
139*78c4dd6aSAndroid Build Coastguard Worker        {
140*78c4dd6aSAndroid Build Coastguard Worker            "$ref": "#/components/schemas/Room"
141*78c4dd6aSAndroid Build Coastguard Worker        },
142*78c4dd6aSAndroid Build Coastguard Worker        {
143*78c4dd6aSAndroid Build Coastguard Worker            "$ref": "#/components/schemas/BedRoom"
144*78c4dd6aSAndroid Build Coastguard Worker        }
145*78c4dd6aSAndroid Build Coastguard Worker    ],
146*78c4dd6aSAndroid Build Coastguard Worker    "components": {
147*78c4dd6aSAndroid Build Coastguard Worker        "schemas": {
148*78c4dd6aSAndroid Build Coastguard Worker            "Room": {
149*78c4dd6aSAndroid Build Coastguard Worker                "type": "object",
150*78c4dd6aSAndroid Build Coastguard Worker                "properties": {
151*78c4dd6aSAndroid Build Coastguard Worker                    "@type": {
152*78c4dd6aSAndroid Build Coastguard Worker                        "type": "string"
153*78c4dd6aSAndroid Build Coastguard Worker                    },
154*78c4dd6aSAndroid Build Coastguard Worker                    "floor": {
155*78c4dd6aSAndroid Build Coastguard Worker                        "type": "integer"
156*78c4dd6aSAndroid Build Coastguard Worker                    }
157*78c4dd6aSAndroid Build Coastguard Worker                },
158*78c4dd6aSAndroid Build Coastguard Worker                "required": [
159*78c4dd6aSAndroid Build Coastguard Worker                    "@type"
160*78c4dd6aSAndroid Build Coastguard Worker                ],
161*78c4dd6aSAndroid Build Coastguard Worker                "discriminator": {
162*78c4dd6aSAndroid Build Coastguard Worker                    "propertyName": "@type",
163*78c4dd6aSAndroid Build Coastguard Worker                    "mapping": {
164*78c4dd6aSAndroid Build Coastguard Worker                        "bed": "#/components/schemas/BedRoom"
165*78c4dd6aSAndroid Build Coastguard Worker                    }
166*78c4dd6aSAndroid Build Coastguard Worker                }
167*78c4dd6aSAndroid Build Coastguard Worker            },
168*78c4dd6aSAndroid Build Coastguard Worker            "BedRoom": {
169*78c4dd6aSAndroid Build Coastguard Worker                "type": "object",
170*78c4dd6aSAndroid Build Coastguard Worker                "allOf": [
171*78c4dd6aSAndroid Build Coastguard Worker                    {
172*78c4dd6aSAndroid Build Coastguard Worker                        "$ref": "#/components/schemas/Room"
173*78c4dd6aSAndroid Build Coastguard Worker                    },
174*78c4dd6aSAndroid Build Coastguard Worker                    {
175*78c4dd6aSAndroid Build Coastguard Worker                        "type": "object",
176*78c4dd6aSAndroid Build Coastguard Worker                        "properties": {
177*78c4dd6aSAndroid Build Coastguard Worker                            "numberOfBeds": {
178*78c4dd6aSAndroid Build Coastguard Worker                                "type": "integer"
179*78c4dd6aSAndroid Build Coastguard Worker                            }
180*78c4dd6aSAndroid Build Coastguard Worker                        },
181*78c4dd6aSAndroid Build Coastguard Worker                        "required": [
182*78c4dd6aSAndroid Build Coastguard Worker                            "numberOfBeds"
183*78c4dd6aSAndroid Build Coastguard Worker                        ]
184*78c4dd6aSAndroid Build Coastguard Worker                    }
185*78c4dd6aSAndroid Build Coastguard Worker                ]
186*78c4dd6aSAndroid Build Coastguard Worker            }
187*78c4dd6aSAndroid Build Coastguard Worker        }
188*78c4dd6aSAndroid Build Coastguard Worker    }
189*78c4dd6aSAndroid Build Coastguard Worker}
190*78c4dd6aSAndroid Build Coastguard Worker```
191