OAI/OpenAPI-Specification

Clarification on nullable properties, OpenAPI 3.1

Closed this issue ยท 10 comments

OpenAPI 3.1 introduces support for jsonschema's 'null' type, however, the OpenAPI 3.1 spec makes no mention of this leading to confusion on how to specify null objects. I've seen two common ways to represent nullable properties in the wild.

Option A

openapi: '3.1.0'
components:
  schemas:
    Foo:
      type: 'object'
      properties:
        bar:
          type: ['string', 'null']
          format: 'uri'
          maxLength: 255

Option B

openapi: '3.1.0'
components:
  schemas:
    Foo:
      type: 'object'
      properties:
        bar:
          oneOf:
            - type: 'string'
              format: 'uri'
              maxLength: 255
            - type: 'null'

Option A is more succinct but arguably incorrect, since format and maxLength are not applicable for the null type. It is rather common though. For example, GitHub's OpenAPI 3.1 specs does this:

---
openapi: 3.1.0
# ...
paths:
  # ...
  "/authorizations":
    # ...
    post:
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                scopes:
                  description: A list of scopes that this authorization is in.
                  type:
                  - array
                  - 'null'
                  items:
                    type: string
                  examples:
                  - public_repo
                  - user
                # ...

Option B is longer but appears (to me) to be technically correct.

Could we clarify which of these is correct? I assume we'd need a future MINOR or PATCH version if we wanted to (correctly?) forbid option A?

I'm aware this might be an issue with jsonschema itself too. If it makes sense for me to do so, I could close this issue and report a new one against jsonschema.

Hmm, I actually think JSONSchema allows for option A. From the spec:

7.6.1. Assertions and Instance Primitive Types

Most assertions only constrain values within a certain primitive type. When the type of the instance is not of the type targeted by the keyword, the instance is considered to conform to the assertion.
For example, the "maxLength" keyword from the companion validation vocabulary [json-schema-validation]: will only restrict certain strings (that are too long) from being valid. If the instance is a number, boolean, null, array, or object, then it is valid against this assertion. This behavior allows keywords to be used more easily with instances that can be of multiple primitive types. The companion validation vocabulary also includes a "type" keyword which can independently restrict the instance to one or more primitive types. This allows for a concise expression of use cases such as a function that might return either a string of a certain length or a null value:

{
    "type": ["string", "null"],
    "maxLength": 255
}

If "maxLength" also restricted the instance type to be a string, then this would be substantially more cumbersome to express because the example as written would not actually allow null values. Each keyword is evaluated separately unless explicitly specified otherwise, so if "maxLength" restricted the instance to strings, then including "null" in "type" would not have any useful effect.

Assuming I've understood this correctly, both are valid options and it's a case of determining whether clarity trumps succinctness or not. I, for one, would love to see this detailed in the spec itself so I'll leave this open as a kind of docs RFE.

Both options are valid. Sometimes there are multiple ways to define the same thing with JSON Schema.

Option A is more succinct but arguably incorrect, since format and maxLength are not applicable for the null type.

Type-specific keywords (such as string-specific maxLength or number-specific maximum) don't apply when the instance being validated is of another data type. In case of Option A, the format and maxLength constraints only have effect when the value of bar is a string and are ignored when bar is null.

@hkosova is correct.

Perhaps an example using "type": ["integer", "null"] or something similar can be added in the Schema Object section in 3.1.1?

We do not want to get into things like keyword applicability to types as that is a JSON Schema concern and OAS should not duplicate JSON Schema stuff.

It's been nearly a year since multiple folks answered with "both are valid" and no further questions, so I'm closing this as resolved.

According to the spec, neither are valid.

@XedinUnknown that doc is about OpenAPI 3.0, whereas this discussion is about 3.1.

@XedinUnknown that doc is about OpenAPI 3.0, whereas this discussion is about 3.1.

https://spec.openapis.org/oas/latest.html#data-types

@hkosova even for OpenAPI 3.1 spec doesn't mention that data types should support null. may i know how the nullable field is supported now actually?

Need to know this information as well to make structs into pointer types when generating off openapi 3.1.0 yaml files

The answer is the same as it always has been: That both of the options written out by the OP are supported in OAS 3.1. For information about which form your tool prefers, please contact your tooling vendor.