Aller au contenu

Paramètres de requête et validations de chaînes de caractères

FastAPI vous permet de déclarer des informations et des validateurs additionnels pour vos paramètres de requêtes.

Commençons avec cette application pour exemple :

from typing import Union

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[str, None] = None):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Le paramètre de requête q a pour type Union[str, None] (ou str | None en Python 3.10), signifiant qu'il est de type str mais pourrait aussi être égal à None, et bien sûr, la valeur par défaut est None, donc FastAPI saura qu'il n'est pas requis.

Note

FastAPI saura que la valeur de q n'est pas requise grâce à la valeur par défaut = None.

Le Union dans Union[str, None] permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.

Validation additionnelle

Nous allons imposer que bien que q soit un paramètre optionnel, dès qu'il est fourni, sa longueur n'excède pas 50 caractères.

Importer Query

Pour cela, importez d'abord Query depuis fastapi :

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Utiliser Query comme valeur par défaut

Construisez ensuite la valeur par défaut de votre paramètre avec Query, en choisissant 50 comme max_length :

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Comme nous devons remplacer la valeur par défaut None dans la fonction par Query(), nous pouvons maintenant définir la valeur par défaut avec le paramètre Query(default=None), il sert le même objectif qui est de définir cette valeur par défaut.

Donc :

q: Union[str, None] = Query(default=None)

... rend le paramètre optionnel, et est donc équivalent à :

q: Union[str, None] = None

Mais déclare explicitement q comme étant un paramètre de requête.

Info

Gardez à l'esprit que la partie la plus importante pour rendre un paramètre optionnel est :

= None

ou :

= Query(None)

et utilisera ce None pour détecter que ce paramètre de requête n'est pas requis.

Le Union[str, None] est uniquement là pour permettre à votre éditeur un meilleur support.

Ensuite, nous pouvons passer d'autres paramètres à Query. Dans cet exemple, le paramètre max_length qui s'applique aux chaînes de caractères :

q: Union[str, None] = Query(default=None, max_length=50)

Cela va valider les données, montrer une erreur claire si ces dernières ne sont pas valides, et documenter le paramètre dans le schéma OpenAPI de cette path operation.

Rajouter plus de validation

Vous pouvez aussi rajouter un second paramètre min_length :

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(default=None, min_length=3, max_length=50)
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Ajouter des validations par expressions régulières

On peut définir une expression régulière à laquelle le paramètre doit correspondre :

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=None, min_length=3, max_length=50, pattern="^fixedquery$"
    )
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Cette expression régulière vérifie que la valeur passée comme paramètre :

  • ^ : commence avec les caractères qui suivent, avec aucun caractère avant ceux-là.
  • fixedquery : a pour valeur exacte fixedquery.
  • $ : se termine directement ensuite, n'a pas d'autres caractères après fixedquery.

Si vous vous sentez perdu avec le concept d'expression régulière, pas d'inquiétudes. Il s'agit d'une notion difficile pour beaucoup, et l'on peut déjà réussir à faire beaucoup sans jamais avoir à les manipuler.

Mais si vous décidez d'apprendre à les utiliser, sachez qu'ensuite vous pouvez les utiliser directement dans FastAPI.

Valeurs par défaut

De la même façon que vous pouvez passer None comme premier argument pour l'utiliser comme valeur par défaut, vous pouvez passer d'autres valeurs.

Disons que vous déclarez le paramètre q comme ayant une longueur minimale de 3, et une valeur par défaut étant "fixedquery" :

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: str = Query(default="fixedquery", min_length=3)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Rappel

Avoir une valeur par défaut rend le paramètre optionnel.

Rendre ce paramètre requis

Quand on ne déclare ni validation, ni métadonnée, on peut rendre le paramètre q requis en ne lui déclarant juste aucune valeur par défaut :

q: str

à la place de :

q: Union[str, None] = None

Mais maintenant, on déclare q avec Query, comme ceci :

q: Union[str, None] = Query(default=None, min_length=3)

Donc pour déclarer une valeur comme requise tout en utilisant Query, il faut utiliser ... comme premier argument :

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: str = Query(min_length=3)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Info

Si vous n'avez jamais vu ce ... auparavant : c'est une des constantes natives de Python appelée "Ellipsis".

Cela indiquera à FastAPI que la présence de ce paramètre est obligatoire.

