Zum Inhalt

Beispiel-Request-Daten deklarieren

Sie können Beispiele fĂŒr die Daten deklarieren, die Ihre App empfangen kann.

Hier sind mehrere Möglichkeiten, das zu tun.

ZusÀtzliche JSON-Schemadaten in Pydantic-Modellen

Sie können examples („Beispiele“) fĂŒr ein Pydantic-Modell deklarieren, welche dem generierten JSON-Schema hinzugefĂŒgt werden.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ]
        }
    }


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results
đŸ€“ Other versions and variants
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


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

    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ]
        }
    }


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results
from fastapi import FastAPI
from pydantic.v1 import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

    class Config:
        schema_extra = {
            "examples": [
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ]
        }


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results
đŸ€“ Other versions and variants
from typing import Union

from fastapi import FastAPI
from pydantic.v1 import BaseModel

app = FastAPI()


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

    class Config:
        schema_extra = {
            "examples": [
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ]
        }


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

Diese zusĂ€tzlichen Informationen werden unverĂ€ndert zum fĂŒr dieses Modell ausgegebenen JSON-Schema hinzugefĂŒgt und in der API-Dokumentation verwendet.

In Pydantic Version 2 wĂŒrden Sie das Attribut model_config verwenden, das ein dict akzeptiert, wie beschrieben in Pydantic-Dokumentation: Configuration.

Sie können json_schema_extra setzen, mit einem dict, das alle zusĂ€tzlichen Daten enthĂ€lt, die im generierten JSON-Schema angezeigt werden sollen, einschließlich examples.

In Pydantic Version 1 wĂŒrden Sie eine interne Klasse Config und schema_extra verwenden, wie beschrieben in Pydantic-Dokumentation: Schema customization.

Sie können schema_extra setzen, mit einem dict, das alle zusĂ€tzlichen Daten enthĂ€lt, die im generierten JSON-Schema angezeigt werden sollen, einschließlich examples.

Tipp

Mit derselben Technik können Sie das JSON-Schema erweitern und Ihre eigenen benutzerdefinierten Zusatzinformationen hinzufĂŒgen.

Sie könnten das beispielsweise verwenden, um Metadaten fĂŒr eine Frontend-BenutzeroberflĂ€che usw. hinzuzufĂŒgen.

Info

OpenAPI 3.1.0 (verwendet seit FastAPI 0.99.0) hat UnterstĂŒtzung fĂŒr examples hinzugefĂŒgt, was Teil des JSON Schema Standards ist.

Zuvor unterstĂŒtzte es nur das SchlĂŒsselwort example mit einem einzigen Beispiel. Dieses wird weiterhin von OpenAPI 3.1.0 unterstĂŒtzt, ist jedoch deprecatet und nicht Teil des JSON Schema Standards. Wir empfehlen Ihnen daher, von example nach examples zu migrieren. đŸ€“

Mehr erfahren Sie am Ende dieser Seite.

ZusĂ€tzliche Argumente fĂŒr Field

Wenn Sie Field() mit Pydantic-Modellen verwenden, können Sie ebenfalls zusÀtzliche examples deklarieren:

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()


class Item(BaseModel):
    name: str = Field(examples=["Foo"])
    description: str | None = Field(default=None, examples=["A very nice Item"])
    price: float = Field(examples=[35.4])
    tax: float | None = Field(default=None, examples=[3.2])


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results
đŸ€“ Other versions and variants
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()


class Item(BaseModel):
    name: str = Field(examples=["Foo"])
    description: Union[str, None] = Field(default=None, examples=["A very nice Item"])
    price: float = Field(examples=[35.4])
    tax: Union[float, None] = Field(default=None, examples=[3.2])


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

examples im JSON-Schema – OpenAPI

Bei Verwendung von:

  • Path()
  • Query()
  • Header()
  • Cookie()
  • Body()
  • Form()
  • File()

können Sie auch eine Gruppe von examples mit zusĂ€tzlichen Informationen deklarieren, die zu ihren JSON-Schemas innerhalb von OpenAPI hinzugefĂŒgt werden.

Body mit examples

Hier ĂŒbergeben wir examples, welches ein einzelnes Beispiel fĂŒr die in Body() erwarteten Daten enthĂ€lt:

from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples=[
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ],
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results
đŸ€“ Other versions and variants
from typing import Annotated, Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


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


@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples=[
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ],
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results

Tip

