swagger-ui
swagger-ui copied to clipboard
OpenAPI 3.1.0 support: OpenAPI 3.1 type: […, "null"] incomplete support in parameters
Q&A (please complete the following information)
- OS: Ubuntu
- Browser: Firefox
- Version: 114.0.2
- Method of installation: apt
- Swagger-UI version: https://editor-next.swagger.io/
- Swagger/OpenAPI version: 3.1
Content & configuration
Example Swagger/OpenAPI definition: https://gist.github.com/commonism/7adcb666278f4070b8f7aabd456faa43
openapi: 3.1.0
info:
title: ''
version: 0.0.0
servers:
- url: http://127.0.0.1/api
security:
- {}
paths:
/{path}:
parameters:
- $ref: "#/components/parameters/path"
- $ref: '#/components/parameters/cookie'
post:
operationId: post
requestBody:
description: "!"
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Any'
responses:
'200':
description: "!"
content:
application/json:
schema:
$ref: "#/components/schemas/Any"
callbacks:
onData:
'{$request.query.callbackUrl}/data':
post:
requestBody:
description: "!"
content:
application/json:
schema:
$ref: "#/components/schemas/Any"
responses:
'200':
description: "!"
content:
application/json:
schema:
$ref: "#/components/schemas/Any"
get:
operationId: get
parameters:
- $ref: "#/components/parameters/query"
- $ref: "#/components/parameters/header"
responses: &resp
'200':
description: "!"
content:
application/json:
schema:
$ref: '#/components/schemas/Any'
headers:
head:
$ref: "#/components/headers/header"
components:
schemas:
Any:
type: [integer, string, object, array, boolean, "null"]
items:
$ref: "#/components/schemas/Any"
properties:
next:
$ref: "#/components/schemas/Any"
headers:
header:
schema:
$ref: "#/components/schemas/Any"
style: simple
explode: false
parameters:
query:
in: query
name: query
style: deepObject
explode: true
required: true
schema:
$ref: "#/components/schemas/Any"
path:
in: path
name: path
required: true
schema:
type: [string, "null"]
header:
in: header
name: header
required: true
schema:
type: [string, "null"]
cookie:
in: cookie
name: cookie
required: true
schema:
type: [string, "null"]
Describe the bug you're encountering
The rendering of the parameters does not reflect the use of OpenAPI 3.1 type as a list. The use of "null" as list element to indicate "nullable" is not reflected as well.
To reproduce...
Steps to reproduce the behavior: Paste the yaml to swagger editor.
Expected behavior
Screenshots
Bad types for Response & header
all Parameters
Callback Response
but works for a RequestBody
Additional context or thoughts
type: […, "null"] is the preferable way to define nullable in v3.1, using the alternative anyOf: […,{type: "null"}] instead results in a additional/unnecessary level of indirection in models generated from description documents.
I'm confused:
- Here https://github.com/OAI/OpenAPI-Specification/issues/3148 @handrews states that both ways (
type: […, "null"]andanyOf: […,{type: "null"}]) are are supported in OAS 3.1 - But here https://github.com/smallrye/smallrye-open-api/issues/2094#issuecomment-2539374215 @MikeEdgar describes convincingly that combining
$refwithtype: […, "null"]is invalid - @commonism says above "...
type: […, "null"]is the preferable way to define nullable in v3.1, using the alternativeanyOf: […,{type: "null"}]..."
So openApi generated by smallrye with Quarkus3.17 is valid according to JSON-Schema (using the anyOf-way) but it's rendered badly in swagger-ui (real type is shown deeply nested, see https://github.com/smallrye/smallrye-open-api/issues/2094#issue-2722703834).
The question is: Is it possible to get a nicely rendered swagger-ui (with type-info not deeply nested but at the top like in the screenshot) with valid openApi.yaml according to [2]
(screenshot from https://github.com/smallrye/smallrye-open-api/issues/2094)
@ChMThiel there isn't any conflict here. What @MikeEdgar seems to be pointing out is that if you $ref a schema with type: "string", you can't just stick a type: "null" next to the $ref have it be the same as an anyOf. This is true: adjacent keyword results are ANDed (like allOf) and not ORed (like anyOf).
So you have to use anyOf to "add" type: "null" to the set of available types. This works because no other keywords apply to type: "null", so it doesn't really matter what else is in the schema containing type: "string" on the other end of the $ref.
What's different about the example that I answered is that the two options were 1.) have both types in the same type keyword (type: ["string", "null"]) or 2.) put each type in a separate anyOf branch. At no point in that issue I answered does it say that you can just put type: "null" next to a $ref and have that work.
Ok, than anyOfis the way to describe nullability.
But if so, the null/type-info is rendered in swagger-ui in a much less comprehensive way, as it was using OpenApi 3.0.3 (that's why i got a ticket in my company, see https://github.com/smallrye/smallrye-open-api/issues/2094):
- 3.0.3
- 3.1.0
Afaik the anyOf was orginaly intend to be used for multiple types (like inheritance: e.g. anyOf plant: tree, bush, flower, etc.) In such a case the 3.1.0-way of rendereing is just fine.
The special case that a value has just one type (in my example a LocalTime) but can be null is a very common thing (at least in my APIs). Rendering that special case in swagger-ui as 'ordinary' anyOf's is imho not optimal (compared with the 'old' 3.0.3 way: in 3.0.3 you see the 'real' local-time type on first level; in 3.1.0 you have expand/klick all the way down, at first glance on first level it looks like a string-value).
Isn't there a posibility that swagger-ui renders the type/null-information at least for one type/null anyOf's in a better way and not so deeply nested?
When this was written - swagger-ui does not support type-lists as type: […, null].
`anyOf: [{type: null}] was a workaround to have swagger-ui render nullable in 3.1.
This has changed over time:
Some improved:
Others … not:
Afaik the anyOf was orginaly intend to be used for multiple types (like inheritance: e.g. anyOf plant: tree, bush, flower, etc.) In such a case the 3.1.0-way of rendereing is just fine.
anyOf is just a non-exclusive OR. It has no inherent semantics beyond that.
When using null, as long as the other option(s) don't accept null then you can use oneOf safely as an alternative. But do be careful with this- a schema like {"minimum": 1} will accept null (but {"type": "integer", "minimum": 1} will not).
Afaik the anyOf was orginaly intend to be used for multiple types (like inheritance: e.g. anyOf plant: tree, bush, flower, etc.) In such a case the 3.1.0-way of rendereing is just fine.
anyOfis just a non-exclusive OR. It has no inherent semantics beyond that.When using
null, as long as the other option(s) don't acceptnullthen you can useoneOfsafely as an alternative. But do be careful with this- a schema like{"minimum": 1}will acceptnull(but{"type": "integer", "minimum": 1}will not).
I'm using quarkus that generates the openApi.yml - with anyOf for the null-info. So (even if i wanted to) i have very limited options to change this. And as the discussion here shows, using anyOf seem to be the right way to do that (so i closed https://github.com/smallrye/smallrye-open-api/issues/2094).
All i`m pointing out is that the type-info in the special case that a value has just one type but can be null, is rendered not as comprehensive as it was in OpenAPi 3.0.3.
hello, i'm looking for advice since i fail to find it in the spec ... is it that the order of {"type": "null"} in either anyOf or oneOf is relevant with regards to nullability? i have this mimal working example:
{
"openapi": "3.1.0",
"paths": {
"/foo": {
"get": {
"operationId": "foo",
"parameters": [
{
"name": "just_a_string",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "optional_from_enum",
"in": "query",
"description": "quux",
"required": false,
"schema": {
"oneOf": [
{ "type": "null" },
{ "$ref": "#/components/schemas/Role" }
]
}
}
]
}
}
},
"components": {
"schemas": {
"Role": {
"type": "string",
"enum": [ "abc", "def", "ghi" ]
}
}
}
}
which renders (incorrectly) like this (swagger ui 5.22.0):
however, merely swapping the order of the types in the oneOf gives me the expected UI:
...
{
"name": "optional_from_enum",
"in": "query",
"description": "quux",
"required": false,
"schema": {
"oneOf": [
{ "$ref": "#/components/schemas/Role" },
{ "type": "null" }
]
}
}
...
i'm surprised the order matters, but i'm not sure whether it's a "spec thingy" or just a deficiency of swagger-ui. I hope somebody can clarify.
just a deficiency of swagger-ui
How could we help to get the correct syntax working ?