thephpleague / openapi-psr7-validator

It validates PSR-7 messages (HTTP request/response) against OpenAPI specifications
MIT License
528 stars 93 forks source link

oneOf discriminator validation #229

Open leon0399 opened 2 months ago

leon0399 commented 2 months ago

Package version 0.22.0

Describe the bug Schema discriminator is not supported: https://swagger.io/docs/specification/data-models/inheritance-and-polymorphism/

To Reproduce

components:
  responses:
    sampleObjectResponse:
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/simpleObject'
              - $ref: '#/components/schemas/complexObject'
            discriminator:
              propertyName: objectType
  …
  schemas:
    simpleObject:
      type: object
      required:
        - objectType
      properties:
        objectType:
          type: string
      …
    complexObject:
      type: object
      required:
        - objectType
      properties:
        objectType:
          type: string
      …

Expected behaviour The validator must find a schema based on the discriminator

Additional context I've tried to make a fix myself, but does not know how to resolve the schema by ref from the validator: src/Schema/Keywords/OneOf.php:59

        // Validate against all schemas
        $schemaValidator = new SchemaValidator($this->validationDataType);
        $innerExceptions = [];
        $validSchemas    = [];

+        $discriminator = $this->parentSchema->discriminator;
+        if ($discriminator !== null) {
+            $resolved = $discriminator->mapping[$data[$discriminator->propertyName]];
+            // how do I get ref by Schema object? or how to get schema by ref?
+            // $oneOf = array_filter(
+            //     $oneOf,
+            //     static fn(CebeSchema $schema) => $schema->getRef() === $resolved
+            // );
+        }

        foreach ($oneOf as $schema) {
            try {
                $schemaValidator->validate($data, $schema, $this->dataBreadCrumb);
                $validSchemas[] = $schema;
            } catch (SchemaMismatch $e) {
                $innerExceptions[] = $e;
            }
        }
leon0399 commented 2 months ago

A temporary solution that even might be better in some way:

Instead of relying on discriminators based on property, I assigned this property a schema of enum with one entry:

components:
  responses:
    sampleObjectResponse:
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/simpleObject'
              - $ref: '#/components/schemas/complexObject'
-            discriminator:
-              propertyName: objectType
  …
  schemas:
    simpleObject:
      type: object
      required:
        - objectType
      properties:
        objectType:
          type: string
+          enum: 
+            - simpleObject
      …
    complexObject:
      type: object
      required:
        - objectType
      properties:
        objectType:
          type: string
+          enum: 
+            - complexObject
      …