Prefer to use the Annotated version if possible.

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Item = Body(
        examples=[
            {
                "name": "Foo",
                "description": "A very nice Item",
                "price": 35.4,
                "tax": 3.2,
            }
        ],
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


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


@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Item = Body(
        examples=[
            {
                "name": "Foo",
                "description": "A very nice Item",
                "price": 35.4,
                "tax": 3.2,
            }
        ],
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

Beispiel in der Dokumentations-BenutzeroberflÀche

Mit jeder der oben genannten Methoden wĂŒrde es in /docs so aussehen:

Body mit mehreren examples

Sie können natĂŒrlich auch mehrere examples ĂŒbergeben:

from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples=[
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                },
                {
                    "name": "Bar",
                    "price": "35.4",
                },
                {
                    "name": "Baz",
                    "price": "thirty five point four",
                },
            ],
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results
đŸ€“ Other versions and variants
from typing import Annotated, Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


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


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples=[
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                },
                {
                    "name": "Bar",
                    "price": "35.4",
                },
                {
                    "name": "Baz",
                    "price": "thirty five point four",
                },
            ],
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results

Tip

Prefer to use the Annotated version if possible.

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        examples=[
            {
                "name": "Foo",
                "description": "A very nice Item",
                "price": 35.4,
                "tax": 3.2,
            },
            {
                "name": "Bar",
                "price": "35.4",
            },
            {
                "name": "Baz",
                "price": "thirty five point four",
            },
        ],
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


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


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        examples=[
            {
                "name": "Foo",
                "description": "A very nice Item",
                "price": 35.4,
                "tax": 3.2,
            },
            {
                "name": "Bar",
                "price": "35.4",
            },
            {
                "name": "Baz",
                "price": "thirty five point four",
            },
        ],
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

Wenn Sie das tun, werden die Beispiele Teil des internen JSON-Schemas fĂŒr diese Body-Daten.

WĂ€hrend dies geschrieben wird, unterstĂŒtzt Swagger UI, das fĂŒr die Anzeige der Dokumentations-BenutzeroberflĂ€che zustĂ€ndige Tool, jedoch nicht die Anzeige mehrerer Beispiele fĂŒr die Daten in JSON Schema. Aber lesen Sie unten fĂŒr einen Workaround weiter.

OpenAPI-spezifische examples

Schon bevor JSON Schema examples unterstĂŒtzte, unterstĂŒtzte OpenAPI ein anderes Feld, das auch examples genannt wurde.

Diese OpenAPI-spezifischen examples finden sich in einem anderen Abschnitt der OpenAPI-Spezifikation. Sie sind Details fĂŒr jede Pfadoperation, nicht fĂŒr jedes JSON-Schema.

Und Swagger UI unterstĂŒtzt dieses spezielle Feld examples schon seit einiger Zeit. Sie können es also verwenden, um verschiedene Beispiele in der BenutzeroberflĂ€che der Dokumentation anzuzeigen.

Das Format dieses OpenAPI-spezifischen Felds examples ist ein dict mit mehreren Beispielen (anstelle einer list), jedes mit zusĂ€tzlichen Informationen, die auch zu OpenAPI hinzugefĂŒgt werden.

Dies erfolgt nicht innerhalb jedes in OpenAPI enthaltenen JSON-Schemas, sondern außerhalb, in der Pfadoperation.

Verwendung des Parameters openapi_examples

Sie können die OpenAPI-spezifischen examples in FastAPI mit dem Parameter openapi_examples deklarieren, fĂŒr:

  • Path()
  • Query()
  • Header()
  • Cookie()
  • Body()
  • Form()
  • File()

Die SchlĂŒssel des dict identifizieren jedes Beispiel, und jeder Wert ist ein weiteres dict.

Jedes spezifische Beispiel-dict in den examples kann Folgendes enthalten:

  • summary: Kurze Beschreibung fĂŒr das Beispiel.
  • description: Eine lange Beschreibung, die Markdown-Text enthalten kann.
  • value: Dies ist das tatsĂ€chlich angezeigte Beispiel, z. B. ein dict.
  • externalValue: Alternative zu value, eine URL, die auf das Beispiel verweist. Allerdings wird dies möglicherweise nicht von so vielen Tools unterstĂŒtzt wie value.

Sie können es so verwenden:

from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            openapi_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
đŸ€“ Other versions and variants
from typing import Annotated, Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


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


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            openapi_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

Tip

Prefer to use the Annotated version if possible.

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        openapi_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

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


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


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        openapi_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

OpenAPI-Beispiele in der Dokumentations-BenutzeroberflÀche

Wenn openapi_examples zu Body() hinzugefĂŒgt wird, wĂŒrde /docs so aussehen:

Technische Details

Tipp

Wenn Sie bereits FastAPI Version 0.99.0 oder höher verwenden, können Sie diese Details wahrscheinlich ĂŒberspringen.

Sie sind fĂŒr Ă€ltere Versionen relevanter, bevor OpenAPI 3.1.0 verfĂŒgbar war.

