litestar-org/litestar

Bug: OpenAPI spec blank response schema when using Response object

Opened this issue · 2 comments

Description

See example below - using the Scalar docs the schema for the get_items endpoint is blank (just says "No Body"). Ideally the schema would be populated exactly as if the response wasn't wrapped in a "Response" object, i.e. it should just use the type hinting info List[Item].

URL to code causing the issue

http://127.0.0.1:8000/schema

MCVE

from dataclasses import dataclass
from typing import List

from litestar import Litestar, get, Response
from litestar.openapi import OpenAPIConfig
from litestar.openapi.plugins import ScalarRenderPlugin
from litestar.dto import DataclassDTO, DTOConfig


@dataclass
class Item:
    id: int
    name: str
    secret: str


class ItemReadDTO(DataclassDTO[Item]):
    config = DTOConfig(exclude=["secret"])


@get("/get_items", return_dto=ItemReadDTO)
async def get_items() -> Response[List[Item]]:
    return Response(
        headers={"X-SomeParam": "SomeValue"},
        content=[
            Item(id=1, name="Item 1", secret='123'),
            Item(id=2, name="Item 2", secret='456'),
        ]
    )


@get("/get_items_raw", return_dto=ItemReadDTO)
async def get_items_raw() -> List[Item]:
    return [
        Item(id=1, name="Item 1", secret='123'),
        Item(id=2, name="Item 2", secret='456'),
    ]


app = Litestar(
    route_handlers=[get_items, get_items_raw],
    openapi_config=OpenAPIConfig(
        title="Scalar Issue",
        version="0.1.0",
        render_plugins=[ScalarRenderPlugin()],
    ),
    debug=True,
)

Steps to reproduce

run uvicorn main:app

Screenshots

"![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"

Logs

No response

Litestar Version

2.13.0

Platform

  • Linux
  • 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 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

I think this is a bug with DTOs, not the Response itself

@provinzkraut indeed that makes sense.

FYI, the following endpoint (that returns a Response but doesn't specify a return_dto in the route decorator) also has the same issue.

@get("/get_items_nodto")
async def get_items_nodto() -> List[ItemReadDTO]:
    return Response(
        headers={"X-SomeParam": "SomeValue"},
        content=[
            Item(id=1, name="Item 1", secret='123'),
            Item(id=2, name="Item 2", secret='456'),
        ]
    )

However, using a response with a non-dto works correctly, e.g.

@get("/get_items_nodto")
async def get_items_nodto() -> List[Item]:
    return Response(
        headers={"X-SomeParam": "SomeValue"},
        content=[
            Item(id=1, name="Item 1", secret='123'),
            Item(id=2, name="Item 2", secret='456'),
        ]
    )