Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Incorrectly serialized examples in OpenAPI schema #2272

Closed
4 tasks
floxay opened this issue Sep 2, 2023 · 9 comments · Fixed by #2660
Closed
4 tasks

Bug: Incorrectly serialized examples in OpenAPI schema #2272

floxay opened this issue Sep 2, 2023 · 9 comments · Fixed by #2660
Assignees
Labels
Bug 🐛 This is something that is not working as expected

Comments

@floxay
Copy link
Contributor

floxay commented Sep 2, 2023

Description

The provided example values are serialized incorrectly into the OpenAPI schema.
image

The issue seem to be that due to inheritance simply the BaseSchemaObject.to_schema() method is called for Example instances during the schema serialization, because of this all of the fields of Example ends up being serialized under the example "section" instead of just the value of the Example.value field.

URL to code causing the issue

if isinstance(value, BaseSchemaObject):
return value.to_schema()

MCVE

from typing import Annotated
from msgspec import Struct, Meta
from litestar import Litestar, post


class TestBody(Struct):
    field1: Annotated[str, Meta(examples=["the answer"])]
    field2: Annotated[int, Meta(examples=[42])]


@post(sync_to_thread=False)
def test(data: TestBody) -> None:
    ...


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app=Litestar(route_handlers=[test]), port=8080)

Steps to reproduce

1. Run the MCVE
2. Open any of the auto-generated docs (redoc, swagger, elements)
3. See the request or schema example (depending on docs)

Screenshots

No response

Logs

No response

Litestar Version

2.0.1

Platform

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)

Funding

  • If you would like to see an issue prioritized, make a pledge towards it!
  • We receive the pledge once the issue is completed & verified
Fund with Polar
@floxay floxay added Bug 🐛 This is something that is not working as expected Triage Required 🏥 This requires triage labels Sep 2, 2023
@abdulhaq-e
Copy link
Member

Hello

Sorry that I don't have much experience with OpenAPI yet. I would like to clarify that the correct serialization according to the OpenAPI specs is:

{
    "field1": "the answer",
    "field2": 42
}

Is that correct?

@abdulhaq-e abdulhaq-e self-assigned this Sep 2, 2023
@Goldziher
Copy link
Contributor

Hello

Sorry that I don't have much experience with OpenAPI yet. I would like to clarify that the correct serialization according to the OpenAPI specs is:

{
    "field1": "the answer",
    "field2": 42
}

Is that correct?

you can see the openapi spec: https://spec.openapis.org/oas/latest.html#requestBodyObject

@Goldziher
Copy link
Contributor

I am actually not certain this bug report is correct- https://spec.openapis.org/oas/latest.html#exampleObject. We need a reproduction of this with openapi 3.1 schema that fails an up to date validator.

@floxay
Copy link
Contributor Author

floxay commented Sep 2, 2023

Yes, this is a little bit confusing but I believe this is incorrect:

  • the "Try it out" feature fails on both Swagger and Spotlight Elements, which is not really surprising
    as it tries to send the above JSON which is obviously incorrect.
Images of the error (click to expand)

image
image

image

Edit: This seems to work and to me makes the most sense
image

Edit 2: Maybe it's enough to just not make Example instances for per field examples as those are not supposed to be OpenAPI Example Objects? Not sure where the logic for this is or what it looks like, just seems like a reasonable approach.

@floxay
Copy link
Contributor Author

floxay commented Sep 2, 2023

Based on "Edit 2": main...floxay:litestar:exp/openapi-example-serialization
Seems to work but unsure about the Pydantic v2 json_schema_extra callable stuff.

openapi.json

image

Pydantic v2 with `json_schema_extra`
class TestBody(BaseModel):
    field1: str = Field(examples=["the answer", "the other answer"])
    field2: int = Field(examples=[42])

    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "field1": "the answer",
                    "field2": 42
                }
            ]
        }
    }

image
image

Here I think it would make sense to create an Example Object from the json_schema_extra value as this is supposed to be a complete example?
Schema Objects don't seem to allow Example Objects nor Reference Objects...

@Goldziher
Copy link
Contributor

there should be a field called examples: [...], I think. So this is a bug.

PR with a fix and proper tests is highly welcome.

@Goldziher
Copy link
Contributor

@floxay do you want to take this over?

@Goldziher Goldziher removed the Triage Required 🏥 This requires triage label Sep 9, 2023
@floxay
Copy link
Contributor Author

floxay commented Sep 11, 2023

Sure, I think I can do it later today.

@floxay
Copy link
Contributor Author

floxay commented Sep 11, 2023

Unfortunately I still have no clue how to resolve the JsonSchemaExtraCallable in Pydantic's ConfigDict.json_schema_extra.

Additionally, while I were correcting some tests I've also noticed that the examples field of OpenAPI Parameter Objects is supposed to be a string to Example Object | Reference Object mapping, meaning the list litestar.Parameter takes is somewhat problematic as example names cannot be provided to build the map.
Plus, currently these examples provided as Example objects are serialized into ParamObj.schema.examples rather than ParamObj.examples:

  • ParamObj.schema is a Schema Object, "examples" here is a list of raw example values, values supplied here will not show up in Swagger for Parameter Objects (meanwhile a single example value under the deprecated "example" field would, somewhat weird...)
  • ParamObj.examples is the above mentioned map which allows Example Object, values supplied here will show up in Swagger for Parameter Objects

Due to the above tests/unit/test_openapi/test_parameters.py::test_create_parameters still fails in #2299

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug 🐛 This is something that is not working as expected
Projects
None yet
3 participants