Skip to content

Nested classes result in invalid openapi.json #67

@evroon

Description

@evroon

Thanks for this package, makes generating OpenAPI specs much easier!

I couldn't find an existing issue, so here it is.

I noticed that when you put a pydantic model that models a request's body inside another class, it will result in an invalid openapi.json.
Let's consider this code:

from openapi_pydantic import OpenAPI
from openapi_pydantic.util import PydanticSchema, construct_open_api_with_schema_class
from pydantic import BaseModel, Field


def construct_base_open_api() -> OpenAPI:
    return OpenAPI.model_validate(
        {
            "info": {"title": "My own API", "version": "v0.0.1"},
            "paths": {
                "/a": {
                    "post": {
                        "requestBody": {
                            "content": {
                                "application/json": {
                                    "schema": PydanticSchema(schema_class=ResourceA.Body)
                                }
                            }
                        },
                    }
                },
                "/b": {
                    "post": {
                        "requestBody": {
                            "content": {
                                "application/json": {
                                    "schema": PydanticSchema(schema_class=ResourceB.Body)
                                }
                            }
                        },
                    }
                },
            },
        }
    )


class ResourceA:
    class Body(BaseModel):
        a: str


class ResourceB:
    class Body(BaseModel):
        b: str


open_api = construct_base_open_api()
open_api = construct_open_api_with_schema_class(open_api)

print(open_api.model_dump_json(by_alias=True, exclude_none=True, indent=2))

Let's consider that there are two flask resources, and we define the body of the request inside the resource as nested class.

{
  "openapi": "3.1.1",
  "info": {
    "title": "My own API",
    "version": "v0.0.1"
  },
  "servers": [
    {
      "url": "/"
    }
  ],
  "paths": {
    "/a": {
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Body"
              }
            }
          },
          "required": false
        },
        "deprecated": false
      }
    },
    "/b": {
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Body"
              }
            }
          },
          "required": false
        },
        "deprecated": false
      }
    }
  },
  "components": {
    "schemas": {
      "__main____ResourceA__Body": {
        "properties": {
          "a": {
            "type": "string",
            "title": "A"
          }
        },
        "type": "object",
        "required": [
          "a"
        ],
        "title": "Body"
      },
      "__main____ResourceB__Body": {
        "properties": {
          "b": {
            "type": "string",
            "title": "B"
          }
        },
        "type": "object",
        "required": [
          "b"
        ],
        "title": "Body"
      }
    }
  }
}

That results in an OpenAPI where both requests reference #/components/schemas/Body, which is not defined.

So I think the reference #/components/schemas/Body, should instead be more specific, like #/components/schemas/__main____ResourceA__Body.

I hope this makes sense. Please let me know if I misunderstood something and this is not actually a bug :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions