Aller au contenu

Déclarer des exemples de données de requête

🌐 Traduction par IA et humains

Cette traduction a été réalisée par une IA guidée par des humains. 🤝

Elle peut contenir des erreurs d'interprétation du sens original, ou paraître peu naturelle, etc. 🤖

Vous pouvez améliorer cette traduction en nous aidant à mieux guider le LLM d'IA.

Version anglaise

Vous pouvez déclarer des exemples des données que votre application peut recevoir.

Voici plusieurs façons de le faire.

Ajouter des données JSON Schema supplémentaires dans les modèles Pydantic

Vous pouvez déclarer examples pour un modèle Pydantic qui seront ajoutés au JSON Schema généré.

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

Ces informations supplémentaires seront ajoutées telles quelles au JSON Schema de sortie pour ce modèle, et elles seront utilisées dans la documentation de l'API.

Vous pouvez utiliser l'attribut model_config qui accepte un dict comme décrit dans Documentation de Pydantic : Configuration.

Vous pouvez définir "json_schema_extra" avec un dict contenant toutes les données supplémentaires que vous souhaitez voir apparaître dans le JSON Schema généré, y compris examples.

Astuce

Vous pouvez utiliser la même technique pour étendre le JSON Schema et ajouter vos propres informations supplémentaires personnalisées.

Par exemple, vous pourriez l'utiliser pour ajouter des métadonnées pour une interface utilisateur frontend, etc.

Info

OpenAPI 3.1.0 (utilisé depuis FastAPI 0.99.0) a ajouté la prise en charge de examples, qui fait partie du standard JSON Schema.

Avant cela, seule la clé example avec un exemple unique était prise en charge. Elle l'est toujours par OpenAPI 3.1.0, mais elle est dépréciée et ne fait pas partie du standard JSON Schema. Vous êtes donc encouragé à migrer de example vers examples. 🤓

Vous pouvez en lire davantage à la fin de cette page.

Arguments supplémentaires de Field

Lorsque vous utilisez Field() avec des modèles Pydantic, vous pouvez également déclarer des examples supplémentaires :

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

examples dans JSON Schema - OpenAPI

En utilisant l'un des éléments suivants :

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

vous pouvez également déclarer un groupe de examples avec des informations supplémentaires qui seront ajoutées à leurs JSON Schemas à l'intérieur d'OpenAPI.

Body avec examples

Ici, nous passons examples contenant un exemple des données attendues dans Body() :

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

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

Exemple dans l'interface des documents

Avec l'une des méthodes ci-dessus, cela ressemblerait à ceci dans le /docs :

Body avec plusieurs examples

Vous pouvez bien sûr aussi passer plusieurs examples :

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

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

Lorsque vous faites cela, les exemples feront partie du JSON Schema interne pour ces données de corps.

Néanmoins, au moment de la rédaction, Swagger UI, l'outil chargé d'afficher l'interface des documents, ne prend pas en charge l'affichage de plusieurs exemples pour les données dans JSON Schema. Mais lisez ci-dessous pour un contournement.

examples spécifiques à OpenAPI

Avant que JSON Schema ne prenne en charge examples, OpenAPI prenait déjà en charge un autre champ également appelé examples.

Ce examples spécifique à OpenAPI se trouve dans une autre section de la spécification OpenAPI. Il se trouve dans les détails de chaque chemin d'accès, et non à l'intérieur de chaque JSON Schema.

Et Swagger UI prend en charge ce champ particulier examples depuis un certain temps. Vous pouvez donc l'utiliser pour afficher différents exemples dans l'interface des documents.

