openapi-pydantic icon indicating copy to clipboard operation
openapi-pydantic copied to clipboard

Bug: Pydantic Generic Models are not handled correctly in "$ref" field

Open jfschneider opened this issue 5 months ago • 0 comments

The "$ref" field in the openapi-schema only has a limited set of characters allowed. If I use a Generic Model as the schema_class parameter for "PydanticSchema", the square brackets "[]" won't get removed, which results in an invalid schema. Pydantic itself removes all invalid characters in "‎GenerateJsonSchema.normalize_name" (https://github.com/pydantic/pydantic/blob/main/pydantic/json_schema.py#L1939 ).

Reproduce:

from typing import Generic, TypeVar

from openapi_pydantic.util import (PydanticSchema,
                                   construct_open_api_with_schema_class)
from openapi_pydantic.v3 import OpenAPI
from pydantic import BaseModel

DataType = TypeVar("SibData")


class ResponseObject(BaseModel, Generic[DataType]):
    msg: str
    data: DataType


class HostResponse(BaseModel):
    fqdn: str
    location: str


if __name__ == "__main__":
    openapi = OpenAPI.model_validate(
        {
            "info": {"title": "Test", "version": "v0.0.1"},
            "paths": {
                "/host": {
                    "get": {
                        "responses": {
                            "200": {
                                "description": "host",
                                "content": {
                                    "application/json": {
                                        "schema": PydanticSchema(
                                            schema_class=ResponseObject[HostResponse]
                                        )
                                    }
                                },
                            }
                        },
                    }
                }
            },
        }
    )
    schema = construct_open_api_with_schema_class(openapi)
    print(schema.model_dump_json(by_alias=True, exclude_none=True, indent=2))

This results in

"schema": {
                  "$ref": "#/components/schemas/ResponseObject[HostResponse]"
                }

where as it should be:

"schema": {
                  "$ref": "#/components/schemas/ResponseObject_HostResponse_"
                }

to work with Pydantic:

  "components": {
    "schemas": {
       "ResponseObject_HostResponse_": 

I have a quick fix ready (basically copied the regex from "‎GenerateJsonSchema.normalize_name" to "_construct_ref_obj", but no test yet (https://github.com/jfschneider/openapi-pydantic/blob/normalize-refname/openapi_pydantic/util.py#L173)

jfschneider avatar Sep 19 '24 12:09 jfschneider