Aller au contenu

Paramètres de chemin

🌐 Translation by AI and humans

This translation was made by AI guided by humans. 🤝

It could have mistakes of misunderstanding the original meaning, or looking unnatural, etc. 🤖

You can improve this translation by helping us guide the AI LLM better.

English version

Vous pouvez déclarer des « paramètres » ou « variables » de chemin avec la même syntaxe utilisée par les chaînes de format Python :

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id):
    return {"item_id": item_id}

La valeur du paramètre de chemin item_id sera transmise à votre fonction dans l'argument item_id.

Donc, si vous exécutez cet exemple et allez sur http://127.0.0.1:8000/items/foo, vous verrez comme réponse :

{"item_id":"foo"}

Paramètres de chemin typés

Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type Python standard :

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}

Ici, item_id est déclaré comme int.

Vérifications

Cela vous apporte la prise en charge par l'éditeur dans votre fonction, avec vérifications d'erreurs, autocomplétion, etc.

Conversion de données

Si vous exécutez cet exemple et ouvrez votre navigateur sur http://127.0.0.1:8000/items/3, vous verrez comme réponse :

{"item_id":3}

Vérifications

Remarquez que la valeur reçue par votre fonction (et renvoyée) est 3, en tant qu'entier (int) Python, pas la chaîne de caractères « 3 ».

Ainsi, avec cette déclaration de type, FastAPI vous fournit automatiquement le « parsing » de la requête.

Validation de données

Mais si vous allez dans le navigateur sur http://127.0.0.1:8000/items/foo, vous verrez une belle erreur HTTP :

{
  "detail": [
    {
      "type": "int_parsing",
      "loc": [
        "path",
        "item_id"
      ],
      "msg": "Input should be a valid integer, unable to parse string as an integer",
      "input": "foo"
    }
  ]
}

car le paramètre de chemin item_id a pour valeur « foo », qui n'est pas un int.

La même erreur apparaîtrait si vous fournissiez un float au lieu d'un int, comme ici : http://127.0.0.1:8000/items/4.2

Vérifications

Ainsi, avec la même déclaration de type Python, FastAPI vous fournit la validation de données.

Remarquez que l'erreur indique clairement l'endroit exact où la validation n'a pas réussi.

C'est incroyablement utile lors du développement et du débogage du code qui interagit avec votre API.

Documentation

Et lorsque vous ouvrez votre navigateur sur http://127.0.0.1:8000/docs, vous verrez une documentation d'API automatique et interactive comme :

Vérifications

À nouveau, simplement avec cette même déclaration de type Python, FastAPI vous fournit une documentation interactive automatique (intégrant Swagger UI).

Remarquez que le paramètre de chemin est déclaré comme entier.

Les avantages d'une norme, documentation alternative

Et comme le schéma généré suit la norme OpenAPI, il existe de nombreux outils compatibles.

Grâce à cela, FastAPI fournit lui-même une documentation d'API alternative (utilisant ReDoc), accessible sur http://127.0.0.1:8000/redoc :

De la même façon, il existe de nombreux outils compatibles, y compris des outils de génération de code pour de nombreux langages.

Pydantic

Toute la validation de données est effectuée sous le capot par Pydantic, vous en bénéficiez donc pleinement. Vous savez ainsi que vous êtes entre de bonnes mains.

Vous pouvez utiliser les mêmes déclarations de type avec str, float, bool et de nombreux autres types de données complexes.

Plusieurs d'entre eux sont explorés dans les prochains chapitres du tutoriel.

L'ordre importe

Quand vous créez des chemins d'accès, vous pouvez vous retrouver dans une situation avec un chemin fixe.

Par exemple /users/me, disons pour récupérer les données de l'utilisateur actuel.

Et vous pouvez aussi avoir un chemin /users/{user_id} pour récupérer des données sur un utilisateur spécifique grâce à un identifiant d'utilisateur.

Comme les chemins d'accès sont évalués dans l'ordre, vous devez vous assurer que le chemin /users/me est déclaré avant celui de /users/{user_id} :

from fastapi import FastAPI

app = FastAPI()


@app.get("/users/me")
async def read_user_me():
    return {"user_id": "the current user"}


@app.get("/users/{user_id}")
async def read_user(user_id: str):
    return {"user_id": user_id}