Liste de paramètres / valeurs multiples via Query

Quand on définit un paramètre de requête explicitement avec Query on peut aussi déclarer qu'il reçoit une liste de valeur, ou des "valeurs multiples".

Par exemple, pour déclarer un paramètre de requête q qui peut apparaître plusieurs fois dans une URL, on écrit :

from typing import List, Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[List[str], None] = Query(default=None)):
    query_items = {"q": q}
    return query_items

Ce qui fait qu'avec une URL comme :

http://localhost:8000/items/?q=foo&q=bar

vous recevriez les valeurs des multiples paramètres de requête q (foo et bar) dans une list Python au sein de votre fonction de path operation, dans le paramètre de fonction q.

Donc la réponse de cette URL serait :

{
  "q": [
    "foo",
    "bar"
  ]
}

Astuce

Pour déclarer un paramètre de requête de type list, comme dans l'exemple ci-dessus, il faut explicitement utiliser Query, sinon cela sera interprété comme faisant partie du corps de la requête.

La documentation sera donc mise à jour automatiquement pour autoriser plusieurs valeurs :

Combiner liste de paramètres et valeurs par défaut

Et l'on peut aussi définir une liste de valeurs par défaut si aucune n'est fournie :

from typing import List

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: List[str] = Query(default=["foo", "bar"])):
    query_items = {"q": q}
    return query_items

Si vous allez à :

http://localhost:8000/items/

la valeur par défaut de q sera : ["foo", "bar"]

et la réponse sera :

{
  "q": [
    "foo",
    "bar"
  ]
}

Utiliser list

Il est aussi possible d'utiliser directement list plutôt que List[str] :

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: list = Query(default=[])):
    query_items = {"q": q}
    return query_items

Note

Dans ce cas-là, FastAPI ne vérifiera pas le contenu de la liste.

Par exemple, List[int] vérifiera (et documentera) que la liste est bien entièrement composée d'entiers. Alors qu'un simple list ne ferait pas cette vérification.

Déclarer des métadonnées supplémentaires

On peut aussi ajouter plus d'informations sur le paramètre.

Ces informations seront incluses dans le schéma OpenAPI généré et utilisées par la documentation interactive ou les outils externes utilisés.

Note

Gardez en tête que les outils externes utilisés ne supportent pas forcément tous parfaitement OpenAPI.

Il se peut donc que certains d'entre eux n'utilisent pas toutes les métadonnées que vous avez déclarées pour le moment, bien que dans la plupart des cas, les fonctionnalités manquantes ont prévu d'être implémentées.

Vous pouvez ajouter un title :

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(default=None, title="Query string", min_length=3)
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Et une description :

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=None,
        title="Query string",
        description="Query string for the items to search in the database that have a good match",
        min_length=3,
    )
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Alias de paramètres

Imaginez que vous vouliez que votre paramètre se nomme item-query.

Comme dans la requête :

http://127.0.0.1:8000/items/?item-query=foobaritems

Mais item-query n'est pas un nom de variable valide en Python.

Le nom le plus proche serait item_query.

Mais vous avez vraiment envie que ce soit exactement item-query...

Pour cela vous pouvez déclarer un alias, et cet alias est ce qui sera utilisé pour trouver la valeur du paramètre :

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, alias="item-query")):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Déprécier des paramètres

Disons que vous ne vouliez plus utiliser ce paramètre désormais.

Il faut qu'il continue à exister pendant un certain temps car vos clients l'utilisent, mais vous voulez que la documentation mentionne clairement que ce paramètre est déprécié.

On utilise alors l'argument deprecated=True de Query :

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=None,
        alias="item-query",
        title="Query string",
        description="Query string for the items to search in the database that have a good match",
        min_length=3,
        max_length=50,
        pattern="^fixedquery$",
        deprecated=True,
    )
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

La documentation le présentera comme il suit :

Pour résumer

Il est possible d'ajouter des validateurs et métadonnées pour vos paramètres.

Validateurs et métadonnées génériques:

  • alias
  • title
  • description
  • deprecated

Validateurs spécifiques aux chaînes de caractères :

  • min_length
  • max_length
  • regex

Parmi ces exemples, vous avez pu voir comment déclarer des validateurs pour les chaînes de caractères.

Dans les prochains chapitres, vous verrez comment déclarer des validateurs pour d'autres types, comme les nombres.