Sie können dies als eine kurze Geschichtsstunde zu OpenAPI und JSON Schema betrachten. đŸ€“

Achtung

Dies sind sehr technische Details zu den Standards JSON Schema und OpenAPI.

Wenn die oben genannten Ideen bereits fĂŒr Sie funktionieren, reicht das möglicherweise aus und Sie benötigen diese Details wahrscheinlich nicht, ĂŒberspringen Sie sie gerne.

Vor OpenAPI 3.1.0 verwendete OpenAPI eine Àltere und modifizierte Version von JSON Schema.

JSON Schema hatte keine examples, daher fĂŒgte OpenAPI seiner eigenen modifizierten Version ein eigenes example-Feld hinzu.

OpenAPI fĂŒgte auch die Felder example und examples zu anderen Teilen der Spezifikation hinzu:

Info

Dieser alte, OpenAPI-spezifische examples-Parameter heißt seit FastAPI 0.103.0 jetzt openapi_examples.

JSON Schemas Feld examples

Aber dann fĂŒgte JSON Schema ein examples-Feld zu einer neuen Version der Spezifikation hinzu.

Und dann basierte das neue OpenAPI 3.1.0 auf der neuesten Version (JSON Schema 2020-12), die dieses neue Feld examples enthielt.

Und jetzt hat dieses neue examples-Feld Vorrang vor dem alten (und benutzerdefinierten) example-Feld, im Singular, das jetzt deprecatet ist.

Dieses neue examples-Feld in JSON Schema ist nur eine list von Beispielen, kein Dict mit zusÀtzlichen Metadaten wie an den anderen Stellen in OpenAPI (oben beschrieben).

Info

Selbst, nachdem OpenAPI 3.1.0 veröffentlicht wurde, mit dieser neuen, einfacheren Integration mit JSON Schema, unterstĂŒtzte Swagger UI, das Tool, das die automatische Dokumentation bereitstellt, eine Zeit lang OpenAPI 3.1.0 nicht (das tut es seit Version 5.0.0 🎉).

Aus diesem Grund verwendeten Versionen von FastAPI vor 0.99.0 immer noch Versionen von OpenAPI vor 3.1.0.

Pydantic- und FastAPI-examples

Wenn Sie examples innerhalb eines Pydantic-Modells hinzufĂŒgen, indem Sie schema_extra oder Field(examples=["something"]) verwenden, wird dieses Beispiel dem JSON-Schema fĂŒr dieses Pydantic-Modell hinzugefĂŒgt.

Und dieses JSON-Schema des Pydantic-Modells ist in der OpenAPI Ihrer API enthalten und wird dann in der BenutzeroberflÀche der Dokumentation verwendet.

In Versionen von FastAPI vor 0.99.0 (0.99.0 und höher verwenden das neuere OpenAPI 3.1.0), wenn Sie example oder examples mit einem der anderen Werkzeuge (Query(), Body(), usw.) verwendet haben, wurden diese Beispiele nicht zum JSON-Schema hinzugefĂŒgt, das diese Daten beschreibt (nicht einmal zur OpenAPI-eigenen Version von JSON Schema), sondern direkt zur Pfadoperation-Deklaration in OpenAPI (außerhalb der Teile von OpenAPI, die JSON Schema verwenden).

Aber jetzt, da FastAPI 0.99.0 und höher, OpenAPI 3.1.0 verwendet, das JSON Schema 2020-12 verwendet, und Swagger UI 5.0.0 und höher, ist alles konsistenter und die Beispiele sind in JSON Schema enthalten.

Swagger-BenutzeroberflÀche und OpenAPI-spezifische examples

Da die Swagger-BenutzeroberflĂ€che derzeit nicht mehrere JSON Schema Beispiele unterstĂŒtzt (Stand: 26.08.2023), hatten Benutzer keine Möglichkeit, mehrere Beispiele in der Dokumentation anzuzeigen.

Um dieses Problem zu lösen, hat FastAPI 0.103.0 UnterstĂŒtzung fĂŒr die Deklaration desselben alten OpenAPI-spezifischen examples-Felds mit dem neuen Parameter openapi_examples hinzugefĂŒgt. đŸ€“

Zusammenfassung

Ich habe immer gesagt, dass ich Geschichte nicht so sehr mag ... und jetzt schauen Sie mich an, wie ich „Technikgeschichte“-Unterricht gebe. 😅

Kurz gesagt: Aktualisieren Sie auf FastAPI 0.99.0 oder höher, und die Dinge sind viel einfacher, konsistenter und intuitiver, und Sie mĂŒssen nicht alle diese historischen Details kennen. 😎