Sinon, le chemin /users/{user_id} correspondrait aussi à /users/me, « pensant » qu'il reçoit un paramètre user_id avec la valeur « me ».

De même, vous ne pouvez pas redéfinir un chemin d'accès :

from fastapi import FastAPI

app = FastAPI()


@app.get("/users")
async def read_users():
    return ["Rick", "Morty"]


@app.get("/users")
async def read_users2():
    return ["Bean", "Elfo"]

Le premier sera toujours utilisé puisque le chemin correspond en premier.

Valeurs prédéfinies

Si vous avez un chemin d'accès qui reçoit un paramètre de chemin, mais que vous voulez que les valeurs possibles de ce paramètre de chemin soient prédéfinies, vous pouvez utiliser une Enum Python standard.

Créer une classe Enum

Importez Enum et créez une sous-classe qui hérite de str et de Enum.

En héritant de str, la documentation de l'API saura que les valeurs doivent être de type string et pourra donc s'afficher correctement.

Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs valides disponibles :

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

Astuce

Si vous vous demandez, « AlexNet », « ResNet » et « LeNet » sont juste des noms de modèles de Machine Learning.

Déclarer un paramètre de chemin

Créez ensuite un paramètre de chemin avec une annotation de type utilisant la classe d'énumération que vous avez créée (ModelName) :

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

Consulter la documentation

Comme les valeurs disponibles pour le paramètre de chemin sont prédéfinies, la documentation interactive peut les afficher clairement :

Travailler avec les énumérations Python

La valeur du paramètre de chemin sera un membre d'énumération.

Comparer des membres d'énumération

Vous pouvez le comparer avec le membre d'énumération dans votre enum ModelName :

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

Obtenir la valeur de l'énumération

Vous pouvez obtenir la valeur réelle (une str dans ce cas) avec model_name.value, ou en général, votre_membre_d_enum.value :

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

Astuce

Vous pouvez aussi accéder à la valeur « lenet » avec ModelName.lenet.value.

Retourner des membres d'énumération

Vous pouvez retourner des membres d'énumération depuis votre chemin d'accès, même imbriqués dans un corps JSON (par ex. un dict).

Ils seront convertis vers leurs valeurs correspondantes (des chaînes de caractères ici) avant d'être renvoyés au client :

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

Dans votre client, vous recevrez une réponse JSON comme :

{
  "model_name": "alexnet",
  "message": "Deep Learning FTW!"
}

Paramètres de chemin contenant des chemins

Disons que vous avez un chemin d'accès avec un chemin /files/{file_path}.

Mais vous avez besoin que file_path lui-même contienne un chemin, comme home/johndoe/myfile.txt.

Ainsi, l'URL pour ce fichier serait : /files/home/johndoe/myfile.txt.

Support d'OpenAPI

OpenAPI ne prend pas en charge une manière de déclarer un paramètre de chemin contenant un chemin à l'intérieur, car cela peut conduire à des scénarios difficiles à tester et à définir.

Néanmoins, vous pouvez toujours le faire dans FastAPI, en utilisant l'un des outils internes de Starlette.

Et la documentation fonctionnera quand même, même si aucune indication supplémentaire ne sera ajoutée pour dire que le paramètre doit contenir un chemin.

Convertisseur de chemin

En utilisant une option directement depuis Starlette, vous pouvez déclarer un paramètre de chemin contenant un chemin avec une URL comme :

/files/{file_path:path}

Dans ce cas, le nom du paramètre est file_path, et la dernière partie, :path, indique que le paramètre doit correspondre à n'importe quel chemin.

Vous pouvez donc l'utiliser ainsi :

from fastapi import FastAPI

app = FastAPI()


@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
    return {"file_path": file_path}

Astuce

Vous pourriez avoir besoin que le paramètre contienne /home/johndoe/myfile.txt, avec un slash initial (/).

Dans ce cas, l'URL serait : /files//home/johndoe/myfile.txt, avec un double slash (//) entre files et home.

Récapitulatif

Avec FastAPI, en utilisant des déclarations de type Python courtes, intuitives et standard, vous obtenez :

  • Support de l'éditeur : vérifications d'erreurs, autocomplétion, etc.
  • Données « parsing »
  • Validation de données
  • Annotations d'API et documentation automatique

Et vous n'avez besoin de les déclarer qu'une seule fois.

C'est probablement l'avantage visible principal de FastAPI comparé aux autres frameworks (outre les performances pures).