La forme de ce champ examples spécifique à OpenAPI est un dict avec plusieurs exemples (au lieu d'une list), chacun avec des informations supplémentaires qui seront également ajoutées à OpenAPI.

Cela ne va pas à l'intérieur de chaque JSON Schema contenu dans OpenAPI, cela se place à l'extérieur, directement dans le chemin d'accès.

Utiliser le paramètre openapi_examples

Vous pouvez déclarer le examples spécifique à OpenAPI dans FastAPI avec le paramètre openapi_examples pour :

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

Les clés du dict identifient chaque exemple, et chaque valeur est un autre dict.

Chaque dict d'exemple spécifique dans examples peut contenir :

  • summary : une courte description de l'exemple.
  • description : une description longue qui peut contenir du texte Markdown.
  • value : c'est l'exemple réel affiché, par ex. un dict.
  • externalValue : alternative à value, une URL pointant vers l'exemple. Cependant, cela pourrait ne pas être pris en charge par autant d'outils que value.

Vous pouvez l'utiliser ainsi :

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

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

Exemples OpenAPI dans l'interface des documents

Avec openapi_examples ajouté à Body(), le /docs ressemblerait à :

Détails techniques

Astuce

Si vous utilisez déjà FastAPI en version 0.99.0 ou supérieure, vous pouvez probablement passer ces détails.

Ils sont plus pertinents pour les versions plus anciennes, avant que OpenAPI 3.1.0 ne soit disponible.

Vous pouvez considérer ceci comme une courte leçon d'histoire d'OpenAPI et de JSON Schema. 🤓

Alertes

Ce sont des détails très techniques au sujet des standards JSON Schema et OpenAPI.

Si les idées ci-dessus fonctionnent déjà pour vous, cela pourrait suffire, et vous n'avez probablement pas besoin de ces détails, n'hésitez pas à les ignorer.

Avant OpenAPI 3.1.0, OpenAPI utilisait une version plus ancienne et modifiée de JSON Schema.

JSON Schema n'avait pas examples, donc OpenAPI a ajouté son propre champ example à sa version modifiée.

OpenAPI a également ajouté les champs example et examples à d'autres parties de la spécification :

Info

Ce paramètre examples ancien et spécifique à OpenAPI est désormais openapi_examples depuis FastAPI 0.103.0.

Le champ examples de JSON Schema

Ensuite, JSON Schema a ajouté un champ examples dans une nouvelle version de la spécification.

Puis le nouveau OpenAPI 3.1.0 s'est basé sur la dernière version (JSON Schema 2020-12) qui incluait ce nouveau champ examples.

Et désormais, ce nouveau champ examples a priorité sur l'ancien champ unique (et personnalisé) example, qui est maintenant déprécié.

Ce nouveau champ examples dans JSON Schema est juste une list d'exemples, et non pas un dict avec des métadonnées supplémentaires comme dans les autres endroits d'OpenAPI (décrits ci-dessus).

Info

Même après la sortie d'OpenAPI 3.1.0 avec cette nouvelle intégration plus simple avec JSON Schema, pendant un temps, Swagger UI, l'outil qui fournit la documentation automatique, ne prenait pas en charge OpenAPI 3.1.0 (il le fait depuis la version 5.0.0 🎉).

À cause de cela, les versions de FastAPI antérieures à 0.99.0 utilisaient encore des versions d'OpenAPI inférieures à 3.1.0.

examples avec Pydantic et FastAPI

Lorsque vous ajoutez examples dans un modèle Pydantic, en utilisant schema_extra ou Field(examples=["something"]), cet exemple est ajouté au JSON Schema de ce modèle Pydantic.

Et ce JSON Schema du modèle Pydantic est inclus dans l'OpenAPI de votre API, puis il est utilisé dans l'interface de la documentation.

Dans les versions de FastAPI antérieures à 0.99.0 (0.99.0 et supérieures utilisent le nouveau OpenAPI 3.1.0), lorsque vous utilisiez example ou examples avec l'une des autres utilitaires (Query(), Body(), etc.), ces exemples n'étaient pas ajoutés au JSON Schema qui décrit ces données (pas même à la version de JSON Schema propre à OpenAPI), ils étaient ajoutés directement à la déclaration du chemin d'accès dans OpenAPI (en dehors des parties d'OpenAPI qui utilisent JSON Schema).

Mais maintenant que FastAPI 0.99.0 et supérieures utilisent OpenAPI 3.1.0, qui utilise JSON Schema 2020-12, et Swagger UI 5.0.0 et supérieures, tout est plus cohérent et les exemples sont inclus dans JSON Schema.

Swagger UI et examples spécifiques à OpenAPI

Comme Swagger UI ne prenait pas en charge plusieurs exemples JSON Schema (au 2023-08-26), les utilisateurs n'avaient pas de moyen d'afficher plusieurs exemples dans les documents.

Pour résoudre cela, FastAPI 0.103.0 a ajouté la prise en charge de la déclaration du même ancien champ examples spécifique à OpenAPI avec le nouveau paramètre openapi_examples. 🤓

Résumé

Je disais que je n'aimais pas trop l'histoire ... et me voilà maintenant à donner des leçons d'« tech history ». 😅

En bref, mettez à niveau vers FastAPI 0.99.0 ou supérieur, et les choses sont bien plus simples, cohérentes et intuitives, et vous n'avez pas besoin de connaître tous ces détails historiques. 😎