litestar icon indicating copy to clipboard operation
litestar copied to clipboard

Enhancement: Support OpenAPI examples defined in Structs, Pydantic models and dataclasses

Open bogdanteleaga opened this issue 1 year ago • 3 comments

Description

Examples provided on json parameter fields do not get rendered in the Swagger UI.

The /schema/openapi.json does get generated similarly to https://github.com/litestar-org/litestar/pull/2660, but it seems this does not result in the examples being actually rendered in the Swagger UI.

I included examples for defining the classes with any of pydantic, msgspec and dataclass.

URL to code causing the issue

No response

MCVE

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


class Lookup(Struct):
    id: Annotated[str, Meta(examples=["example-1", "example-2"])]

#class Lookup(BaseModel):
#    id: Annotated[str, Field(json_schema_extra={"example": "example-1"})

#@dataclass
#class Lookup:
#    id: Annotated[str, Parameter(examples=[Example(value="example-1"), Example(value="example-2")])


@post(path="/lookup")
async def lookup(lookup: Lookup) -> Lookup:
    return Lookup(id=lookup.id)


app = Litestar(route_handlers=[lookup])

Steps to reproduce

1. Go to `http://127.0.0.1:8000/schema/swagger`
2. Click on `/lookup`
3. Scroll down to examples
4. They are missing

Screenshots

"![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"

Logs

No response

Litestar Version

2.4.2

Platform

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

[!NOTE]
While we are open for sponsoring on GitHub Sponsors and OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.

Check out all issues funded or available for funding on our Polar.sh Litestar dashboard

  • If you would like to see an issue prioritized, make a pledge towards it!
  • We receive the pledge once the issue is completed & verified
  • This, along with engagement in the community, helps us know which features are a priority to our users.
Fund with Polar

bogdanteleaga avatar Dec 06 '23 09:12 bogdanteleaga

Hey @bogdanteleaga, I've re-labelled this as an enhancement, since it's not really a bug; Declaring examples this way is simply not supported at the moment, but it's a reasonable feature to add.

provinzkraut avatar Feb 15 '24 10:02 provinzkraut

If I remember correctly this used to work before the rename. Maybe that came with a bigger change than expected, but that's the main reason I considered it to be a bug.

Looking at the other issue I still don't see an answer to the initial question: there is no way currently to set examples for the request body?

bogdanteleaga avatar Feb 15 '24 11:02 bogdanteleaga

If I remember correctly this used to work before the rename. Maybe that came with a bigger change than expected, but that's the main reason I considered it to be a bug.

That was in version 1.x, so it's considered a breaking change. The reason it used to work is that back then, the schema generation was done by Pydantic, which was good for Pydantic models, but tricky when you wanted to use other libraries such as msgspec or attrs. Now we're doing the schema generation ourselves, which has enabled a lot more features, but there's of course also some drawbacks and room for improvement, which this would fall under.

Looking at the other issue I still don't see an answer to the initial question: there is no way currently to set examples for the request body?

Sure, you can. You'll simply have to write it out explicitly:

from litestar import post, Litestar
from typing import Annotated

from litestar.openapi.spec import Example
from litestar.params import BodyKwarg
from dataclasses import dataclass


@dataclass
class Foo:
    bar: str


@post("/")
async def handler(
    data: Annotated[
        Foo,
        BodyKwarg(
            examples=[
                Example(summary="This is how to use the body", value="some string")
            ]
        ),
    ]
) -> None:
    pass

provinzkraut avatar Feb 15 '24 11:02 provinzkraut

Thank you for this example, but if Foo has several different attributes is it possible to set examples for each of them?

bogdanteleaga avatar Feb 29 '24 09:02 bogdanteleaga

@bogdanteleaga You can set e.g. value={"attr": 1, "another": 2}, and you can give a list of examples for the different variations.

tuukkamustonen avatar Feb 29 '24 10:02 tuukkamustonen

So the example above rewritten like this

@dataclass
class Foo:
    foo: str
    bar: str


@post("/")
async def handler(
    data: Annotated[
        Foo,
        BodyKwarg(
            examples=[
                Example(
                    summary="This is how to use the body",
                    value={"foo": "a", "bar": "b"},
                )
            ]
        ),
    ]
) -> None:
    pass

Results in this within the swagger UI

{
  "foo": "string",
  "bar": "string"
}

bogdanteleaga avatar Mar 01 '24 00:03 bogdanteleaga

A fix for this issue has been released in v2.7.1

github-actions[bot] avatar Mar 27 '24 06:03 github-actions[bot]