Problem with generated OpenAPI schema via Pydantic

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'
1 Like

Pydantic doesn’t use default oas path for components. You need to pass it a param to change the template.

We are experiencing the same problem, could you expand on how can we pass the parameters? Currently even when adding a custom path such as:

oas_test = OperationRequest.model_json_schema(ref_template="#/components/schemas/{model}")

The resulting documentation has the components within the class that uses it instead of root level.

Hello, I have the same issue and haven’t been able to make it work properly.
If I change the “ref_template”, it changes the ref but it keeps generating the components under “$defs”. Moreover, it’s within the path level.
On the other hand, if I use @dataclass to generate the OpenAPI and perform validation, I don’t know how to add metadata to include descriptions and examples for each field.
What is the correct way to achieve validation and generate documentation in ReDoc accurately? Thank you in advance.