Optional types in query parameters don't seem to play well with OpenAPI, resulting in a bad schema, except that upon some more testing if there is more than one non-None type in the annotation it works.
A query parameter annotated int | None produces incorrectly:
Additionally, optional types are being assumed to be optional parameters, resulting in "required": false regardless of whether the parameter has a default value or not.
And finally, route return types that are optional are mostly correct, but for some reason include an empty node (e.g. { "oneOf": [ { "type": "null" }, { "type": "integer" }, {} }). This results in /schema/redoc including a possible type of Any.
To Reproduce
(I ran this on 3.11, but IIRC 3.8+ for | None should work. I also tried with Optional and got the same results.)
As a minimal example:
# starlite_optionals.py
from datetime import date
from starlite import Starlite, get
@get("/a")
def a(v: int | None) -> int | None:
return v
@get("/b")
def b(v: int | str | date | None) -> int | str | date | None:
return v
@get("/c")
def c(v: int | None = None) -> int | None:
return v
@get("/d")
def d(v: int | str | date | None = None) -> int | str | date | None:
return v
app = Starlite(route_handlers=[a, b, c, d], debug=True)
Describe the bug
A query parameter annotated
int | None
produces incorrectly:While one annotated
int | str | date | None
produces correctly:Additionally, optional types are being assumed to be optional parameters, resulting in
"required": false
regardless of whether the parameter has a default value or not.And finally, route return types that are optional are mostly correct, but for some reason include an empty node (e.g.
{ "oneOf": [ { "type": "null" }, { "type": "integer" }, {} }
). This results in/schema/redoc
including a possible type ofAny
.To Reproduce
(I ran this on 3.11, but IIRC 3.8+ for
| None
should work. I also tried withOptional
and got the same results.)As a minimal example:
Check the generated schema below, or by running
uvicorn starlite_optionals:app
and navigating to http://127.0.0.1:8000/schema/openapi.json and/or http://127.0.0.1:8000/schema/.Generated OpenAPI schema.
```json { "openapi": "3.1.0", "info": { "title": "Starlite API", "version": "1.0.0" }, "servers": [ { "url": "/" } ], "paths": { "/a": { "get": { "operationId": "AA", "parameters": [ { "name": "v", "in": "query", "required": false, "deprecated": false, "allowEmptyValue": false, "allowReserved": false, "schema": { "oneOf": [ { "type": "null" }, { "oneOf": [] } ] } } ], "responses": { "200": { "description": "Request fulfilled, document follows", "headers": {}, "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "type": "integer" }, {} ] } } } }, "400": { "description": "Bad request syntax or unsupported method", "content": { "application/json": { "schema": { "properties": { "status_code": { "type": "integer" }, "detail": { "type": "string" }, "extra": { "additionalProperties": {}, "type": [ "null", "object", "array" ] } }, "type": "object", "required": [ "detail", "status_code" ], "description": "Validation Exception", "examples": [ { "status_code": 400, "detail": "Bad Request", "extra": {} } ] } } } } }, "deprecated": false } }, "/b": { "get": { "operationId": "BB", "parameters": [ { "name": "v", "in": "query", "required": false, "deprecated": false, "allowEmptyValue": false, "allowReserved": false, "schema": { "oneOf": [ { "type": "null" }, { "type": "integer" }, { "type": "string" }, { "type": "string", "format": "date" } ] } } ], "responses": { "200": { "description": "Request fulfilled, document follows", "headers": {}, "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "type": "integer" }, { "type": "string" }, { "type": "string", "format": "date" }, {} ] } } } }, "400": { "description": "Bad request syntax or unsupported method", "content": { "application/json": { "schema": { "properties": { "status_code": { "type": "integer" }, "detail": { "type": "string" }, "extra": { "additionalProperties": {}, "type": [ "null", "object", "array" ] } }, "type": "object", "required": [ "detail", "status_code" ], "description": "Validation Exception", "examples": [ { "status_code": 400, "detail": "Bad Request", "extra": {} } ] } } } } }, "deprecated": false } }, "/c": { "get": { "operationId": "CC", "parameters": [ { "name": "v", "in": "query", "required": false, "deprecated": false, "allowEmptyValue": false, "allowReserved": false, "schema": { "oneOf": [ { "type": "null" }, { "oneOf": [] } ] } } ], "responses": { "200": { "description": "Request fulfilled, document follows", "headers": {}, "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "type": "integer" }, {} ] } } } }, "400": { "description": "Bad request syntax or unsupported method", "content": { "application/json": { "schema": { "properties": { "status_code": { "type": "integer" }, "detail": { "type": "string" }, "extra": { "additionalProperties": {}, "type": [ "null", "object", "array" ] } }, "type": "object", "required": [ "detail", "status_code" ], "description": "Validation Exception", "examples": [ { "status_code": 400, "detail": "Bad Request", "extra": {} } ] } } } } }, "deprecated": false } }, "/d": { "get": { "operationId": "DD", "parameters": [ { "name": "v", "in": "query", "required": false, "deprecated": false, "allowEmptyValue": false, "allowReserved": false, "schema": { "oneOf": [ { "type": "null" }, { "type": "integer" }, { "type": "string" }, { "type": "string", "format": "date" } ] } } ], "responses": { "200": { "description": "Request fulfilled, document follows", "headers": {}, "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "type": "integer" }, { "type": "string" }, { "type": "string", "format": "date" }, {} ] } } } }, "400": { "description": "Bad request syntax or unsupported method", "content": { "application/json": { "schema": { "properties": { "status_code": { "type": "integer" }, "detail": { "type": "string" }, "extra": { "additionalProperties": {}, "type": [ "null", "object", "array" ] } }, "type": "object", "required": [ "detail", "status_code" ], "description": "Validation Exception", "examples": [ { "status_code": 400, "detail": "Bad Request", "extra": {} } ] } } } } }, "deprecated": false } } } } ```