express-openapi-validator icon indicating copy to clipboard operation
express-openapi-validator copied to clipboard

Nullable object property fails to validate `null`

Open bluenote10 opened this issue 4 years ago • 6 comments

Describe the bug

I'm working with an API that requires differentiating between properties that are T | undefined or T | null.

In OpenAPI 3.0, T | null properties seem to be modelled like:

schemas:
  TestObject:
    type: object
    properties:
      otherObjectMaybeNullA:
        $ref: "#/components/schemas/OtherObject"
        nullable: true
      otherObjectMaybeNullB:
        anyOf:
        - $ref: "#/components/schemas/OtherObject"
        nullable: true
    required:
    - otherObjectMaybeNullA
    - otherObjectMaybeNullB

  OtherObject:
    type: object

In both cases the validator does not accept null as a valid value. Errors are 'should be object' and 'should match some schema in anyOf'.

To Reproduce

Validate above against { otherObjectMaybeNullA: null, otherObjectMaybeNullB: null }.

Actual behavior

Validation fails.

Expected behavior

Validation should pass.

Examples and context

See above.

bluenote10 avatar Mar 26 '20 13:03 bluenote10

@bluenote10 Using the first form e.g. nullableObjectMaybeNullA, nullable would be ignored given its a sibling to the $ref, hence that won't work.

The second form is, well, complicated, see https://github.com/OAI/OpenAPI-Specification/issues/1368

That being said, I did some playing around. The following will pass validation: Note: moving nullable: true to OtherObject

    TestObject:
      type: object
      properties:
        nullableObject:
          $ref: '#/components/schemas/OtherObject'
      required:
        - nullableObject

    OtherObject:
      type: object
      nullable: true

There is some good news. It looks like when OAS v3.1.0 is released, nulllable will be deprecated in favor of a null type. This should make things much more straightforward. 3.1.0 (as of now) has not been released/finalized.

In the meantime, the above example works. Hopefully, it fits your use case

cdimascio avatar Apr 01 '20 19:04 cdimascio

Thanks for looking into this! Yes, that seems to be a bit of a mess in OpenAPI 3.0. My interpretation of Clarify Semantics of nullable in OpenAPI 3.0 was that at least the second form is valid. Other indicators:

  • The online swagger validator shows the second form as valid, and actually outputs a warning for the first case to change it into the second form.
  • When I raised the same issue for swagger-typescript-api support for both forms was added.

Looks like I'm a bit stuck in terms of work-arounds because:

  • I can't migrate to OAS 3.1.0 yet, because other libraries depending on the API definitions don't support it yet.
  • Regarding moving nullable: true to OtherObject. This other object is intended to appear in non-nullable form in other places. I naively thought I can wrap it into OtherObjectNullable, but that again results in having to combine $ref with nullable: true. This maybe leaves duplicating all fields in OtherObject and OtherObjectNullable as an option, which calls for trouble when changing the fields and forgetting to sync them.

bluenote10 avatar Apr 02 '20 11:04 bluenote10

@cdimascio

v4.5.0

Nullable objects can't be validated if properties are defined in the openapi.json.

This one works (nestedObject can be null or object)

ObjectOne:
  type: object
  additionalProperties: false
  required: 
    - id
    - username
  properties:
    id:
      type: string
      format: uuid
      readOnly: true
    username:
      type: string
    nestedObject:
      nullable: true
      type: object

This one can't be null (error: .response.ObjectOne.nestedObject should be object)

ObjectOne:
  type: object
  additionalProperties: false
  required: 
    - id
    - username
  properties:
    id:
      type: string
      format: uuid
      readOnly: true
    username:
      type: string
    nestedObject:
      nullable: true
      type: object
      required:
        - name
        - id
      properties:
      	id:
          type: string
          format: uuid
        name:
          type: string

dotMortis avatar Nov 10 '20 11:11 dotMortis

@dotMortis Both of your examples produce the same error for me. I'm using v4.12.9 and I cannot get a nested property to be nullable no matter what I do. Though in my case it's nested twice: ObjectOne.NestedObject.NullableProperty

BlueSialia avatar Mar 14 '22 19:03 BlueSialia

                "data": {
                  "oneOf": [
                    {
                      "$ref": "#/definitions/348",
                      "x-apifox-overrides": {}
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "x-apifox-overrides": {},
                  "$ref": "#/components/schemas/ChatClientSettings"
                }
              },

can't handle this oneof ?

Akimyou avatar Jun 21 '22 11:06 Akimyou

Nullable objects can't be validated if properties are defined in the openapi.json.

Why can't it validate nullable objects with properties defined??

tobq avatar Jul 06 '22 14:07 tobq