Skip to content

nullable oneOf/anyOf value rejected #146

@AlbinoDrought

Description

@AlbinoDrought
<?php

declare(strict_types=1);

namespace League\OpenAPIValidation\Tests\FromCommunity;

use GuzzleHttp\Psr7\Response;
use League\OpenAPIValidation\PSR7\OperationAddress;
use League\OpenAPIValidation\PSR7\ValidatorBuilder;
use League\OpenAPIValidation\Tests\PSR7\BaseValidatorTest;

final class IssueWithNullableMergeTest extends BaseValidatorTest
{
    public function testNullableMergeOneOf(): void
    {
        $yaml = /** @lang yaml */
               <<<'YAML'
openapi: 3.0.0
paths:
  /api/nullable-merge:
    get:
      description: 'Test'
      responses:
        '200':
          description: 'ok'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Thing"
components:
  schemas:
    FooResult:
      type: object
      properties:
        id:
          type: integer
        foo:
          type: string
    BarResult:
      type: object
      nullable: true
      properties:
        id:
          type: integer
        bar:
          type: string
    Thing:
      type: object
      properties:
        result:
          oneOf:
            - $ref: "#/components/schemas/FooResult"
            - $ref: "#/components/schemas/BarResult"
YAML;

        $validator = (new ValidatorBuilder())->fromYaml($yaml)->getResponseValidator();
        $operation = new OperationAddress('/api/nullable-merge', 'get');

        $responseContent = /** @lang JSON */
            '
    {
      "result": null
    }
';

        $response = new Response(200, ['Content-Type' => 'application/json'], $responseContent);

        $validator->validate($operation, $response);

        $this->addToAssertionCount(1);
    }
}

FooResult is not nullable. BarResult is nullable. Thing.result can be one of FooResult or BarResult, so my expectation is that null should be an acceptable value. Validation fails with:

There was 1 error:

1) League\OpenAPIValidation\Tests\FromCommunity\IssueWithNullableMergeTest::testNullableMergeOneOf
League\OpenAPIValidation\PSR7\Exception\Validation\InvalidBody: Body does not match schema for content-type "application/json" for Response [get /api/nullable-merge 200]

/openapi-psr7-validator/src/PSR7/Exception/Validation/AddressValidationFailed.php:28
/openapi-psr7-validator/src/PSR7/Exception/Validation/InvalidBody.php:19
/openapi-psr7-validator/src/PSR7/Validators/BodyValidator/UnipartValidator.php:60
/openapi-psr7-validator/src/PSR7/Validators/BodyValidator/BodyValidator.php:73
/openapi-psr7-validator/src/PSR7/Validators/ValidatorChain.php:25
/openapi-psr7-validator/src/PSR7/ResponseValidator.php:42
/openapi-psr7-validator/tests/FromCommunity/IssueWithNullableMergeTest.php:68

Caused by
League\OpenAPIValidation\Schema\Exception\KeywordMismatch: Keyword validation failed: Value cannot be null

/openapi-psr7-validator/src/Schema/Exception/KeywordMismatch.php:22
/openapi-psr7-validator/src/Schema/Keywords/Nullable.php:21
/openapi-psr7-validator/src/Schema/SchemaValidator.php:60
/openapi-psr7-validator/src/Schema/Keywords/Properties.php:85
/openapi-psr7-validator/src/Schema/SchemaValidator.php:139
/openapi-psr7-validator/src/PSR7/Validators/BodyValidator/UnipartValidator.php:58
/openapi-psr7-validator/src/PSR7/Validators/BodyValidator/BodyValidator.php:73
/openapi-psr7-validator/src/PSR7/Validators/ValidatorChain.php:25
/openapi-psr7-validator/src/PSR7/ResponseValidator.php:42
/openapi-psr7-validator/tests/FromCommunity/IssueWithNullableMergeTest.php:68

This same issue happens if oneOf: in the above snippet is replaced with anyOf:.

Swagger UI shows the nullable: true constraint as expected:

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions