I’m trying to document endpoints via Pydantic models. When the Pydantic model contains an Enum type, both Swagger and ReDoc fail to render the OpenAPI JSON properly.
Here’s a minimal example:
from enum import Enum
from pydantic import BaseModel
from sanic import Sanic, json
from sanic_ext import openapi, validate
class Size(str, Enum):
S = "small"
M = "medium"
L = "large"
class Test(BaseModel):
size: Size
app = Sanic("TestApp")
@app.post("/")
@openapi.definition(body={"application/json": Test.model_json_schema()})
@validate(json=Test)
async def test(request, body):
return json(request.json)
ReDoc complains:
Something went wrong...
Invalid reference token: $defs
Swagger complains:
Resolver error at paths./.post.requestBody.content.application/json.schema.properties.size.$ref
Could not resolve reference: Could not resolve pointer: /$defs/Size does not exist in document
Pydantic seems to support Enums: Enums and Choices - Pydantic
Just not sure if this is a bug or whether there is something I’m missing here.
I tried switching from using an Enum
to a typing.Literal
, for example:
class Test(BaseModel):
size: Literal["small", "medium", "large"]
That works fine as a temporary workaround, but I’d really like an Enum
to reference inside handlers and throughout the code base like Size.M
, and I can’t use typing.Literal
in the same way.
I ran the generated openapi.json
through the redocly cli linter to find out more:
$ npx @redocly/cli lint ./openapi.json
...
[2] openapi.json:17:17 at #/paths/~1/post/requestBody/content/application~1json/schema/$defs
Property `$defs` is not expected here.
Did you mean: items ?
15 | "application/json": {
16 | "schema": {
17 | "$defs": {
18 | "Size": {
19 | "enum": [
Error was generated by the spec rule.
[3] openapi.json:29:27 at #/paths/~1/post/requestBody/content/application~1json/schema/properties/size
Can't resolve $ref
27 | },
28 | "properties": {
29 | "size": {
30 | "$ref": "#/$defs/Size"
31 | }
32 | },
33 | "required": [
Error was generated by the no-unresolved-refs rule.
...
Versions:
aiofiles==23.2.1; python_version >= '3.7'
annotated-types==0.5.0; python_version >= '3.7'
html5tagger==1.3.0; python_version >= '3.7'
httptools==0.6.0; python_full_version >= '3.5.0'
multidict==6.0.4; python_version >= '3.7'
pydantic==2.2.1; python_version >= '3.7'
pydantic-core==2.6.1; python_version >= '3.7'
pyyaml==6.0.1; python_version >= '3.6'
sanic[ext]==23.6.0; python_version >= '3.8'
sanic-ext==23.6.0
sanic-routing==23.6.0
tracerite==1.1.0
typing-extensions==4.7.1; python_version >= '3.7'
ujson==5.8.0; sys_platform != 'win32' and implementation_name == 'cpython'
uvloop==0.17.0; sys_platform != 'win32' and implementation_name == 'cpython'
websockets==11.0.3; python_version >= '3.7'