1[ 2 { 3 "description": "discriminator with anyOf/allOf", 4 "schema": { 5 "anyOf": [ 6 { 7 "$ref": "#/components/schemas/Room" 8 }, 9 { 10 "$ref": "#/components/schemas/BedRoom" 11 }, 12 { 13 "$ref": "#/components/schemas/KidsBedRoom" 14 }, 15 { 16 "$ref": "#/components/schemas/Kitchen" 17 }, 18 { 19 "$ref": "#/components/schemas/GuestRoom" 20 } 21 ], 22 "components": { 23 "schemas": { 24 "Room": { 25 "type": "object", 26 "properties": { 27 "@type": { 28 "type": "string" 29 }, 30 "floor": { 31 "type": "integer" 32 } 33 }, 34 "required": [ 35 "@type" 36 ], 37 "discriminator": { 38 "propertyName": "@type", 39 "mapping": { 40 "bed": "#/components/schemas/BedRoom" 41 } 42 } 43 }, 44 "BedRoom": { 45 "type": "object", 46 "allOf": [ 47 { 48 "$ref": "#/components/schemas/Room" 49 }, 50 { 51 "type": "object", 52 "properties": { 53 "numberOfBeds": { 54 "type": "integer" 55 } 56 }, 57 "required": [ 58 "numberOfBeds" 59 ] 60 } 61 ], 62 "discriminator": { 63 "mapping": { 64 "guest": "#/components/schemas/GuestRoom" 65 } 66 } 67 }, 68 "KidsBedRoom": { 69 "type": "object", 70 "allOf": [ 71 { 72 "$ref": "#/components/schemas/BedRoom" 73 }, 74 { 75 "type": "object", 76 "properties": { 77 "isTidy": { 78 "type": "boolean" 79 } 80 }, 81 "required": [ 82 "isTidy" 83 ] 84 } 85 ] 86 }, 87 "GuestRoom": { 88 "type": "object", 89 "allOf": [ 90 { 91 "$ref": "#/components/schemas/BedRoom" 92 }, 93 { 94 "type": "object", 95 "properties": { 96 "guest": { 97 "type": "string" 98 } 99 }, 100 "required": [ 101 "guest" 102 ] 103 } 104 ] 105 }, 106 "Kitchen": { 107 "type": "object", 108 "allOf": [ 109 { 110 "$ref": "#/components/schemas/Room" 111 }, 112 { 113 "type": "object", 114 "properties": { 115 "hasMicrowaveOven": { 116 "type": "boolean" 117 }, 118 "equipment": { 119 "type": "array", 120 "items": { 121 "anyOf": [ 122 { 123 "$ref": "#/components/schemas/Pot" 124 }, 125 { 126 "$ref": "#/components/schemas/Blender" 127 } 128 ] 129 } 130 } 131 }, 132 "required": [ 133 "hasMicrowaveOven" 134 ] 135 } 136 ] 137 }, 138 "KitchenEquipment": { 139 "type": "object", 140 "properties": { 141 "@type": { 142 "type": "string" 143 } 144 }, 145 "required": [ 146 "@type" 147 ], 148 "discriminator": { 149 "propertyName": "@type" 150 } 151 }, 152 "Pot": { 153 "allOf": [ 154 { 155 "$ref": "#/components/schemas/KitchenEquipment" 156 }, 157 { 158 "type": "object", 159 "properties": { 160 "capacity": { 161 "type": "integer" 162 } 163 }, 164 "required": [ 165 "capacity" 166 ] 167 } 168 ] 169 }, 170 "Blender": { 171 "allOf": [ 172 { 173 "$ref": "#/components/schemas/KitchenEquipment" 174 }, 175 { 176 "type": "object", 177 "properties": { 178 "maxSpeed": { 179 "type": "integer" 180 } 181 }, 182 "required": [ 183 "maxSpeed" 184 ] 185 } 186 ] 187 } 188 } 189 } 190 }, 191 "tests": [ 192 { 193 "description": "mapping to base type", 194 "data": { 195 "@type": "Room" 196 }, 197 "valid": true 198 }, 199 { 200 "description": "mapped to Bedroom", 201 "data": { 202 "@type": "bed", 203 "numberOfBeds": 2 204 }, 205 "valid": true 206 }, 207 { 208 "description": "mapped to Kitchen", 209 "data": { 210 "@type": "Kitchen", 211 "hasMicrowaveOven": true, 212 "equipment": [ 213 { 214 "@type": "Blender", 215 "maxSpeed": 1500 216 }, 217 { 218 "@type": "Pot", 219 "capacity": 5 220 } 221 ] 222 }, 223 "valid": true 224 }, 225 { 226 "description": "mapped to KidsBedRoom", 227 "data": { 228 "@type": "KidsBedRoom", 229 "numberOfBeds": 1, 230 "isTidy": false 231 }, 232 "valid": true 233 }, 234 { 235 "description": "mapped to Bedroom with missing number of beds", 236 "data": { 237 "@type": "bed" 238 }, 239 "valid": false 240 }, 241 { 242 "description": "mapped to KidsBedroom with missing number of beds", 243 "data": { 244 "@type": "KidsBedRoom", 245 "isTidy": true 246 }, 247 "valid": false 248 }, 249 { 250 "description": "mapped to KidsBedroom with missing tidiness", 251 "data": { 252 "@type": "KidsBedRoom", 253 "numberOfBeds": 1 254 }, 255 "valid": false 256 }, 257 { 258 "description": "mapped to GuestRoom with correct @type (mapping override on BedRoom)", 259 "data": { 260 "@type": "guest", 261 "numberOfBeds": 9, 262 "guest": "Steve" 263 }, 264 "valid": true 265 }, 266 { 267 "description": "mapped to GuestRoom with incorrect @type (mapping override on BedRoom)", 268 "data": { 269 "@type": "GuestRoom", 270 "guest": "Steve" 271 }, 272 "valid": false 273 }, 274 { 275 "description": "mapped to invalid Room", 276 "data": { 277 "@type": "Bathroom" 278 }, 279 "valid": false 280 }, 281 { 282 "description": "discriminator missing - falling back to default validation with failure as @type is mandatory", 283 "data": { 284 }, 285 "valid": false 286 } 287 ] 288 }, 289 { 290 "description": "absent discriminator value as discriminator marked as non-mandatory (which is against OAS3 recommendations)", 291 "schema": { 292 "anyOf": [ 293 { 294 "$ref": "#/components/schemas/Room" 295 }, 296 { 297 "$ref": "#/components/schemas/BedRoom" 298 } 299 ], 300 "components": { 301 "schemas": { 302 "Room": { 303 "type": "object", 304 "properties": { 305 "intOrStringType": { 306 "type": "integer" 307 } 308 }, 309 "discriminator": { 310 "propertyName": "@type", 311 "mapping": { 312 "bed": "#/components/schemas/BedRoom" 313 } 314 } 315 }, 316 "BedRoom": { 317 "type": "object", 318 "allOf": [ 319 { 320 "$ref": "#/components/schemas/Room" 321 }, 322 { 323 "type": "object", 324 "properties": { 325 "intOrStringType": { 326 "type": "string" 327 } 328 } 329 } 330 ] 331 } 332 } 333 } 334 }, 335 "tests": [ 336 { 337 "description": "discriminator missing - falling back to default anyOf behavior", 338 "data": { 339 "intOrStringType": 4 340 }, 341 "valid": true 342 }, 343 { 344 "description": "discriminator missing - with constructed schema conflict", 345 "data": { 346 "intOrStringType": "cannot match due to allOf" 347 }, 348 "valid": false 349 } 350 ] 351 }, 352 { 353 "description": "Issue #398 - $ref pointing to base type with discriminator and w/o anyOf", 354 "schema": { 355 "$ref": "#/components/schemas/Room", 356 "components": { 357 "schemas": { 358 "Room": { 359 "type": "object", 360 "properties": { 361 "@type": { 362 "type": "string" 363 }, 364 "floor": { 365 "type": "integer" 366 }, 367 "nextRoom": { 368 "anyOf": [ 369 {"$ref":"#/components/schemas/Room" }, 370 {"$ref":"#/components/schemas/BedRoom" } 371 ] 372 } 373 }, 374 "required": [ 375 "@type" 376 ], 377 "discriminator": { 378 "propertyName": "@type" 379 } 380 }, 381 "BedRoom": { 382 "type": "object", 383 "allOf": [ 384 { 385 "$ref": "#/components/schemas/Room" 386 }, 387 { 388 "type": "object", 389 "properties": { 390 "numberOfBeds": { 391 "type": "integer" 392 } 393 }, 394 "required": [ 395 "numberOfBeds" 396 ] 397 } 398 ] 399 } 400 } 401 } 402 }, 403 "tests": [ 404 { 405 "description": "$ref without anyOf and therefore no discriminator context", 406 "data": { 407 "@type": "Room" 408 }, 409 "valid": true 410 }, 411 { 412 "description": "schema with discriminator and recursion with invalid BedRoom", 413 "data": { 414 "@type": "can be ignored - discriminator not in use on root schema", 415 "numberOfBeds": 42, 416 "nextRoom": { 417 "@type": "BedRoom", 418 "floor": 1 419 } 420 }, 421 "valid": false 422 } 423 ] 424 }, 425 { 426 "description": "Issue #398 - $ref pointing to extended type with discriminator and w/o anyOf", 427 "schema": { 428 "$ref": "#/components/schemas/BedRoom", 429 "components": { 430 "schemas": { 431 "Room": { 432 "type": "object", 433 "properties": { 434 "@type": { 435 "type": "string" 436 }, 437 "floor": { 438 "type": "integer" 439 }, 440 "nextRoom": { 441 "anyOf": [ 442 {"$ref": "#/components/schemas/Room"}, 443 {"$ref": "#/components/schemas/BedRoom"} 444 ] 445 } 446 }, 447 "required": [ 448 "@type" 449 ], 450 "discriminator": { 451 "propertyName": "@type" 452 } 453 }, 454 "BedRoom": { 455 "type": "object", 456 "allOf": [ 457 { 458 "$ref": "#/components/schemas/Room" 459 }, 460 { 461 "type": "object", 462 "properties": { 463 "numberOfBeds": { 464 "type": "integer" 465 }, 466 "nextRoom": { 467 "anyOf": [ 468 {"$ref": "#/components/schemas/Room"}, 469 {"$ref": "#/components/schemas/BedRoom"} 470 ] 471 } 472 }, 473 "required": [ 474 "numberOfBeds" 475 ] 476 } 477 ] 478 } 479 } 480 } 481 }, 482 "tests": [ 483 { 484 "description": "$ref without anyOf and therefore no discriminator context", 485 "data": { 486 "@type": "can be ignored - discriminator not in use on root schema", 487 "numberOfBeds": 42, 488 "nextRoom": { 489 "@type": "Room", 490 "floor": 3 491 } 492 }, 493 "valid": true 494 }, 495 { 496 "description": "schema with discriminator and recursion with valid BedRoom", 497 "data": { 498 "@type": "can be ignored - discriminator not in use on root schema", 499 "numberOfBeds": 42, 500 "nextRoom": { 501 "@type": "BedRoom", 502 "floor": 1, 503 "numberOfBeds": 12345 504 } 505 }, 506 "valid": true 507 }, 508 { 509 "description": "schema with discriminator and recursion with invalid BedRoom", 510 "data": { 511 "@type": "can be ignored - discriminator not in use on root schema", 512 "numberOfBeds": 42, 513 "nextRoom": { 514 "@type": "BedRoom", 515 "floor": 1 516 } 517 }, 518 "valid": false 519 } 520 ] 521 }, 522 { 523 "description": "Issue #398 - invalid discriminator specification has to lead to failed validation", 524 "schema": { 525 "anyOf": [ 526 {"$ref": "#/components/schemas/Room"}, 527 {"$ref": "#/components/schemas/BedRoom"} 528 ], 529 "components": { 530 "schemas": { 531 "Room": { 532 "type": "object", 533 "properties": { 534 "@type": { 535 "type": "string" 536 }, 537 "floor": { 538 "type": "integer" 539 }, 540 "nextRoom": { 541 "anyOf": [ 542 {"$ref": "#/components/schemas/Room"}, 543 {"$ref": "#/components/schemas/BedRoom"} 544 ] 545 } 546 }, 547 "required": [ 548 "@type" 549 ], 550 "discriminator": { 551 "propertyName": "@type" 552 } 553 }, 554 "BedRoom": { 555 "type": "object", 556 "allOf": [ 557 { 558 "$ref": "#/components/schemas/Room" 559 }, 560 { 561 "type": "object", 562 "properties": { 563 "numberOfBeds": { 564 "type": "integer" 565 }, 566 "nextRoom": { 567 "anyOf": [ 568 {"$ref": "#/components/schemas/Room"}, 569 {"$ref": "#/components/schemas/BedRoom"} 570 ] 571 } 572 }, 573 "required": [ 574 "numberOfBeds" 575 ] 576 } 577 ] 578 } 579 } 580 } 581 }, 582 "tests": [ 583 { 584 "description": "$ref without anyOf and therefore no discriminator context", 585 "data": { 586 "@type": "illegal discriminator property value" 587 }, 588 "valid": false 589 } 590 ] 591 } 592] 593