FastAPI's generated API docs drop down for showing multiple examples for the request body is only showing 1 example
Asked Answered
C

2

10

I am following the FastAPI tutorial, specifically the part about displaying multiple examples: https://fastapi.tiangolo.com/tutorial/schema-extra-example/.

I copied the code:

from typing import Optional

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        ...,
        examples={
            "normal": {
                "summary": "A normal example",
                "description": "A **normal** item works correctly.",
                "value": {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                },
            },
            "converted": {
                "summary": "An example with converted data",
                "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
                "value": {
                    "name": "Bar",
                    "price": "35.4",
                },
            },
            "invalid": {
                "summary": "Invalid data is rejected with an error",
                "value": {
                    "name": "Baz",
                    "price": "thirty five point four",
                },
            },
        },
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

...exactly as it is displayed on the page and I run it using Uvicorn. On my my screen I do not see any drop down with the 3 examples in the example dictionary of the request body. All I see is a single example value with just the types the fields need to be.

Why would that be and why is this not working for me please?

This is what I should get:

expected Swagger UI

But this is what I get:

actual Swagger UI

Complicacy answered 6/1, 2022 at 4:1 Comment(1)
Reported here: github.com/tiangolo/fastapi/discussions/9958Cartouche
P
11

I am not sure if this could help: https://github.com/tiangolo/fastapi/pull/1267#issuecomment-762557261 This means two things:

  1. examples need to go in Item.Config.schema_extra
  2. examples parameter must be referenced to the data from the class

Something like this:

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None

    class Config:
        schema_extra = {
            "examples": {
                "normal": {
                    "summary": "A normal example",
                    "description": "A **normal** item works correctly.",
                    "value": {
                        "name": "Foo",
                        "description": "A very nice Item",
                        "price": 35.4,
                        "tax": 3.2,
                    },
                },
                "converted": {
                    "summary": "An example with converted data",
                    "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
                    "value": {
                        "name": "Bar",
                        "price": "35.4",
                    },
                },
                "invalid": {
                    "summary": "Invalid data is rejected with an error",
                    "value": {
                        "name": "Baz",
                        "price": "thirty five point four",
                    },
                },
            }
        }


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        None,
        examples=Item.Config.schema_extra["examples"],
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

It helped me!

Profanity answered 2/2, 2022 at 22:46 Comment(2)
Doesn't work anymore as of FastAPI 0.99.1.Cartouche
@GinoMempin This worked for me with FastAPI 0.96.0.Aspia
C
1

It was an issue with FastAPI on >0.99.0 and <0.103.0, specifically with FastAPI's internal update to support OpenAPI 3.1 that is now based on the new JSON Schema that included spec for defining multiple examples in the generated openapi.json.

Unfortunately, (at this time) Swagger doesn't (yet) fully support this new spec for defining multiple examples, as explained in a related discussion on Github:

...the issue is with Swagger UI to fix - FastAPI is passing a valid schema to it, with all of the examples, but it is just that they aren't rendering those examples as a dropdown when they are in the JSON schema.

So, FastAPI fixed it on their side for now on 0.103.0 (related PR) and it's now explained in the FastAPI docs in https://fastapi.tiangolo.com/tutorial/schema-extra-example/#swagger-ui-and-openapi-specific-examples:

Now, as Swagger UI didn't support multiple JSON Schema examples (as of 2023-08-26), users didn't have a way to show multiple examples in the docs.

To solve that, FastAPI 0.103.0 added support for declaring the same old OpenAPI-specific examples field with the new parameter openapi_examples. 🤓

The only change you need to do is to bump your FastAPI version to be at least 0.103.0 and update your code to use openapi_examples instead of examples:

Old documentation (same as the one in the question):

@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        ...,
        examples={               # <-- THIS.

New way as of 0.103.0:

@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        openapi_examples={       # <-- THIS.

... and the Swagger UI docs should show the dropdown for selecting the examples, as documented. Preferrably, while you are it updating the code, consider using the recommended Annotated way: https://fastapi.tiangolo.com/tutorial/schema-extra-example/#__tabbed_6_1:

@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            openapi_examples={   # <-- THIS.

NOTE that bumping FastAPI to >0.100.0 might also bump your Pydantic dependency to v2, depending on how you are managing dependencies in your project. See FastAPI's 0.100.0 release notes.


For more technical details, see:

Cartouche answered 27/8, 2023 at 3:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.