45

How to specify a property as null or a reference? discusses how to specify a property as null or a reference using jsonschema.

I'm looking to do the same thing with swagger.

To recap the answer to the above, with jsonschema, one could do this:

{
   "definitions": {
      "Foo": {
         # some complex object
      }
   },

   "type": "object",
   "properties": {
      "foo": {
         "oneOf": [
            {"$ref": "#/definitions/Foo"},
            {"type": "null"}
         ]
      }
   }
}

The key point to the answer was the use of oneOf.

The key points to my question:

  1. I have a complex object which I want to keep DRY so I put it in a definitions section for reuse throughout my swagger spec: values of other properties; response objects, etc.

  2. In various places in my spec a property may be a reference to such an object OR be null.

How do I specify this with Swagger which doesn't support oneOf or anyOf?

Note: some swagger implementations use x-nullable (or some-such) to specify a property value can be null, however, $ref replaces the object with what it references, so it would appear any use of x-nullable is ignored.

dpr
  • 10,591
  • 3
  • 41
  • 71
djpinne
  • 673
  • 1
  • 6
  • 9

3 Answers3

71

OpenAPI 3.1

Define the property as anyOf of the $ref and type: 'null'.

YAML version:

foo:
  anyOf:
    - type: 'null'   # Note the quotes around 'null'
    - $ref: '#/components/schemas/Foo'

JSON version:

"foo": {
    "anyOf": [
        { "type": "null" },
        { "$ref": "#/components/schemas/Foo" }
    ]
}

Why use anyOf and not oneOf? oneOf will fail validation if the referenced schema itself allows nulls, whereas anyOf will work.

OpenAPI 3.0

YAML version:

foo:
  nullable: true
  allOf:
  - $ref: '#/components/schemas/Foo'

JSON version:

"foo": {
    "nullable": true,
    "allOf": [
        { "$ref": "#/components/schemas/Foo" }
    ]
}

In OAS 3.0, wrapping $ref into allOf is needed to combine the $ref with other keywords - because $ref overwrites any sibling keywords. This is further discussed in the OpenAPI Specification repository: Reference objects don't combine well with “nullable”

Helen
  • 87,344
  • 17
  • 243
  • 314
  • I'm using swashbuckle 5x on .net core and I want to add `"nullable": true` to `"payload": { "$ref": "#/components/schemas/MyClass" }`, so it's `"payload": { "nullable": true, "$ref": "#/components/schemas/MyClass" }`, Does anyone know of a swashbuckle option to do this? – Adam Diament Jun 16 '20 at 15:19
  • 1
    @AdamDiament please [ask a new question](/questions/ask?tags=swashbuckle) – Helen Jun 16 '20 at 16:38
  • Thanks Helen, I've done that [here](https://stackoverflow.com/questions/62424769/using-swashbuckle-5-x-specify-nullable-true-on-a-generic-t-parameter-reference) – Adam Diament Jun 17 '20 at 08:34
  • This kind of expression has quite bad support with the libraries I use (python connexion/flask/OpenAPI 3.0). Referenced class code is generated twice, and when I submit invalid data in the referenced object, error message is messed up. This is disappointing – Kiruahxh Jan 31 '23 at 13:30
  • > Why use anyOf and not oneOf? oneOf will fail validation if the referenced schema itself allows nulls, whereas anyOf will work. If null is part of the referenced schema, then does this even make sense to do? – Ben Longo May 09 '23 at 16:26
  • @BenLongo if you know for sure that the referenced schema covers nulls, just `$ref` it directly. The `anyOf` approach is more like a fallback in case of complex composition/imheritance scenarios (i.e. if you don't know if the "parent" schemas are nullable) and to account for possible future schema updates (e.g. if the referenced schema is not nullable now, but becomes nullable after 6 months). – Helen May 09 '23 at 19:37
  • In my use case I went for oneOf with null because I'd consider it problematic to have a $ref to a type that also has null. – Ben Longo May 14 '23 at 02:52
7

For OpenAPI 3.0 for some reason using nullable: true followed by allOf didn't work for the OpenAPI interpreter I'm using. As a workaround I ended up defining a must-be-null ref called null_type that I can use in an anyOf construct.

Like so:

allOf:
  - anyOf:
      - $ref: "#/components/schemas/null_type"
      - $ref: "#/components/schemas/your_ref"
  - description: "optionally add other properties here..."

where:

schemas:
  null_type:
    title: "OpenAPI 3.0 null-type ref"
    description: "for adding nullability to a ref"
    enum: [null]

  your_ref:
    ...
Hans Bouwmeester
  • 1,121
  • 1
  • 17
  • 19
  • This is the only solution that made all the tools I'm using happy. – jpbochi Oct 26 '22 at 07:38
  • Confirmed for me as well (using in Postman OpenAPI 3.0.0 API definition) – boylec1986 Dec 16 '22 at 21:58
  • 1
    If you're using YAML for the specification the enum should be a YAML array (not a JSON array): ```yml schemas: null_type: title: "OpenAPI 3.0 null-type ref" description: "for adding nullability to a ref" enum: - null ``` – Axel GeNuS Jun 08 '23 at 09:58
5

Not easy to do that. Even almost impossible. Your options :

Wait

There is a very long discussion about this point, maybe one day it will be done...

Use vendors extensions

You can use vendors extensions like x-oneOf and x-anyOf. I have already taken this hard way: You must to upgrade all used 'swagger tools' to take into account these vendors extensions.

In my case, we needed 'only' to :

  • Develops our own Jax-RS parser with customized annotations in order to extract swagger API file from sources
  • Extends swagger-codegen to take into account these extensions to generate java code for our clients
  • Develops our own swagger-ui: to facilitate this work, we added a preprocessing step to convert our swagger schema with our extensions to a valid json schema. It's easier to find a module to represent json schemas than swagger schemas in javascript. By cons we gave up the idea to test the API with the 'try it' button.

It was a year ago, maybe now ...

Refactor your APIs

Many projects don't need anyOf and oneOf, why not us ?

Nelson G.
  • 5,145
  • 4
  • 43
  • 54
  • 2
    "Wait" - yes, apparently v3 is going to support oneOf, anyOf, but then we have to wait for the tooling and libraries that consume it. – djpinne Dec 07 '16 at 14:49
  • "Extensions" - I'm consuming my swagger in python (w/ bravado-core) which does not have the extensions you mention...bummer. – djpinne Dec 07 '16 at 14:58
  • "Refactor" - that would require dumbing down my api to fit the spec...I need the spec to fit my api! The only other thing I could think to do for the case of returning $ref-or-null *now* is **not** return the property which in the case of clients (javascript in my case) would treat "undefined" as "null". But I loathe that idea. – djpinne Dec 07 '16 at 14:59