quart-schema
quart-schema copied to clipboard
schemas are not referenced correctly in openapi.json
Description Currently, the openapi.json is faulty in the sense that even thought the schemas in the components property exists, they are not referenced in the requests/responses section.
Code to reproduce
from quart import Quart
from quart_schema import QuartSchema
from typing import List
from dataclasses import dataclass
app = Quart(__name__)
QuartSchema(app)
@dataclass
class Student:
name: str
@dataclass
class Students:
students: List[Student]
# works:
# "schema": {
# "properties": {
# "students": {
# "items": {
# "$ref": "#/components/schemas/Students"
# },
# "title": "Students",
# "type": "array"
# }
# },
@app.get("/students")
@validate_response(model_class=Students, status_code=200)
async def get_students():
return Students(students=[Student("stud1")]), 200
# doesnt work
# expected behaviour here would be
# "schema": {
# "$ref": "#/components/schemas/Student"
# }
@app.get("/student")
@validate_response(model_class=Student, status_code=200)
async def get_student():
return Student("stud1"), 200
This might be due to pydantics GenerateJsonSchema (l. 458 in quart_schema/extensions.py), which only returns a $ref, if the model_class.pydantic_core_schema contains properties with lists of dataclasses / pydantic dataclasses. Otherwise, just the model with its field definitions is returned as json.
Environment Python: 3.11.5 Quart: 0.19.4 Quart-Schema: 0.18.0
Possible Fix I am not quite sure about this, but it might be beneficial to use
JsonSchemaMode = "validation" # either "validation" or "serialization" # see pydantic.json_schema.JsonSchemaMode
def_, schema = GenerateJsonSchema(ref_template=REF_TEMPLATE).generate_definitions(
[(model_class.__name__, JsonSchemaMode, model_class.__pydantic_core_schema__)]
)
def_ contains the definitions as references using the REF_TEMPLATE
assert def_ == {(model_class.__name__, JsonSchemaMode): {"$ref": "REF_TEMPLATE".format(model_class.__name__)}}
# i.e. it would look like this: {('Students', 'validation'): {'$ref': '#/components/schemas/Students'}}
# and like this if Student where used instead: {('Student', 'validation'): {'$ref': '#/components/schemas/Student'}}
schema is similar to GenerateJsonSchema(...).generate(...) but without $defs in case of nested classes. Instead it contains the nested classes with references to each other, e.g.
def_, schema = GenerateJsonSchema(ref_template=REF_TEMPLATE).generate_definitions(
[(Students.__name__, JsonSchemaMode, Students.__pydantic_core_schema__)]
)
schema = {
"Student": {"properties": ...}, # same as schema from GenerateJsonSchema(...),generate(...) for Student
"Students": {"properties": ...} # same as schema from GenerateJsonSchema(...),generate(...) for Students but without $defs
}
# and in case Student is used instead of Students:
schema = {'Student': {'properties': {...}, 'required': [...], 'title': 'Student', 'type': 'object'}}
I don't understand the issue here, is it that it defines the schema rather than referencing it?
I don't understand the issue here, is it that it defines the schema rather than referencing it?
Yeah exactly.