#Named Request Body Examples

1 messages · Page 1 of 1 (latest)

mint drum
#

Hi all, I'm struggling to get named examples for a request body to work.

The OpenAPI spec here should support it:
https://spec.openapis.org/oas/v3.1.0#example-object

Redocly has an example here for Request examples:
https://redocly.com/docs/openapi-visual-reference/example#request-examples

I was able to take some of the code from the documentation on Customizing the Operation Class to sort-of get the behavior I want:
https://docs.litestar.dev/latest/usage/openapi/schema_generation.html#customizing-operation-class

FastAPI had a similar issue and appears to have fixed it here:
https://fastapi.tiangolo.com/tutorial/schema-extra-example/#openapi-examples-in-the-docs-ui

Note the CustomOperation where I'm sticking the examples in manually. Running this gets me what I want, but it feels like I'm doing it in a way that is way too janky.

Thanks in advance to anyone who reaches out. I've banged my head on my desk with this issue for about 2 days now.

FastAPI framework, high performance, easy to learn, fast to code, ready for production

OpenAPI-generated documentation tool with 23k+ stars on Github - make APIs your company's superpower.

hard currentBOT
#
Notes for Named Request Body Examples
At your assistance

@mint drum

No Response?

If no response in a reasonable time, ping @Member.

Closing

To close, type !solve or byte solve.

MCVE

Please include an MCVE so that we can reproduce your issue locally.

mint drum
#

MCVE:

from dataclasses import dataclass

from litestar import Litestar, post
from litestar.datastructures import State
from litestar.openapi.spec import (
    Example,
    Operation,
)
from pydantic.v1 import BaseModel


class User(BaseModel):
    name: str
    age: int


class Job(BaseModel):
    job_title: str


request_examples = {
    "John Doe Example": Example(
        summary="John Doe Example Summary",
        description="John Doe Example Description",
        value=User(name="John Doe", age=25).dict(),
    ),
    "Larry Moe Example": Example(
        summary="Larry Moe Example Summary",
        description="Larry Moe Example Description",
        value=User(name="Larry Moe", age=30).dict(),
    ),
}

response_examples = {
    "John Doe Example": Example(
        summary="John Doe Response Example Summary",
        description="John Doe Response Example Description",
        value=Job(job_title="Engineer").dict(),
    ),
    "Larry Moe Example": Example(
        summary="Larry Moe Response Example Summary",
        description="Larry Moe Response Example Description",
        value=Job(job_title="Manager").dict(),
    ),
}


@dataclass
class CustomOperation(Operation):
    def __post_init__(self) -> None:
        self.request_body.content["application/json"].examples = request_examples
        self.responses["201"].content["application/json"].examples = response_examples


@post(
    "/user-example",
    operation_class=CustomOperation,
)
async def user_example(state: State, data: User) -> Job:
    return Job(job_title="Engineer")


app = Litestar(
    route_handlers=[user_example],
)
hasty river
#
from pydantic.v1 import BaseModel
from typing_extensions import Annotated
from litestar import Litestar, post
from litestar.datastructures import State
from litestar.openapi.datastructures import ResponseSpec
from litestar.openapi.spec import Example
from litestar.params import Body

class User(BaseModel):
    name: str
    age: int

class Job(BaseModel):
    job_title: str

request_examples = [
    Example(
        summary="John Doe Example Summary",
        description="John Doe Example Description",
        value=User(name="John Doe", age=25).dict(),
    ),
    Example(
        summary="Larry Moe Example Summary",
        description="Larry Moe Example Description",
        value=User(name="Larry Moe", age=30).dict(),
    ),
]

response_examples = [
    Example(
        summary="John Doe Response Example Summary",
        description="John Doe Response Example Description",
        value=Job(job_title="Engineer").dict(),
    ),
    Example(
        summary="Larry Moe Response Example Summary",
        description="Larry Moe Response Example Description",
        value=Job(job_title="Manager").dict(),
    ),
]

@post("/user-example", responses={201: ResponseSpec(User, examples=response_examples)})
async def user_example(state: State, data: Annotated[User, Body(examples=request_examples)]) -> Job:
    return Job(job_title="Engineer")

app = Litestar(route_handlers=[user_example])
#

this takes care of what you want, except that we only seem to show only one example in the request body (not sure if we are adding it in the wrong place)

#

yes, we are adding the request examples in the wrong place

mint drum
# hasty river yes, we are adding the request examples in the wrong place

Thanks for the reply! That looks a lot cleaner but it's still not quite what I'm getting at. I've narrowed it down and can really show what I'm trying to get at.

Firstly, request and response bodies are capable of taking a dict[str, Example] in the examples field:

Litestar isn't currently handling request examples correctly anyway, as you mentioned.

Litestar isn't capable of accepting a dict in the examples field for a response. It has to be specified as list[Example], and it automatically generates the key name when it is converted to a dict. In Stoplight Elements, this key name is displayed to the user.

Secondly, schema objects are also capable of taking examples:

Litestar only appears to be including Schema examples if the object is used in a header, but not if it is used in a response.

This creates a funny situation in the attached file where JobResponse has examples visible in the "Endpoints" section but if you check in the "Schemas" section, there's nothing there. In Stoplight Elements, object schemas are also displayed to the user.

I've attached an updated version of the code that should be easy to run and see the docs page.

hasty river
#

<@&1084813023044173866> thoughts?

daring swallow
#

Seems like something we need to fix