committed by
GitHub
36 changed files with 3477 additions and 156 deletions
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 11 KiB |
@ -0,0 +1,34 @@ |
|||
# Test de performance |
|||
|
|||
Les tests de performance de TechEmpower montrent que les applications **FastAPI** tournant sous Uvicorn comme <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">étant l'un des frameworks Python les plus rapides disponibles</a>, seulement inférieur à Starlette et Uvicorn (tous deux utilisés au cœur de FastAPI). (*) |
|||
|
|||
Mais en prêtant attention aux tests de performance et aux comparaisons, il faut tenir compte de ce qu'il suit. |
|||
|
|||
## Tests de performance et rapidité |
|||
|
|||
Lorsque vous vérifiez les tests de performance, il est commun de voir plusieurs outils de différents types comparés comme équivalents. |
|||
|
|||
En particulier, on voit Uvicorn, Starlette et FastAPI comparés (parmi de nombreux autres outils). |
|||
|
|||
Plus le problème résolu par un outil est simple, mieux seront les performances obtenues. Et la plupart des tests de performance ne prennent pas en compte les fonctionnalités additionnelles fournies par les outils. |
|||
|
|||
La hiérarchie est la suivante : |
|||
|
|||
* **Uvicorn** : un serveur ASGI |
|||
* **Starlette** : (utilise Uvicorn) un micro-framework web |
|||
* **FastAPI**: (utilise Starlette) un micro-framework pour API disposant de fonctionnalités additionnelles pour la création d'API, avec la validation des données, etc. |
|||
|
|||
* **Uvicorn** : |
|||
* A les meilleures performances, étant donné qu'il n'a pas beaucoup de code mis-à-part le serveur en lui-même. |
|||
* On n'écrit pas une application avec uniquement Uvicorn. Cela signifie que le code devrait inclure plus ou moins, au minimum, tout le code offert par Starlette (ou **FastAPI**). Et si on fait cela, l'application finale apportera les mêmes complications que si on avait utilisé un framework et que l'on avait minimisé la quantité de code et de bugs. |
|||
* Si on compare Uvicorn, il faut le comparer à d'autre applications de serveurs comme Daphne, Hypercorn, uWSGI, etc. |
|||
* **Starlette** : |
|||
* A les seconde meilleures performances après Uvicorn. Starlette utilise en réalité Uvicorn. De ce fait, il ne peut qu’être plus "lent" qu'Uvicorn car il requiert l'exécution de plus de code. |
|||
* Cependant il nous apporte les outils pour construire une application web simple, avec un routage basé sur des chemins, etc. |
|||
* Si on compare Starlette, il faut le comparer à d'autres frameworks web (ou micorframework) comme Sanic, Flask, Django, etc. |
|||
* **FastAPI** : |
|||
* Comme Starlette, FastAPI utilise Uvicorn et ne peut donc pas être plus rapide que ce dernier. |
|||
* FastAPI apporte des fonctionnalités supplémentaires à Starlette. Des fonctionnalités qui sont nécessaires presque systématiquement lors de la création d'une API, comme la validation des données, la sérialisation. En utilisant FastAPI, on obtient une documentation automatiquement (qui ne requiert aucune manipulation pour être mise en place). |
|||
* Si on n'utilisait pas FastAPI mais directement Starlette (ou un outil équivalent comme Sanic, Flask, Responder, etc) il faudrait implémenter la validation des données et la sérialisation par nous-même. Le résultat serait donc le même dans les deux cas mais du travail supplémentaire serait à réaliser avec Starlette, surtout en considérant que la validation des données et la sérialisation représentent la plus grande quantité de code à écrire dans une application. |
|||
* De ce fait, en utilisant FastAPI on minimise le temps de développement, les bugs, le nombre de lignes de code, et on obtient les mêmes performances (si ce n'est de meilleurs performances) que l'on aurait pu avoir sans ce framework (en ayant à implémenter de nombreuses fonctionnalités importantes par nous-mêmes). |
|||
* Si on compare FastAPI, il faut le comparer à d'autres frameworks web (ou ensemble d'outils) qui fournissent la validation des données, la sérialisation et la documentation, comme Flask-apispec, NestJS, Molten, etc. |
@ -0,0 +1,501 @@ |
|||
# Développement - Contribuer |
|||
|
|||
Tout d'abord, vous voudrez peut-être voir les moyens de base pour [aider FastAPI et obtenir de l'aide](help-fastapi.md){.internal-link target=_blank}. |
|||
|
|||
## Développement |
|||
|
|||
Si vous avez déjà cloné le dépôt et que vous savez que vous devez vous plonger dans le code, voici quelques directives pour mettre en place votre environnement. |
|||
|
|||
### Environnement virtuel avec `venv` |
|||
|
|||
Vous pouvez créer un environnement virtuel dans un répertoire en utilisant le module `venv` de Python : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ python -m venv env |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Cela va créer un répertoire `./env/` avec les binaires Python et vous pourrez alors installer des paquets pour cet environnement isolé. |
|||
|
|||
### Activer l'environnement |
|||
|
|||
Activez le nouvel environnement avec : |
|||
|
|||
=== "Linux, macOS" |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ source ./env/bin/activate |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
=== "Windows PowerShell" |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ .\env\Scripts\Activate.ps1 |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
=== "Windows Bash" |
|||
|
|||
Ou si vous utilisez Bash pour Windows (par exemple <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>): |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ source ./env/Scripts/activate |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Pour vérifier que cela a fonctionné, utilisez : |
|||
|
|||
=== "Linux, macOS, Windows Bash" |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ which pip |
|||
|
|||
some/directory/fastapi/env/bin/pip |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
=== "Windows PowerShell" |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ Get-Command pip |
|||
|
|||
some/directory/fastapi/env/bin/pip |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Si celui-ci montre le binaire `pip` à `env/bin/pip`, alors ça a fonctionné. 🎉 |
|||
|
|||
|
|||
|
|||
!!! tip |
|||
Chaque fois que vous installez un nouveau paquet avec `pip` sous cet environnement, activez à nouveau l'environnement. |
|||
|
|||
Cela permet de s'assurer que si vous utilisez un programme terminal installé par ce paquet (comme `flit`), vous utilisez celui de votre environnement local et pas un autre qui pourrait être installé globalement. |
|||
|
|||
### Flit |
|||
|
|||
**FastAPI** utilise <a href="https://flit.readthedocs.io/en/latest/index.html" class="external-link" target="_blank">Flit</a> pour build, packager et publier le projet. |
|||
|
|||
Après avoir activé l'environnement comme décrit ci-dessus, installez `flit` : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ pip install flit |
|||
|
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Réactivez maintenant l'environnement pour vous assurer que vous utilisez le "flit" que vous venez d'installer (et non un environnement global). |
|||
|
|||
Et maintenant, utilisez `flit` pour installer les dépendances de développement : |
|||
|
|||
=== "Linux, macOS" |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ flit install --deps develop --symlink |
|||
|
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
=== "Windows" |
|||
|
|||
Si vous êtes sous Windows, utilisez `--pth-file` au lieu de `--symlink` : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ flit install --deps develop --pth-file |
|||
|
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Il installera toutes les dépendances et votre FastAPI local dans votre environnement local. |
|||
|
|||
#### Utiliser votre FastAPI local |
|||
|
|||
Si vous créez un fichier Python qui importe et utilise FastAPI, et que vous l'exécutez avec le Python de votre environnement local, il utilisera votre code source FastAPI local. |
|||
|
|||
Et si vous mettez à jour le code source local de FastAPI, tel qu'il est installé avec `--symlink` (ou `--pth-file` sous Windows), lorsque vous exécutez à nouveau ce fichier Python, il utilisera la nouvelle version de FastAPI que vous venez d'éditer. |
|||
|
|||
De cette façon, vous n'avez pas à "installer" votre version locale pour pouvoir tester chaque changement. |
|||
|
|||
### Formatage |
|||
|
|||
Il existe un script que vous pouvez exécuter qui formatera et nettoiera tout votre code : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ bash scripts/format.sh |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Il effectuera également un tri automatique de touts vos imports. |
|||
|
|||
Pour qu'il puisse les trier correctement, vous devez avoir FastAPI installé localement dans votre environnement, avec la commande dans la section ci-dessus en utilisant `--symlink` (ou `--pth-file` sous Windows). |
|||
|
|||
### Formatage des imports |
|||
|
|||
Il existe un autre script qui permet de formater touts les imports et de s'assurer que vous n'avez pas d'imports inutilisés : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ bash scripts/format-imports.sh |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Comme il exécute une commande après l'autre et modifie et inverse de nombreux fichiers, il prend un peu plus de temps à s'exécuter, il pourrait donc être plus facile d'utiliser fréquemment `scripts/format.sh` et `scripts/format-imports.sh` seulement avant de commit. |
|||
|
|||
## Documentation |
|||
|
|||
Tout d'abord, assurez-vous que vous configurez votre environnement comme décrit ci-dessus, qui installera toutes les exigences. |
|||
|
|||
La documentation utilise <a href="https://www.mkdocs.org/" class="external-link" target="_blank">MkDocs</a>. |
|||
|
|||
Et il y a des outils/scripts supplémentaires en place pour gérer les traductions dans `./scripts/docs.py`. |
|||
|
|||
!!! tip |
|||
Vous n'avez pas besoin de voir le code dans `./scripts/docs.py`, vous l'utilisez simplement dans la ligne de commande. |
|||
|
|||
Toute la documentation est au format Markdown dans le répertoire `./docs/fr/`. |
|||
|
|||
De nombreux tutoriels comportent des blocs de code. |
|||
|
|||
Dans la plupart des cas, ces blocs de code sont de véritables applications complètes qui peuvent être exécutées telles quelles. |
|||
|
|||
En fait, ces blocs de code ne sont pas écrits à l'intérieur du Markdown, ce sont des fichiers Python dans le répertoire `./docs_src/`. |
|||
|
|||
Et ces fichiers Python sont inclus/injectés dans la documentation lors de la génération du site. |
|||
|
|||
### Documentation pour les tests |
|||
|
|||
La plupart des tests sont en fait effectués par rapport aux exemples de fichiers sources dans la documentation. |
|||
|
|||
Cela permet de s'assurer que : |
|||
|
|||
* La documentation est à jour. |
|||
* Les exemples de documentation peuvent être exécutés tels quels. |
|||
* La plupart des fonctionnalités sont couvertes par la documentation, assurées par la couverture des tests. |
|||
|
|||
Au cours du développement local, un script build le site et vérifie les changements éventuels, puis il est rechargé en direct : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ python ./scripts/docs.py live |
|||
|
|||
<span style="color: green;">[INFO]</span> Serving on http://127.0.0.1:8008 |
|||
<span style="color: green;">[INFO]</span> Start watching changes |
|||
<span style="color: green;">[INFO]</span> Start detecting changes |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Il servira la documentation sur `http://127.0.0.1:8008`. |
|||
|
|||
De cette façon, vous pouvez modifier la documentation/les fichiers sources et voir les changements en direct. |
|||
|
|||
#### Typer CLI (facultatif) |
|||
|
|||
Les instructions ici vous montrent comment utiliser le script à `./scripts/docs.py` avec le programme `python` directement. |
|||
|
|||
Mais vous pouvez également utiliser <a href="https://typer.tiangolo.com/typer-cli/" class="external-link" target="_blank">Typer CLI</a>, et vous obtiendrez l'auto-complétion dans votre terminal pour les commandes après l'achèvement de l'installation. |
|||
|
|||
Si vous installez Typer CLI, vous pouvez installer la complétion avec : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ typer --install-completion |
|||
|
|||
zsh completion installed in /home/user/.bashrc. |
|||
Completion will take effect once you restart the terminal. |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
### Apps et documentation en même temps |
|||
|
|||
Si vous exécutez les exemples avec, par exemple : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ uvicorn tutorial001:app --reload |
|||
|
|||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Comme Uvicorn utilisera par défaut le port `8000`, la documentation sur le port `8008` n'entrera pas en conflit. |
|||
|
|||
### Traductions |
|||
|
|||
L'aide aux traductions est TRÈS appréciée ! Et cela ne peut se faire sans l'aide de la communauté. 🌎 🚀 |
|||
|
|||
Voici les étapes à suivre pour aider à la traduction. |
|||
|
|||
#### Conseils et lignes directrices |
|||
|
|||
* Vérifiez les <a href="https://github.com/tiangolo/fastapi/pulls" class="external-link" target="_blank">pull requests existantes</a> pour votre langue et ajouter des reviews demandant des changements ou les approuvant. |
|||
|
|||
!!! tip |
|||
Vous pouvez <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request" class="external-link" target="_blank">ajouter des commentaires avec des suggestions de changement</a> aux pull requests existantes. |
|||
|
|||
Consultez les documents concernant <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-reviews" class="external-link" target="_blank">l'ajout d'un review de pull request</a> pour l'approuver ou demander des modifications. |
|||
|
|||
* Vérifiez dans <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">issues</a> pour voir s'il y a une personne qui coordonne les traductions pour votre langue. |
|||
|
|||
* Ajoutez une seule pull request par page traduite. Il sera ainsi beaucoup plus facile pour les autres de l'examiner. |
|||
|
|||
Pour les langues que je ne parle pas, je vais attendre plusieurs autres reviews de la traduction avant de merge. |
|||
|
|||
* Vous pouvez également vérifier s'il existe des traductions pour votre langue et y ajouter une review, ce qui m'aidera à savoir si la traduction est correcte et je pourrai la fusionner. |
|||
|
|||
* Utilisez les mêmes exemples en Python et ne traduisez que le texte des documents. Vous n'avez pas besoin de changer quoi que ce soit pour que cela fonctionne. |
|||
|
|||
* Utilisez les mêmes images, noms de fichiers et liens. Vous n'avez pas besoin de changer quoi que ce soit pour que cela fonctionne. |
|||
|
|||
* Pour vérifier le code à 2 lettres de la langue que vous souhaitez traduire, vous pouvez utiliser le tableau <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" class="external-link" target="_blank">Liste des codes ISO 639-1</a>. |
|||
|
|||
#### Langue existante |
|||
|
|||
Disons que vous voulez traduire une page pour une langue qui a déjà des traductions pour certaines pages, comme l'espagnol. |
|||
|
|||
Dans le cas de l'espagnol, le code à deux lettres est `es`. Ainsi, le répertoire des traductions espagnoles se trouve à l'adresse `docs/es/`. |
|||
|
|||
!!! tip |
|||
La langue principale ("officielle") est l'anglais, qui se trouve à l'adresse "docs/en/". |
|||
|
|||
Maintenant, lancez le serveur en live pour les documents en espagnol : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
// Use the command "live" and pass the language code as a CLI argument |
|||
$ python ./scripts/docs.py live es |
|||
|
|||
<span style="color: green;">[INFO]</span> Serving on http://127.0.0.1:8008 |
|||
<span style="color: green;">[INFO]</span> Start watching changes |
|||
<span style="color: green;">[INFO]</span> Start detecting changes |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Vous pouvez maintenant aller sur <a href="http://127.0.0.1:8008" class="external-link" target="_blank">http://127.0.0.1:8008</a> et voir vos changements en direct. |
|||
|
|||
Si vous regardez le site web FastAPI docs, vous verrez que chaque langue a toutes les pages. Mais certaines pages ne sont pas traduites et sont accompagnées d'une notification concernant la traduction manquante. |
|||
|
|||
Mais si vous le gérez localement de cette manière, vous ne verrez que les pages déjà traduites. |
|||
|
|||
Disons maintenant que vous voulez ajouter une traduction pour la section [Features](features.md){.internal-link target=_blank}. |
|||
|
|||
* Copiez le fichier à : |
|||
|
|||
``` |
|||
docs/en/docs/features.md |
|||
``` |
|||
|
|||
* Collez-le exactement au même endroit mais pour la langue que vous voulez traduire, par exemple : |
|||
|
|||
``` |
|||
docs/es/docs/features.md |
|||
``` |
|||
|
|||
!!! tip |
|||
Notez que le seul changement dans le chemin et le nom du fichier est le code de langue, qui passe de `en` à `es`. |
|||
|
|||
* Ouvrez maintenant le fichier de configuration de MkDocs pour l'anglais à |
|||
|
|||
``` |
|||
docs/en/docs/mkdocs.yml |
|||
``` |
|||
|
|||
* Trouvez l'endroit où cette `docs/features.md` se trouve dans le fichier de configuration. Quelque part comme : |
|||
|
|||
```YAML hl_lines="8" |
|||
site_name: FastAPI |
|||
# More stuff |
|||
nav: |
|||
- FastAPI: index.md |
|||
- Languages: |
|||
- en: / |
|||
- es: /es/ |
|||
- features.md |
|||
``` |
|||
|
|||
* Ouvrez le fichier de configuration MkDocs pour la langue que vous éditez, par exemple : |
|||
|
|||
``` |
|||
docs/es/docs/mkdocs.yml |
|||
``` |
|||
|
|||
* Ajoutez-le à l'endroit exact où il se trouvait pour l'anglais, par exemple : |
|||
|
|||
```YAML hl_lines="8" |
|||
site_name: FastAPI |
|||
# More stuff |
|||
nav: |
|||
- FastAPI: index.md |
|||
- Languages: |
|||
- en: / |
|||
- es: /es/ |
|||
- features.md |
|||
``` |
|||
|
|||
Assurez-vous que s'il y a d'autres entrées, la nouvelle entrée avec votre traduction est exactement dans le même ordre que dans la version anglaise. |
|||
|
|||
Si vous allez sur votre navigateur, vous verrez que maintenant les documents montrent votre nouvelle section. 🎉 |
|||
|
|||
Vous pouvez maintenant tout traduire et voir à quoi cela ressemble au fur et à mesure que vous enregistrez le fichier. |
|||
|
|||
#### Nouvelle langue |
|||
|
|||
Disons que vous voulez ajouter des traductions pour une langue qui n'est pas encore traduite, pas même quelques pages. |
|||
|
|||
Disons que vous voulez ajouter des traductions pour le Créole, et que ce n'est pas encore dans les documents. |
|||
|
|||
En vérifiant le lien ci-dessus, le code pour "Créole" est `ht`. |
|||
|
|||
L'étape suivante consiste à exécuter le script pour générer un nouveau répertoire de traduction : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
// Use the command new-lang, pass the language code as a CLI argument |
|||
$ python ./scripts/docs.py new-lang ht |
|||
|
|||
Successfully initialized: docs/ht |
|||
Updating ht |
|||
Updating en |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Vous pouvez maintenant vérifier dans votre éditeur de code le répertoire nouvellement créé `docs/ht/`. |
|||
|
|||
!!! tip |
|||
Créez une première demande d'extraction à l'aide de cette fonction, afin de configurer la nouvelle langue avant d'ajouter des traductions. |
|||
|
|||
Ainsi, d'autres personnes peuvent vous aider à rédiger d'autres pages pendant que vous travaillez sur la première. 🚀 |
|||
|
|||
Commencez par traduire la page principale, `docs/ht/index.md`. |
|||
|
|||
Vous pouvez ensuite continuer avec les instructions précédentes, pour une "langue existante". |
|||
|
|||
##### Nouvelle langue non prise en charge |
|||
|
|||
Si, lors de l'exécution du script du serveur en direct, vous obtenez une erreur indiquant que la langue n'est pas prise en charge, quelque chose comme : |
|||
|
|||
``` |
|||
raise TemplateNotFound(template) |
|||
jinja2.exceptions.TemplateNotFound: partials/language/xx.html |
|||
``` |
|||
|
|||
Cela signifie que le thème ne supporte pas cette langue (dans ce cas, avec un faux code de 2 lettres de `xx`). |
|||
|
|||
Mais ne vous inquiétez pas, vous pouvez définir la langue du thème en anglais et ensuite traduire le contenu des documents. |
|||
|
|||
Si vous avez besoin de faire cela, modifiez le fichier `mkdocs.yml` pour votre nouvelle langue, il aura quelque chose comme : |
|||
|
|||
```YAML hl_lines="5" |
|||
site_name: FastAPI |
|||
# More stuff |
|||
theme: |
|||
# More stuff |
|||
language: xx |
|||
``` |
|||
|
|||
Changez cette langue de `xx` (de votre code de langue) à `fr`. |
|||
|
|||
Vous pouvez ensuite relancer le serveur live. |
|||
|
|||
#### Prévisualisez le résultat |
|||
|
|||
Lorsque vous utilisez le script à `./scripts/docs.py` avec la commande `live`, il n'affiche que les fichiers et les traductions disponibles pour la langue courante. |
|||
|
|||
Mais une fois que vous avez terminé, vous pouvez tester le tout comme il le ferait en ligne. |
|||
|
|||
Pour ce faire, il faut d'abord construire tous les documents : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
// Use the command "build-all", this will take a bit |
|||
$ python ./scripts/docs.py build-all |
|||
|
|||
Updating es |
|||
Updating en |
|||
Building docs for: en |
|||
Building docs for: es |
|||
Successfully built docs for: es |
|||
Copying en index.md to README.md |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Cela génère tous les documents à `./docs_build/` pour chaque langue. Cela inclut l'ajout de tout fichier dont la traduction est manquante, avec une note disant que "ce fichier n'a pas encore de traduction". Mais vous n'avez rien à faire avec ce répertoire. |
|||
|
|||
Ensuite, il construit tous ces sites MkDocs indépendants pour chaque langue, les combine, et génère le résultat final à `./site/`. |
|||
|
|||
Ensuite, vous pouvez servir cela avec le commandement `serve`: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
// Use the command "serve" after running "build-all" |
|||
$ python ./scripts/docs.py serve |
|||
|
|||
Warning: this is a very simple server. For development, use mkdocs serve instead. |
|||
This is here only to preview a site with translations already built. |
|||
Make sure you run the build-all command first. |
|||
Serving at: http://127.0.0.1:8008 |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
## Tests |
|||
|
|||
Il existe un script que vous pouvez exécuter localement pour tester tout le code et générer des rapports de couverture en HTML : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ bash scripts/test-cov-html.sh |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Cette commande génère un répertoire `./htmlcov/`, si vous ouvrez le fichier `./htmlcov/index.html` dans votre navigateur, vous pouvez explorer interactivement les régions de code qui sont couvertes par les tests, et remarquer s'il y a une région manquante. |
@ -0,0 +1,80 @@ |
|||
# Tutoriel - Guide utilisateur - Introduction |
|||
|
|||
Ce tutoriel vous montre comment utiliser **FastAPI** avec la plupart de ses fonctionnalités, étape par étape. |
|||
|
|||
Chaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour résoudre vos besoins spécifiques en matière d'API. |
|||
|
|||
Il est également conçu pour fonctionner comme une référence future. |
|||
|
|||
Vous pouvez donc revenir et voir exactement ce dont vous avez besoin. |
|||
|
|||
## Exécuter le code |
|||
|
|||
Tous les blocs de code peuvent être copiés et utilisés directement (il s'agit en fait de fichiers Python testés). |
|||
|
|||
Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et commencez `uvicorn` avec : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ uvicorn main:app --reload |
|||
|
|||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) |
|||
<span style="color: green;">INFO</span>: Started reloader process [28720] |
|||
<span style="color: green;">INFO</span>: Started server process [28722] |
|||
<span style="color: green;">INFO</span>: Waiting for application startup. |
|||
<span style="color: green;">INFO</span>: Application startup complete. |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Il est **FORTEMENT encouragé** que vous écriviez ou copiez le code, l'éditiez et l'exécutiez localement. |
|||
|
|||
L'utiliser dans votre éditeur est ce qui vous montre vraiment les avantages de FastAPI, en voyant le peu de code que vous avez à écrire, toutes les vérifications de type, l'autocomplétion, etc. |
|||
|
|||
--- |
|||
|
|||
## Installer FastAPI |
|||
|
|||
La première étape consiste à installer FastAPI. |
|||
|
|||
Pour le tutoriel, vous voudrez peut-être l'installer avec toutes les dépendances et fonctionnalités optionnelles : |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ pip install fastapi[all] |
|||
|
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
... qui comprend également `uvicorn`, que vous pouvez utiliser comme serveur pour exécuter votre code. |
|||
|
|||
!!! note |
|||
Vous pouvez également l'installer pièce par pièce. |
|||
|
|||
C'est ce que vous feriez probablement une fois que vous voudrez déployer votre application en production : |
|||
|
|||
``` |
|||
pip install fastapi |
|||
``` |
|||
|
|||
Installez également `uvicorn` pour qu'il fonctionne comme serveur : |
|||
|
|||
``` |
|||
pip install uvicorn |
|||
``` |
|||
|
|||
Et la même chose pour chacune des dépendances facultatives que vous voulez utiliser. |
|||
|
|||
## Guide utilisateur avancé |
|||
|
|||
Il existe également un **Guide d'utilisation avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide d'utilisation**. |
|||
|
|||
Le **Guide d'utilisation avancé**, qui s'appuie sur cette base, utilise les mêmes concepts et vous apprend quelques fonctionnalités supplémentaires. |
|||
|
|||
Mais vous devez d'abord lire le **Tutoriel - Guide d'utilisation** (ce que vous êtes en train de lire en ce moment). |
|||
|
|||
Il est conçu pour que vous puissiez construire une application complète avec seulement le **Tutoriel - Guide d'utilisation**, puis l'étendre de différentes manières, en fonction de vos besoins, en utilisant certaines des idées supplémentaires du **Guide d'utilisation avancé**. |
@ -0,0 +1,305 @@ |
|||
# 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 : |
|||
|
|||
```Python hl_lines="9" |
|||
{!../../../docs_src/query_params_str_validations/tutorial001.py!} |
|||
``` |
|||
|
|||
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` : |
|||
|
|||
```Python hl_lines="3" |
|||
{!../../../docs_src/query_params_str_validations/tutorial002.py!} |
|||
``` |
|||
|
|||
## 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` : |
|||
|
|||
```Python hl_lines="9" |
|||
{!../../../docs_src/query_params_str_validations/tutorial002.py!} |
|||
``` |
|||
|
|||
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 : |
|||
|
|||
```Python |
|||
q: Union[str, None] = Query(default=None) |
|||
``` |
|||
|
|||
... rend le paramètre optionnel, et est donc équivalent à : |
|||
|
|||
```Python |
|||
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 : |
|||
|
|||
```Python |
|||
= None |
|||
``` |
|||
|
|||
ou : |
|||
|
|||
```Python |
|||
= 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 : |
|||
|
|||
```Python |
|||
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` : |
|||
|
|||
```Python hl_lines="9" |
|||
{!../../../docs_src/query_params_str_validations/tutorial003.py!} |
|||
``` |
|||
|
|||
## Ajouter des validations par expressions régulières |
|||
|
|||
On peut définir une <abbr title="Une expression régulière, regex ou regexp est une suite de caractères qui définit un pattern de correspondance pour les chaînes de caractères.">expression régulière</abbr> à laquelle le paramètre doit correspondre : |
|||
|
|||
```Python hl_lines="10" |
|||
{!../../../docs_src/query_params_str_validations/tutorial004.py!} |
|||
``` |
|||
|
|||
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"` : |
|||
|
|||
```Python hl_lines="7" |
|||
{!../../../docs_src/query_params_str_validations/tutorial005.py!} |
|||
``` |
|||
|
|||
!!! note "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 : |
|||
|
|||
```Python |
|||
q: str |
|||
``` |
|||
|
|||
à la place de : |
|||
|
|||
```Python |
|||
q: Union[str, None] = None |
|||
``` |
|||
|
|||
Mais maintenant, on déclare `q` avec `Query`, comme ceci : |
|||
|
|||
```Python |
|||
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 : |
|||
|
|||
```Python hl_lines="7" |
|||
{!../../../docs_src/query_params_str_validations/tutorial006.py!} |
|||
``` |
|||
|
|||
!!! info |
|||
Si vous n'avez jamais vu ce `...` auparavant : c'est une des constantes natives de Python <a href="https://docs.python.org/fr/3/library/constants.html#Ellipsis" class="external-link" target="_blank">appelée "Ellipsis"</a>. |
|||
|
|||
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 : |
|||
|
|||
```Python hl_lines="9" |
|||
{!../../../docs_src/query_params_str_validations/tutorial011.py!} |
|||
``` |
|||
|
|||
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 : |
|||
|
|||
```JSON |
|||
{ |
|||
"q": [ |
|||
"foo", |
|||
"bar" |
|||
] |
|||
} |
|||
``` |
|||
|
|||
!!! tip "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 : |
|||
|
|||
<img src="/img/tutorial/query-params-str-validations/image02.png"> |
|||
|
|||
### 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 : |
|||
|
|||
```Python hl_lines="9" |
|||
{!../../../docs_src/query_params_str_validations/tutorial012.py!} |
|||
``` |
|||
|
|||
Si vous allez à : |
|||
|
|||
``` |
|||
http://localhost:8000/items/ |
|||
``` |
|||
|
|||
la valeur par défaut de `q` sera : `["foo", "bar"]` |
|||
|
|||
et la réponse sera : |
|||
|
|||
```JSON |
|||
{ |
|||
"q": [ |
|||
"foo", |
|||
"bar" |
|||
] |
|||
} |
|||
``` |
|||
|
|||
#### Utiliser `list` |
|||
|
|||
Il est aussi possible d'utiliser directement `list` plutôt que `List[str]` : |
|||
|
|||
```Python hl_lines="7" |
|||
{!../../../docs_src/query_params_str_validations/tutorial013.py!} |
|||
``` |
|||
|
|||
!!! 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` : |
|||
|
|||
```Python hl_lines="10" |
|||
{!../../../docs_src/query_params_str_validations/tutorial007.py!} |
|||
``` |
|||
|
|||
Et une `description` : |
|||
|
|||
```Python hl_lines="13" |
|||
{!../../../docs_src/query_params_str_validations/tutorial008.py!} |
|||
``` |
|||
|
|||
## 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 : |
|||
|
|||
```Python hl_lines="9" |
|||
{!../../../docs_src/query_params_str_validations/tutorial009.py!} |
|||
``` |
|||
|
|||
## 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 <abbr title="obsolète, recommandé de ne pas l'utiliser">déprécié</abbr>. |
|||
|
|||
On utilise alors l'argument `deprecated=True` de `Query` : |
|||
|
|||
```Python hl_lines="18" |
|||
{!../../../docs_src/query_params_str_validations/tutorial010.py!} |
|||
``` |
|||
|
|||
La documentation le présentera comme il suit : |
|||
|
|||
<img src="/img/tutorial/query-params-str-validations/image01.png"> |
|||
|
|||
## 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. |
@ -0,0 +1,404 @@ |
|||
# 동시성과 async / await |
|||
|
|||
*경로 작동 함수*에서의 `async def` 문법에 대한 세부사항과 비동기 코드, 동시성 및 병렬성에 대한 배경 |
|||
|
|||
## <a name="in-a-hurry"></a>바쁘신 경우 |
|||
|
|||
<strong>요약</strong> |
|||
|
|||
다음과 같이 `await`를 사용해 호출하는 제3의 라이브러리를 사용하는 경우: |
|||
|
|||
```Python |
|||
results = await some_library() |
|||
``` |
|||
|
|||
다음처럼 *경로 작동 함수*를 `async def`를 사용해 선언하십시오: |
|||
|
|||
```Python hl_lines="2" |
|||
@app.get('/') |
|||
async def read_results(): |
|||
results = await some_library() |
|||
return results |
|||
``` |
|||
|
|||
!!! note "참고" |
|||
`async def`로 생성된 함수 내부에서만 `await`를 사용할 수 있습니다. |
|||
|
|||
--- |
|||
|
|||
데이터베이스, API, 파일시스템 등과 의사소통하는 제3의 라이브러리를 사용하고, 그것이 `await`를 지원하지 않는 경우(현재 거의 모든 데이터베이스 라이브러리가 그러합니다), *경로 작동 함수*를 일반적인 `def`를 사용해 선언하십시오: |
|||
|
|||
```Python hl_lines="2" |
|||
@app.get('/') |
|||
def results(): |
|||
results = some_library() |
|||
return results |
|||
``` |
|||
|
|||
--- |
|||
|
|||
만약 당신의 응용프로그램이 (어째서인지) 다른 무엇과 의사소통하고 그것이 응답하기를 기다릴 필요가 없다면 `async def`를 사용하십시오. |
|||
|
|||
--- |
|||
|
|||
모르겠다면, 그냥 `def`를 사용하십시오. |
|||
|
|||
--- |
|||
|
|||
**참고**: *경로 작동 함수*에서 필요한만큼 `def`와 `async def`를 혼용할 수 있고, 가장 알맞은 것을 선택해서 정의할 수 있습니다. FastAPI가 자체적으로 알맞은 작업을 수행할 것입니다. |
|||
|
|||
어찌되었든, 상기 어떠한 경우라도, FastAPI는 여전히 비동기적으로 작동하고 매우 빠릅니다. |
|||
|
|||
그러나 상기 작업을 수행함으로써 어느 정도의 성능 최적화가 가능합니다. |
|||
|
|||
## 기술적 세부사항 |
|||
|
|||
최신 파이썬 버전은 `async`와 `await` 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다. |
|||
|
|||
아래 섹션들에서 해당 문장을 부분별로 살펴보겠습니다: |
|||
|
|||
* **비동기 코드** |
|||
* **`async`와 `await`** |
|||
* **코루틴** |
|||
|
|||
## 비동기 코드 |
|||
|
|||
비동기 코드란 언어 💬 가 코드의 어느 한 부분에서, 컴퓨터 / 프로그램🤖에게 *다른 무언가*가 어딘가에서 끝날 때까지 기다려야한다고 말하는 방식입니다. *다른 무언가*가 “느린-파일" 📝 이라고 불린다고 가정해봅시다. |
|||
|
|||
따라서 “느린-파일” 📝이 끝날때까지 컴퓨터는 다른 작업을 수행할 수 있습니다. |
|||
|
|||
그 다음 컴퓨터 / 프로그램 🤖 은 다시 기다리고 있기 때문에 기회가 있을 때마다 다시 돌아오거나, 혹은 당시에 수행해야하는 작업들이 완료될 때마다 다시 돌아옵니다. 그리고 그것 🤖 은 기다리고 있던 작업 중 어느 것이 이미 완료되었는지, 그것 🤖 이 해야하는 모든 작업을 수행하면서 확인합니다. |
|||
|
|||
다음으로, 그것 🤖 은 완료할 첫번째 작업에 착수하고(우리의 "느린-파일" 📝 이라고 가정합시다) 그에 대해 수행해야하는 작업을 계속합니다. |
|||
|
|||
"다른 무언가를 기다리는 것"은 일반적으로 비교적 "느린" (프로세서와 RAM 메모리 속도에 비해) <abbr title="Input and Output">I/O</abbr> 작업을 의미합니다. 예를 들면 다음의 것들을 기다리는 것입니다: |
|||
|
|||
* 네트워크를 통해 클라이언트로부터 전송되는 데이터 |
|||
* 네트워크를 통해 클라이언트가 수신할, 당신의 프로그램으로부터 전송되는 데이터 |
|||
* 시스템이 읽고 프로그램에 전달할 디스크 내의 파일 내용 |
|||
* 당신의 프로그램이 시스템에 전달하는, 디스크에 작성될 내용 |
|||
* 원격 API 작업 |
|||
* 완료될 데이터베이스 작업 |
|||
* 결과를 반환하는 데이터베이스 쿼리 |
|||
* 기타 |
|||
|
|||
수행 시간의 대부분이 <abbr title="Input and Output">I/O</abbr> 작업을 기다리는데에 소요되기 때문에, "I/O에 묶인" 작업이라고 불립니다. |
|||
|
|||
이것은 "비동기"라고 불리는데 컴퓨터 / 프로그램이 작업 결과를 가지고 일을 수행할 수 있도록, 느린 작업에 "동기화"되어 아무것도 하지 않으면서 작업이 완료될 정확한 시점만을 기다릴 필요가 없기 때문입니다. |
|||
|
|||
이 대신에, "비동기" 시스템에서는, 작업은 일단 완료되면, 컴퓨터 / 프로그램이 수행하고 있는 일을 완료하고 이후 다시 돌아와서 그것의 결과를 받아 이를 사용해 작업을 지속할 때까지 잠시 (몇 마이크로초) 대기할 수 있습니다. |
|||
|
|||
"동기"("비동기"의 반대)는 컴퓨터 / 프로그램이 상이한 작업들간 전환을 하기 전에 그것이 대기를 동반하게 될지라도 모든 순서를 따르기 때문에 "순차"라는 용어로도 흔히 불립니다. |
|||
|
|||
### 동시성과 버거 |
|||
|
|||
위에서 설명한 **비동기** 코드에 대한 개념은 종종 **"동시성"**이라고도 불립니다. 이것은 **"병렬성"**과는 다릅니다. |
|||
|
|||
**동시성**과 **병렬성**은 모두 "동시에 일어나는 서로 다른 일들"과 관련이 있습니다. |
|||
|
|||
하지만 *동시성*과 *병렬성*의 세부적인 개념에는 꽤 차이가 있습니다. |
|||
|
|||
차이를 확인하기 위해, 다음의 버거에 대한 이야기를 상상해보십시오: |
|||
|
|||
### 동시 버거 |
|||
|
|||
당신은 짝사랑 상대 😍 와 패스트푸드 🍔 를 먹으러 갔습니다. 당신은 점원 💁 이 당신 앞에 있는 사람들의 주문을 받을 동안 줄을 서서 기다리고 있습니다. |
|||
|
|||
이제 당신의 순서가 되어서, 당신은 당신과 짝사랑 상대 😍 를 위한 두 개의 고급스러운 버거 🍔 를 주문합니다. |
|||
|
|||
당신이 돈을 냅니다 💸. |
|||
|
|||
점원 💁 은 주방 👨🍳 에 요리를 하라고 전달하고, 따라서 그들은 당신의 버거 🍔 를 준비해야한다는 사실을 알게됩니다(그들이 지금은 당신 앞 고객들의 주문을 준비하고 있을지라도 말입니다). |
|||
|
|||
점원 💁 은 당신의 순서가 적힌 번호표를 줍니다. |
|||
|
|||
기다리는 동안, 당신은 짝사랑 상대 😍 와 함께 테이블을 고르고, 자리에 앉아 오랫동안 (당신이 주문한 버거는 꽤나 고급스럽기 때문에 준비하는데 시간이 조금 걸립니다 ✨🍔✨) 대화를 나눕니다. |
|||
|
|||
짝사랑 상대 😍 와 테이블에 앉아서 버거 🍔 를 기다리는 동안, 그 사람 😍 이 얼마나 멋지고, 사랑스럽고, 똑똑한지 감탄하며 시간을 보냅니다 ✨😍✨. |
|||
|
|||
짝사랑 상대 😍 와 기다리면서 얘기하는 동안, 때때로, 당신은 당신의 차례가 되었는지 보기 위해 카운터의 번호를 확인합니다. |
|||
|
|||
그러다 어느 순간, 당신의 차례가 됩니다. 카운터에 가서, 버거 🍔 를 받고, 테이블로 다시 돌아옵니다. |
|||
|
|||
당신과 짝사랑 상대 😍 는 버거 🍔 를 먹으며 좋은 시간을 보냅니다 ✨. |
|||
|
|||
--- |
|||
|
|||
당신이 이 이야기에서 컴퓨터 / 프로그램 🤖 이라고 상상해보십시오. |
|||
|
|||
줄을 서서 기다리는 동안, 당신은 아무것도 하지 않고 😴 당신의 차례를 기다리며, 어떠한 "생산적인" 일도 하지 않습니다. 하지만 점원 💁 이 (음식을 준비하지는 않고) 주문을 받기만 하기 때문에 줄이 빨리 줄어들어서 괜찮습니다. |
|||
|
|||
그다음, 당신이 차례가 오면, 당신은 실제로 "생산적인" 일 🤓 을 합니다. 당신은 메뉴를 보고, 무엇을 먹을지 결정하고, 짝사랑 상대 😍 의 선택을 묻고, 돈을 내고 💸 , 맞는 카드를 냈는지 확인하고, 비용이 제대로 지불되었는지 확인하고, 주문이 제대로 들어갔는지 확인을 하는 작업 등등을 수행합니다. |
|||
|
|||
하지만 이후에는, 버거 🍔 를 아직 받지 못했음에도, 버거가 준비될 때까지 기다려야 🕙 하기 때문에 점원 💁 과의 작업은 "일시정지" ⏸ 상태입니다. |
|||
|
|||
하지만 번호표를 받고 카운터에서 나와 테이블에 앉으면, 당신은 짝사랑 상대 😍 와 그 "작업" ⏯ 🤓 에 번갈아가며 🔀 집중합니다. 그러면 당신은 다시 짝사랑 상대 😍 에게 작업을 거는 매우 "생산적인" 일 🤓 을 합니다. |
|||
|
|||
점원 💁 이 카운터 화면에 당신의 번호를 표시함으로써 "버거 🍔 가 준비되었습니다"라고 해도, 당신은 즉시 뛰쳐나가지는 않을 것입니다. 당신은 당신의 번호를 갖고있고, 다른 사람들은 그들의 번호를 갖고있기 때문에, 아무도 당신의 버거 🍔 를 훔쳐가지 않는다는 사실을 알기 때문입니다. |
|||
|
|||
그래서 당신은 짝사랑 상대 😍 가 이야기를 끝낼 때까지 기다린 후 (현재 작업 완료 ⏯ / 진행 중인 작업 처리 🤓 ), 정중하게 미소짓고 버거를 가지러 가겠다고 말합니다 ⏸. |
|||
|
|||
그다음 당신은 카운터에 가서 🔀 , 초기 작업을 이제 완료하고 ⏯ , 버거 🍔 를 받고, 감사하다고 말하고 테이블로 가져옵니다. 이로써 카운터와의 상호작용 단계 / 작업이 종료됩니다 ⏹. |
|||
|
|||
이전 작업인 "버거 받기"가 종료되면 ⏹ "버거 먹기"라는 새로운 작업이 생성됩니다 🔀 ⏯. |
|||
|
|||
### 병렬 버거 |
|||
|
|||
이제 "동시 버거"가 아닌 "병렬 버거"를 상상해보십시오. |
|||
|
|||
당신은 짝사랑 상대 😍 와 함께 병렬 패스트푸드 🍔 를 먹으러 갔습니다. |
|||
|
|||
당신은 여러명(8명이라고 가정합니다)의 점원이 당신 앞 사람들의 주문을 받으며 동시에 요리 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 도 하는 동안 줄을 서서 기다립니다. |
|||
|
|||
당신 앞 모든 사람들이 버거가 준비될 때까지 카운터에서 떠나지 않고 기다립니다 🕙 . 왜냐하면 8명의 직원들이 다음 주문을 받기 전에 버거를 준비하러 가기 때문입니다. |
|||
|
|||
마침내 당신의 차례가 왔고, 당신은 당신과 짝사랑 상대 😍 를 위한 두 개의 고급스러운 버거 🍔 를 주문합니다. |
|||
|
|||
당신이 비용을 지불합니다 💸 . |
|||
|
|||
점원이 주방에 갑니다 👨🍳 . |
|||
|
|||
당신은 번호표가 없기 때문에 누구도 당신의 버거 🍔 를 대신 가져갈 수 없도록 카운터에 서서 기다립니다 🕙 . |
|||
|
|||
당신과 짝사랑 상대 😍 는 다른 사람이 새치기해서 버거를 가져가지 못하게 하느라 바쁘기 때문에 🕙 , 짝사랑 상대에게 주의를 기울일 수 없습니다 😞 . |
|||
|
|||
이것은 "동기" 작업이고, 당신은 점원/요리사 👨🍳 와 "동기화" 되었습니다. 당신은 기다리고 🕙 , 점원/요리사 👨🍳 가 버거 🍔 준비를 완료한 후 당신에게 주거나, 누군가가 그것을 가져가는 그 순간에 그 곳에 있어야합니다. |
|||
|
|||
카운터 앞에서 오랫동안 기다린 후에 🕙 , 점원/요리사 👨🍳 가 당신의 버거 🍔 를 가지고 돌아옵니다. |
|||
|
|||
당신은 버거를 받고 짝사랑 상대와 함께 테이블로 돌아옵니다. |
|||
|
|||
단지 먹기만 하다가, 다 먹었습니다 🍔 ⏹. |
|||
|
|||
카운터 앞에서 기다리면서 🕙 너무 많은 시간을 허비했기 때문에 대화를 하거나 작업을 걸 시간이 거의 없었습니다 😞 . |
|||
|
|||
--- |
|||
|
|||
이 병렬 버거 시나리오에서, 당신은 기다리고 🕙 , 오랜 시간동안 "카운터에서 기다리는" 🕙 데에 주의를 기울이는 ⏯ 두 개의 프로세서(당신과 짝사랑 상대😍)를 가진 컴퓨터 / 프로그램 🤖 입니다. |
|||
|
|||
패스트푸드점에는 8개의 프로세서(점원/요리사) 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 가 있습니다. 동시 버거는 단 두 개(한 명의 직원과 한 명의 요리사) 💁 👨🍳 만을 가지고 있었습니다. |
|||
|
|||
하지만 여전히, 병렬 버거 예시가 최선은 아닙니다 😞 . |
|||
|
|||
--- |
|||
|
|||
이 예시는 버거🍔 이야기와 결이 같습니다. |
|||
|
|||
더 "현실적인" 예시로, 은행을 상상해보십시오. |
|||
|
|||
최근까지, 대다수의 은행에는 다수의 은행원들 👨💼👨💼👨💼👨💼 과 긴 줄 🕙🕙🕙🕙🕙🕙🕙🕙 이 있습니다. |
|||
|
|||
모든 은행원들은 한 명 한 명의 고객들을 차례로 상대합니다 👨💼⏯ . |
|||
|
|||
그리고 당신은 오랫동안 줄에서 기다려야하고 🕙 , 그렇지 않으면 당신의 차례를 잃게 됩니다. |
|||
|
|||
아마 당신은 은행 🏦 심부름에 짝사랑 상대 😍 를 데려가고 싶지는 않을 것입니다. |
|||
|
|||
### 버거 예시의 결론 |
|||
|
|||
"짝사랑 상대와의 패스트푸드점 버거" 시나리오에서, 오랜 기다림 🕙 이 있기 때문에 동시 시스템 ⏸🔀⏯ 을 사용하는 것이 더 합리적입니다. |
|||
|
|||
대다수의 웹 응용프로그램의 경우가 그러합니다. |
|||
|
|||
매우 많은 수의 유저가 있지만, 서버는 그들의 요청을 전송하기 위해 그닥-좋지-않은 연결을 기다려야 합니다 🕙 . |
|||
|
|||
그리고 응답이 돌아올 때까지 다시 기다려야 합니다 🕙 . |
|||
|
|||
이 "기다림" 🕙 은 마이크로초 단위이지만, 모두 더해지면, 결국에는 매우 긴 대기시간이 됩니다. |
|||
|
|||
따라서 웹 API를 위해 비동기 ⏸🔀⏯ 코드를 사용하는 것이 합리적입니다. |
|||
|
|||
대부분의 존재하는 유명한 파이썬 프레임워크 (Flask와 Django 등)은 새로운 비동기 기능들이 파이썬에 존재하기 전에 만들어졌습니다. 그래서, 그들의 배포 방식은 병렬 실행과 새로운 기능만큼 강력하지는 않은 예전 버전의 비동기 실행을 지원합니다. |
|||
|
|||
비동기 웹 파이썬(ASGI)에 대한 주요 명세가 웹소켓을 지원하기 위해 Django에서 개발 되었음에도 그렇습니다. |
|||
|
|||
이러한 종류의 비동기성은 (NodeJS는 병렬적이지 않음에도) NodeJS가 사랑받는 이유이고, 프로그래밍 언어로서의 Go의 강점입니다. |
|||
|
|||
그리고 **FastAPI**를 사용함으로써 동일한 성능을 낼 수 있습니다. |
|||
|
|||
또한 병렬성과 비동기성을 동시에 사용할 수 있기 때문에, 대부분의 테스트가 완료된 NodeJS 프레임워크보다 더 높은 성능을 얻고 C에 더 가까운 컴파일 언어인 Go와 동등한 성능을 얻을 수 있습니다<a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(모두 Starlette 덕분입니다)</a>. |
|||
|
|||
### 동시성이 병렬성보다 더 나은가? |
|||
|
|||
그렇지 않습니다! 그것이 이야기의 교훈은 아닙니다. |
|||
|
|||
동시성은 병렬성과 다릅니다. 그리고 그것은 많은 대기를 필요로하는 **특정한** 시나리오에서는 더 낫습니다. 이로 인해, 웹 응용프로그램 개발에서 동시성이 병렬성보다 일반적으로 훨씬 낫습니다. 하지만 모든 경우에 그런 것은 아닙니다. |
|||
|
|||
따라서, 균형을 맞추기 위해, 다음의 짧은 이야기를 상상해보십시오: |
|||
|
|||
> 당신은 크고, 더러운 집을 청소해야합니다. |
|||
|
|||
*네, 이게 전부입니다*. |
|||
|
|||
--- |
|||
|
|||
어디에도 대기 🕙 는 없고, 집안 곳곳에서 해야하는 많은 작업들만 있습니다. |
|||
|
|||
버거 예시처럼 처음에는 거실, 그 다음은 부엌과 같은 식으로 순서를 정할 수도 있으나, 무엇도 기다리지 🕙 않고 계속해서 청소 작업만 수행하기 때문에, 순서는 아무런 영향을 미치지 않습니다. |
|||
|
|||
순서가 있든 없든 동일한 시간이 소요될 것이고(동시성) 동일한 양의 작업을 하게 될 것입니다. |
|||
|
|||
하지만 이 경우에서, 8명의 전(前)-점원/요리사이면서-현(現)-청소부 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 를 고용할 수 있고, 그들 각자(그리고 당신)가 집의 한 부분씩 맡아 청소를 한다면, 당신은 **병렬적**으로 작업을 수행할 수 있고, 조금의 도움이 있다면, 훨씬 더 빨리 끝낼 수 있습니다. |
|||
|
|||
이 시나리오에서, (당신을 포함한) 각각의 청소부들은 프로세서가 될 것이고, 각자의 역할을 수행합니다. |
|||
|
|||
실행 시간의 대부분이 대기가 아닌 실제 작업에 소요되고, 컴퓨터에서 작업은 <abbr title="Central Processing Unit">CPU</abbr>에서 이루어지므로, 이러한 문제를 "CPU에 묶였"다고 합니다. |
|||
|
|||
--- |
|||
|
|||
CPU에 묶인 연산에 관한 흔한 예시는 복잡한 수학 처리를 필요로 하는 경우입니다. |
|||
|
|||
예를 들어: |
|||
|
|||
* **오디오** 또는 **이미지** 처리. |
|||
* **컴퓨터 비전**: 하나의 이미지는 수백개의 픽셀로 구성되어있고, 각 픽셀은 3개의 값 / 색을 갖고 있으며, 일반적으로 해당 픽셀들에 대해 동시에 무언가를 계산해야하는 처리. |
|||
* **머신러닝**: 일반적으로 많은 "행렬"과 "벡터" 곱셈이 필요합니다. 거대한 스프레드 시트에 수들이 있고 그 수들을 동시에 곱해야 한다고 생각해보십시오. |
|||
* **딥러닝**: 머신러닝의 하위영역으로, 동일한 예시가 적용됩니다. 단지 이 경우에는 하나의 스프레드 시트에 곱해야할 수들이 있는 것이 아니라, 거대한 세트의 스프레드 시트들이 있고, 많은 경우에, 이 모델들을 만들고 사용하기 위해 특수한 프로세서를 사용합니다. |
|||
|
|||
### 동시성 + 병렬성: 웹 + 머신러닝 |
|||
|
|||
**FastAPI**를 사용하면 웹 개발에서는 매우 흔한 동시성의 이점을 (NodeJS의 주된 매력만큼) 얻을 수 있습니다. |
|||
|
|||
뿐만 아니라 머신러닝 시스템과 같이 **CPU에 묶인** 작업을 위해 병렬성과 멀티프로세싱(다수의 프로세스를 병렬적으로 동작시키는 것)을 이용하는 것도 가능합니다. |
|||
|
|||
파이썬이 **데이터 사이언스**, 머신러닝과 특히 딥러닝에 의 주된 언어라는 간단한 사실에 더해서, 이것은 FastAPI를 데이터 사이언스 / 머신러닝 웹 API와 응용프로그램에 (다른 것들보다) 좋은 선택지가 되게 합니다. |
|||
|
|||
배포시 병렬을 어떻게 가능하게 하는지 알고싶다면, [배포](/ko/deployment){.internal-link target=_blank}문서를 참고하십시오. |
|||
|
|||
## `async`와 `await` |
|||
|
|||
최신 파이썬 버전에는 비동기 코드를 정의하는 매우 직관적인 방법이 있습니다. 이는 이것을 평범한 "순차적" 코드로 보이게 하고, 적절한 순간에 당신을 위해 "대기"합니다. |
|||
|
|||
연산이 결과를 전달하기 전에 대기를 해야하고 새로운 파이썬 기능들을 지원한다면, 이렇게 코드를 작성할 수 있습니다: |
|||
|
|||
```Python |
|||
burgers = await get_burgers(2) |
|||
``` |
|||
|
|||
여기서 핵심은 `await`입니다. 이것은 파이썬에게 `burgers` 결과를 저장하기 이전에 `get_burgers(2)`의 작업이 완료되기를 🕙 기다리라고 ⏸ 말합니다. 이로 인해, 파이썬은 그동안 (다른 요청을 받는 것과 같은) 다른 작업을 수행해도 된다는 것을 🔀 ⏯ 알게될 것입니다. |
|||
|
|||
`await`가 동작하기 위해, 이것은 비동기를 지원하는 함수 내부에 있어야 합니다. 이를 위해서 함수를 `async def`를 사용해 정의하기만 하면 됩니다: |
|||
|
|||
```Python hl_lines="1" |
|||
async def get_burgers(number: int): |
|||
# Do some asynchronous stuff to create the burgers |
|||
return burgers |
|||
``` |
|||
|
|||
...`def`를 사용하는 대신: |
|||
|
|||
```Python hl_lines="2" |
|||
# This is not asynchronous |
|||
def get_sequential_burgers(number: int): |
|||
# Do some sequential stuff to create the burgers |
|||
return burgers |
|||
``` |
|||
|
|||
`async def`를 사용하면, 파이썬은 해당 함수 내에서 `await` 표현에 주의해야한다는 사실과, 해당 함수의 실행을 "일시정지"⏸하고 다시 돌아오기 전까지 다른 작업을 수행🔀할 수 있다는 것을 알게됩니다. |
|||
|
|||
`async def`f 함수를 호출하고자 할 때, "대기"해야합니다. 따라서, 아래는 동작하지 않습니다. |
|||
|
|||
```Python |
|||
# This won't work, because get_burgers was defined with: async def |
|||
burgers = get_burgers(2) |
|||
``` |
|||
|
|||
--- |
|||
|
|||
따라서, `await`f를 사용해서 호출할 수 있는 라이브러리를 사용한다면, 다음과 같이 `async def`를 사용하는 *경로 작동 함수*를 생성해야 합니다: |
|||
|
|||
```Python hl_lines="2-3" |
|||
@app.get('/burgers') |
|||
async def read_burgers(): |
|||
burgers = await get_burgers(2) |
|||
return burgers |
|||
``` |
|||
|
|||
### 더 세부적인 기술적 사항 |
|||
|
|||
`await`가 `async def`를 사용하는 함수 내부에서만 사용이 가능하다는 것을 눈치채셨을 것입니다. |
|||
|
|||
하지만 동시에, `async def`로 정의된 함수들은 "대기"되어야만 합니다. 따라서, `async def`를 사용한 함수들은 역시 `async def`를 사용한 함수 내부에서만 호출될 수 있습니다. |
|||
|
|||
그렇다면 닭이 먼저냐, 달걀이 먼저냐, 첫 `async` 함수를 어떻게 호출할 수 있겠습니까? |
|||
|
|||
**FastAPI**를 사용해 작업한다면 이것을 걱정하지 않아도 됩니다. 왜냐하면 그 "첫" 함수는 당신의 *경로 작동 함수*가 될 것이고, FastAPI는 어떻게 올바르게 처리할지 알고있기 때문입니다. |
|||
|
|||
하지만 FastAPI를 사용하지 않고 `async` / `await`를 사용하고 싶다면, 이 역시 가능합니다. |
|||
|
|||
### 당신만의 비동기 코드 작성하기 |
|||
|
|||
Starlette(그리고 FastAPI)는 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 기반으로 하고있고, 따라서 파이썬 표준 라이브러리인 <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> 및 <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>와 호환됩니다. |
|||
|
|||
특히, 코드에서 고급 패턴이 필요한 고급 동시성을 사용하는 경우 직접적으로 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 사용할 수 있습니다. |
|||
|
|||
FastAPI를 사용하지 않더라도, 높은 호환성 및 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>의 이점(예: *구조화된 동시성*)을 취하기 위해 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 사용해 비동기 응용프로그램을 작성할 수 있습니다. |
|||
|
|||
### 비동기 코드의 다른 형태 |
|||
|
|||
파이썬에서 `async`와 `await`를 사용하게 된 것은 비교적 최근의 일입니다. |
|||
|
|||
하지만 이로 인해 비동기 코드 작업이 훨씬 간단해졌습니다. |
|||
|
|||
같은 (또는 거의 유사한) 문법은 최신 버전의 자바스크립트(브라우저와 NodeJS)에도 추가되었습니다. |
|||
|
|||
하지만 그 이전에, 비동기 코드를 처리하는 것은 꽤 복잡하고 어려운 일이었습니다. |
|||
|
|||
파이썬의 예전 버전이라면, 스레드 또는 <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>를 사용할 수 있을 것입니다. 하지만 코드를 이해하고, 디버깅하고, 이에 대해 생각하는게 훨씬 복잡합니다. |
|||
|
|||
예전 버전의 NodeJS / 브라우저 자바스크립트라면, "콜백 함수"를 사용했을 것입니다. 그리고 이로 인해 <a href="http://callbackhell.com/" class="external-link" target="_blank">콜백 지옥</a>에 빠지게 될 수 있습니다. |
|||
|
|||
## 코루틴 |
|||
|
|||
**코루틴**은 `async def` 함수가 반환하는 것을 칭하는 매우 고급스러운 용어일 뿐입니다. 파이썬은 그것이 시작되고 어느 시점에서 완료되지만 내부에 `await`가 있을 때마다 내부적으로 일시정지⏸될 수도 있는 함수와 유사한 것이라는 사실을 알고있습니다. |
|||
|
|||
그러나 `async` 및 `await`와 함께 비동기 코드를 사용하는 이 모든 기능들은 "코루틴"으로 간단히 요약됩니다. 이것은 Go의 주된 핵심 기능인 "고루틴"에 견줄 수 있습니다. |
|||
|
|||
## 결론 |
|||
|
|||
상기 문장을 다시 한 번 봅시다: |
|||
|
|||
> 최신 파이썬 버전은 **`async` 및 `await`** 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다. |
|||
|
|||
이제 이 말을 조금 더 이해할 수 있을 것입니다. ✨ |
|||
|
|||
이것이 (Starlette을 통해) FastAPI를 강하게 하면서 그것이 인상적인 성능을 낼 수 있게 합니다. |
|||
|
|||
## 매우 세부적인 기술적 사항 |
|||
|
|||
!!! warning "경고" |
|||
이 부분은 넘어가도 됩니다. |
|||
|
|||
이것들은 **FastAPI**가 내부적으로 어떻게 동작하는지에 대한 매우 세부적인 기술사항입니다. |
|||
|
|||
만약 기술적 지식(코루틴, 스레드, 블록킹 등)이 있고 FastAPI가 어떻게 `async def` vs `def`를 다루는지 궁금하다면, 계속하십시오. |
|||
|
|||
### 경로 작동 함수 |
|||
|
|||
경로 작동 함수를 `async def` 대신 일반적인 `def`로 선언하는 경우, (서버를 차단하는 것처럼) 그것을 직접 호출하는 대신 대기중인 외부 스레드풀에서 실행됩니다. |
|||
|
|||
만약 상기에 묘사된대로 동작하지 않는 비동기 프로그램을 사용해왔고 약간의 성능 향상 (약 100 나노초)을 위해 `def`를 사용해서 계산만을 위한 사소한 *경로 작동 함수*를 정의해왔다면, **FastAPI**는 이와는 반대라는 것에 주의하십시오. 이러한 경우에, *경로 작동 함수*가 블로킹 <abbr title="Input/Output: 디스크 읽기 또는 쓰기, 네트워크 통신.">I/O</abbr>를 수행하는 코드를 사용하지 않는 한 `async def`를 사용하는 편이 더 낫습니다. |
|||
|
|||
하지만 두 경우 모두, FastAPI가 당신이 전에 사용하던 프레임워크보다 [더 빠를](/#performance){.internal-link target=_blank} (최소한 비견될) 확률이 높습니다. |
|||
|
|||
### 의존성 |
|||
|
|||
의존성에도 동일하게 적용됩니다. 의존성이 `async def`가 아닌 표준 `def` 함수라면, 외부 스레드풀에서 실행됩니다. |
|||
|
|||
### 하위-의존성 |
|||
|
|||
함수 정의시 매개변수로 서로를 필요로하는 다수의 의존성과 하위-의존성을 가질 수 있고, 그 중 일부는 `async def`로, 다른 일부는 일반적인 `def`로 생성되었을 수 있습니다. 이것은 여전히 잘 동작하고, 일반적인 `def`로 생성된 것들은 "대기"되는 대신에 (스레드풀로부터) 외부 스레드에서 호출됩니다. |
|||
|
|||
### 다른 유틸리티 함수 |
|||
|
|||
직접 호출되는 다른 모든 유틸리티 함수는 일반적인 `def`나 `async def`로 생성될 수 있고 FastAPI는 이를 호출하는 방식에 영향을 미치지 않습니다. |
|||
|
|||
이것은 FastAPI가 당신을 위해 호출하는 함수와는 반대입니다: *경로 작동 함수*와 의존성 |
|||
|
|||
만약 당신의 유틸리티 함수가 `def`를 사용한 일반적인 함수라면, 스레드풀에서가 아니라 직접 호출(당신이 코드에 작성한 대로)될 것이고, `async def`로 생성된 함수라면 코드에서 호출할 때 그 함수를 `await` 해야 합니다. |
|||
|
|||
--- |
|||
|
|||
다시 말하지만, 이것은 당신이 이것에 대해 찾고있던 경우에 한해 유용할 매우 세부적인 기술사항입니다. |
|||
|
|||
그렇지 않은 경우, 상기의 가이드라인만으로도 충분할 것입니다: [바쁘신 경우](#in-a-hurry). |
@ -0,0 +1,92 @@ |
|||
# Данные формы |
|||
|
|||
Когда вам нужно получить поля формы вместо JSON, вы можете использовать `Form`. |
|||
|
|||
!!! info "Дополнительная информация" |
|||
Чтобы использовать формы, сначала установите <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>. |
|||
|
|||
Например, выполните команду `pip install python-multipart`. |
|||
|
|||
## Импорт `Form` |
|||
|
|||
Импортируйте `Form` из `fastapi`: |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python hl_lines="3" |
|||
{!> ../../../docs_src/request_forms/tutorial001_an_py39.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python hl_lines="1" |
|||
{!> ../../../docs_src/request_forms/tutorial001_an.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать 'Annotated' версию, если это возможно. |
|||
|
|||
```Python hl_lines="1" |
|||
{!> ../../../docs_src/request_forms/tutorial001.py!} |
|||
``` |
|||
|
|||
## Определение параметров `Form` |
|||
|
|||
Создайте параметры формы так же, как это делается для `Body` или `Query`: |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python hl_lines="9" |
|||
{!> ../../../docs_src/request_forms/tutorial001_an_py39.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python hl_lines="8" |
|||
{!> ../../../docs_src/request_forms/tutorial001_an.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать 'Annotated' версию, если это возможно. |
|||
|
|||
```Python hl_lines="7" |
|||
{!> ../../../docs_src/request_forms/tutorial001.py!} |
|||
``` |
|||
|
|||
Например, в одном из способов использования спецификации OAuth2 (называемом "потоком пароля") требуется отправить `username` и `password` в виде полей формы. |
|||
|
|||
Данный способ требует отправку данных для авторизации посредством формы (а не JSON) и обязательного наличия в форме строго именованных полей `username` и `password`. |
|||
|
|||
Вы можете настроить `Form` точно так же, как настраиваете и `Body` ( `Query`, `Path`, `Cookie`), включая валидации, примеры, псевдонимы (например, `user-name` вместо `username`) и т.д. |
|||
|
|||
!!! info "Дополнительная информация" |
|||
`Form` - это класс, который наследуется непосредственно от `Body`. |
|||
|
|||
!!! tip "Подсказка" |
|||
Вам необходимо явно указывать параметр `Form` при объявлении каждого поля, иначе поля будут интерпретироваться как параметры запроса или параметры тела (JSON). |
|||
|
|||
## О "полях формы" |
|||
|
|||
Обычно способ, которым HTML-формы (`<form></form>`) отправляют данные на сервер, использует "специальное" кодирование для этих данных, отличное от JSON. |
|||
|
|||
**FastAPI** гарантирует правильное чтение этих данных из соответствующего места, а не из JSON. |
|||
|
|||
!!! note "Технические детали" |
|||
Данные из форм обычно кодируются с использованием "типа медиа" `application/x-www-form-urlencoded`. |
|||
|
|||
Но когда форма содержит файлы, она кодируется как `multipart/form-data`. Вы узнаете о работе с файлами в следующей главе. |
|||
|
|||
Если вы хотите узнать больше про кодировки и поля формы, ознакомьтесь с <a href="https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank">документацией <abbr title="Mozilla Developer Network">MDN</abbr> для `POST` на веб-сайте</a>. |
|||
|
|||
!!! warning "Предупреждение" |
|||
Вы можете объявлять несколько параметров `Form` в *операции пути*, но вы не можете одновременно с этим объявлять поля `Body`, которые вы ожидаете получить в виде JSON, так как запрос будет иметь тело, закодированное с использованием `application/x-www-form-urlencoded`, а не `application/json`. |
|||
|
|||
Это не ограничение **FastAPI**, это часть протокола HTTP. |
|||
|
|||
## Резюме |
|||
|
|||
Используйте `Form` для объявления входных параметров данных формы. |
@ -0,0 +1,213 @@ |
|||
# Тіло запиту |
|||
|
|||
Коли вам потрібно надіслати дані з клієнта (скажімо, браузера) до вашого API, ви надсилаєте їх як **тіло запиту**. |
|||
|
|||
Тіло **запиту** — це дані, надіслані клієнтом до вашого API. Тіло **відповіді** — це дані, які ваш API надсилає клієнту. |
|||
|
|||
Ваш API майже завжди має надсилати тіло **відповіді**. Але клієнтам не обов’язково потрібно постійно надсилати тіла **запитів**. |
|||
|
|||
Щоб оголосити тіло **запиту**, ви використовуєте <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> моделі з усією їх потужністю та перевагами. |
|||
|
|||
!!! info |
|||
Щоб надіслати дані, ви повинні використовувати один із: `POST` (більш поширений), `PUT`, `DELETE` або `PATCH`. |
|||
|
|||
Надсилання тіла із запитом `GET` має невизначену поведінку в специфікаціях, проте воно підтримується FastAPI лише для дуже складних/екстремальних випадків використання. |
|||
|
|||
Оскільки це не рекомендується, інтерактивна документація з Swagger UI не відображатиме документацію для тіла запиту під час використання `GET`, і проксі-сервери в середині можуть не підтримувати її. |
|||
|
|||
## Імпортуйте `BaseModel` від Pydantic |
|||
|
|||
Спочатку вам потрібно імпортувати `BaseModel` з `pydantic`: |
|||
|
|||
=== "Python 3.6 і вище" |
|||
|
|||
```Python hl_lines="4" |
|||
{!> ../../../docs_src/body/tutorial001.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10 і вище" |
|||
|
|||
```Python hl_lines="2" |
|||
{!> ../../../docs_src/body/tutorial001_py310.py!} |
|||
``` |
|||
|
|||
## Створіть свою модель даних |
|||
|
|||
Потім ви оголошуєте свою модель даних як клас, який успадковується від `BaseModel`. |
|||
|
|||
Використовуйте стандартні типи Python для всіх атрибутів: |
|||
|
|||
=== "Python 3.6 і вище" |
|||
|
|||
```Python hl_lines="7-11" |
|||
{!> ../../../docs_src/body/tutorial001.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10 і вище" |
|||
|
|||
```Python hl_lines="5-9" |
|||
{!> ../../../docs_src/body/tutorial001_py310.py!} |
|||
``` |
|||
|
|||
Так само, як і при оголошенні параметрів запиту, коли атрибут моделі має значення за замовчуванням, він не є обов’язковим. В іншому випадку це потрібно. Використовуйте `None`, щоб зробити його необов'язковим. |
|||
|
|||
Наприклад, ця модель вище оголошує JSON "`об'єкт`" (або Python `dict`), як: |
|||
|
|||
```JSON |
|||
{ |
|||
"name": "Foo", |
|||
"description": "An optional description", |
|||
"price": 45.2, |
|||
"tax": 3.5 |
|||
} |
|||
``` |
|||
|
|||
...оскільки `description` і `tax` є необов'язковими (зі значенням за замовчуванням `None`), цей JSON "`об'єкт`" також буде дійсним: |
|||
|
|||
```JSON |
|||
{ |
|||
"name": "Foo", |
|||
"price": 45.2 |
|||
} |
|||
``` |
|||
|
|||
## Оголоси її як параметр |
|||
|
|||
Щоб додати модель даних до вашої *операції шляху*, оголосіть її так само, як ви оголосили параметри шляху та запиту: |
|||
|
|||
=== "Python 3.6 і вище" |
|||
|
|||
```Python hl_lines="18" |
|||
{!> ../../../docs_src/body/tutorial001.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10 і вище" |
|||
|
|||
```Python hl_lines="16" |
|||
{!> ../../../docs_src/body/tutorial001_py310.py!} |
|||
``` |
|||
|
|||
...і вкажіть її тип як модель, яку ви створили, `Item`. |
|||
|
|||
## Результати |
|||
|
|||
Лише з цим оголошенням типу Python **FastAPI** буде: |
|||
|
|||
* Читати тіло запиту як JSON. |
|||
* Перетворювати відповідні типи (якщо потрібно). |
|||
* Валідувати дані. |
|||
* Якщо дані недійсні, він поверне гарну та чітку помилку, вказуючи, де саме і які дані були неправильними. |
|||
* Надавати отримані дані у параметрі `item`. |
|||
* Оскільки ви оголосили його у функції як тип `Item`, ви також матимете всю підтримку редактора (автозаповнення, тощо) для всіх атрибутів та їх типів. |
|||
* Генерувати <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> визначення для вашої моделі, ви також можете використовувати їх де завгодно, якщо це має сенс для вашого проекту. |
|||
* Ці схеми будуть частиною згенерованої схеми OpenAPI і використовуватимуться автоматичною документацією інтерфейсу користувача. |
|||
|
|||
## Автоматична документація |
|||
|
|||
Схеми JSON ваших моделей будуть частиною вашої схеми, згенерованої OpenAPI, і будуть показані в інтерактивній API документації: |
|||
|
|||
<img src="/img/tutorial/body/image01.png"> |
|||
|
|||
А також використовуватимуться в API документації всередині кожної *операції шляху*, якій вони потрібні: |
|||
|
|||
<img src="/img/tutorial/body/image02.png"> |
|||
|
|||
## Підтримка редактора |
|||
|
|||
У вашому редакторі, всередині вашої функції, ви будете отримувати підказки типу та завершення скрізь (це б не сталося, якби ви отримали `dict` замість моделі Pydantic): |
|||
|
|||
<img src="/img/tutorial/body/image03.png"> |
|||
|
|||
Ви також отримуєте перевірку помилок на наявність операцій з неправильним типом: |
|||
|
|||
<img src="/img/tutorial/body/image04.png"> |
|||
|
|||
Це не випадково, весь каркас був побудований навколо цього дизайну. |
|||
|
|||
І він був ретельно перевірений на етапі проектування, перед будь-яким впровадженням, щоб переконатися, що він працюватиме з усіма редакторами. |
|||
|
|||
Були навіть деякі зміни в самому Pydantic, щоб підтримати це. |
|||
|
|||
Попередні скріншоти були зроблені у <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>. |
|||
|
|||
Але ви отримаєте ту саму підтримку редактора у <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> та більшість інших редакторів Python: |
|||
|
|||
<img src="/img/tutorial/body/image05.png"> |
|||
|
|||
!!! tip |
|||
Якщо ви використовуєте <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> як ваш редактор, ви можете використати <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>. |
|||
|
|||
Він покращує підтримку редакторів для моделей Pydantic за допомогою: |
|||
|
|||
* автозаповнення |
|||
* перевірки типу |
|||
* рефакторингу |
|||
* пошуку |
|||
* інспекції |
|||
|
|||
## Використовуйте модель |
|||
|
|||
Усередині функції ви можете отримати прямий доступ до всіх атрибутів об’єкта моделі: |
|||
|
|||
=== "Python 3.6 і вище" |
|||
|
|||
```Python hl_lines="21" |
|||
{!> ../../../docs_src/body/tutorial002.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10 і вище" |
|||
|
|||
```Python hl_lines="19" |
|||
{!> ../../../docs_src/body/tutorial002_py310.py!} |
|||
``` |
|||
|
|||
## Тіло запиту + параметри шляху |
|||
|
|||
Ви можете одночасно оголошувати параметри шляху та тіло запиту. |
|||
|
|||
**FastAPI** розпізнає, що параметри функції, які відповідають параметрам шляху, мають бути **взяті з шляху**, а параметри функції, які оголошуються як моделі Pydantic, **взяті з тіла запиту**. |
|||
|
|||
=== "Python 3.6 і вище" |
|||
|
|||
```Python hl_lines="17-18" |
|||
{!> ../../../docs_src/body/tutorial003.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10 і вище" |
|||
|
|||
```Python hl_lines="15-16" |
|||
{!> ../../../docs_src/body/tutorial003_py310.py!} |
|||
``` |
|||
|
|||
## Тіло запиту + шлях + параметри запиту |
|||
|
|||
Ви також можете оголосити параметри **тіло**, **шлях** і **запит** одночасно. |
|||
|
|||
**FastAPI** розпізнає кожен з них і візьме дані з потрібного місця. |
|||
|
|||
=== "Python 3.6 і вище" |
|||
|
|||
```Python hl_lines="18" |
|||
{!> ../../../docs_src/body/tutorial004.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10 і вище" |
|||
|
|||
```Python hl_lines="16" |
|||
{!> ../../../docs_src/body/tutorial004_py310.py!} |
|||
``` |
|||
|
|||
Параметри функції будуть розпізнаватися наступним чином: |
|||
|
|||
* Якщо параметр також оголошено в **шляху**, він використовуватиметься як параметр шляху. |
|||
* Якщо параметр має **сингулярний тип** (наприклад, `int`, `float`, `str`, `bool` тощо), він буде інтерпретуватися як параметр **запиту**. |
|||
* Якщо параметр оголошується як тип **Pydantic моделі**, він інтерпретується як **тіло** запиту. |
|||
|
|||
!!! note |
|||
FastAPI буде знати, що значення "q" не є обов'язковим через значення за замовчуванням "= None". |
|||
|
|||
`Optional` у `Optional[str]` не використовується FastAPI, але дозволить вашому редактору надати вам кращу підтримку та виявляти помилки. |
|||
|
|||
## Без Pydantic |
|||
|
|||
Якщо ви не хочете використовувати моделі Pydantic, ви також можете використовувати параметри **Body**. Перегляньте документацію для [Тіло – Кілька параметрів: сингулярні значення в тілі](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}. |
@ -0,0 +1 @@ |
|||
INHERIT: ../en/mkdocs.yml |
@ -0,0 +1,197 @@ |
|||
# Tính năng |
|||
|
|||
## Tính năng của FastAPI |
|||
|
|||
**FastAPI** cho bạn những tính năng sau: |
|||
|
|||
### Dựa trên những tiêu chuẩn mở |
|||
|
|||
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> cho việc tạo API, bao gồm những khai báo về <abbr title="cũng được biết đến như: endpoints, routes">đường dẫn</abbr> <abbr title="cũng được biết đến như các phương thức HTTP, như POST, GET, PUT, DELETE"> các toán tử</abbr>, tham số, body requests, cơ chế bảo mật, etc. |
|||
* Tự động tài liệu hóa data model theo <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (OpenAPI bản thân nó được dựa trên JSON Schema). |
|||
* Được thiết kế xung quanh các tiêu chuẩn này sau khi nghiên cứu tỉ mỉ thay vì chỉ suy nghĩ đơn giản và sơ xài. |
|||
* Điều này cho phép tự động hóa **trình sinh code client** cho nhiều ngôn ngữ lập trình khác nhau. |
|||
|
|||
### Tự động hóa tài liệu |
|||
|
|||
|
|||
Tài liệu tương tác API và web giao diện người dùng. Là một framework được dựa trên OpenAPI do đó có nhiều tùy chọn giao diện cho tài liệu API, 2 giao diện bên dưới là mặc định. |
|||
|
|||
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>, với giao diện khám phá, gọi và kiểm thử API trực tiếp từ trình duyệt. |
|||
|
|||
 |
|||
|
|||
* Thay thế với tài liệu API với <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>. |
|||
|
|||
 |
|||
|
|||
### Chỉ cần phiên bản Python hiện đại |
|||
|
|||
Tất cả được dựa trên khai báo kiểu dữ liệu chuẩn của **Python 3.6** (cảm ơn Pydantic). Bạn không cần học cú pháp mới, chỉ cần biết chuẩn Python hiện đại. |
|||
|
|||
Nếu bạn cần 2 phút để làm mới lại cách sử dụng các kiểu dữ liệu mới của Python (thậm chí nếu bạn không sử dụng FastAPI), xem hướng dẫn ngắn: [Kiểu dữ liệu Python](python-types.md){.internal-link target=_blank}. |
|||
|
|||
Bạn viết chuẩn Python với kiểu dữ liệu như sau: |
|||
|
|||
```Python |
|||
from datetime import date |
|||
|
|||
from pydantic import BaseModel |
|||
|
|||
# Declare a variable as a str |
|||
# and get editor support inside the function |
|||
def main(user_id: str): |
|||
return user_id |
|||
|
|||
|
|||
# A Pydantic model |
|||
class User(BaseModel): |
|||
id: int |
|||
name: str |
|||
joined: date |
|||
``` |
|||
|
|||
Sau đó có thể được sử dụng: |
|||
|
|||
```Python |
|||
my_user: User = User(id=3, name="John Doe", joined="2018-07-19") |
|||
|
|||
second_user_data = { |
|||
"id": 4, |
|||
"name": "Mary", |
|||
"joined": "2018-11-30", |
|||
} |
|||
|
|||
my_second_user: User = User(**second_user_data) |
|||
``` |
|||
|
|||
!!! info |
|||
`**second_user_data` nghĩa là: |
|||
|
|||
Truyền các khóa và giá trị của dict `second_user_data` trực tiếp như các tham số kiểu key-value, tương đương với: `User(id=4, name="Mary", joined="2018-11-30")` |
|||
|
|||
### Được hỗ trợ từ các trình soạn thảo |
|||
|
|||
|
|||
Toàn bộ framework được thiết kế để sử dụng dễ dàng và trực quan, toàn bộ quyết định đã được kiểm thử trên nhiều trình soạn thảo thậm chí trước khi bắt đầu quá trình phát triển, để chắc chắn trải nghiệm phát triển là tốt nhất. |
|||
|
|||
Trong lần khảo sát cuối cùng dành cho các lập trình viên Python, đã rõ ràng <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">rằng đa số các lập trình viên sử dụng tính năng "autocompletion"</a>. |
|||
|
|||
Toàn bộ framework "FastAPI" phải đảm bảo rằng: autocompletion hoạt động ở mọi nơi. Bạn sẽ hiếm khi cần quay lại để đọc tài liệu. |
|||
|
|||
Đây là các trình soạn thảo có thể giúp bạn: |
|||
|
|||
* trong <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a>: |
|||
|
|||
 |
|||
|
|||
* trong <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>: |
|||
|
|||
 |
|||
|
|||
Bạn sẽ có được auto-completion trong code, thậm chí trước đó là không thể. Như trong ví dụ, khóa `price` bên trong một JSON (đó có thể được lồng nhau) đến từ một request. |
|||
|
|||
Không còn nhập sai tên khóa, quay đi quay lại giữa các tài liệu hoặc cuộn lên cuộn xuống để tìm xem cuối cùng bạn đã sử dụng `username` hay `user_name`. |
|||
|
|||
### Ngắn gọn |
|||
|
|||
FastAPI có các giá trị mặc định hợp lý cho mọi thứ, với các cấu hình tùy chọn ở mọi nơi. Tất cả các tham số có thể được tinh chỉnh để thực hiện những gì bạn cần và để định nghĩa API bạn cần. |
|||
|
|||
Nhưng mặc định, tất cả **đều hoạt động**. |
|||
|
|||
### Validation |
|||
|
|||
* Validation cho đa số (hoặc tất cả?) **các kiểu dữ liệu** Python, bao gồm: |
|||
* JSON objects (`dict`). |
|||
* Mảng JSON (`list`) định nghĩa kiểu dữ liệu từng phần tử. |
|||
* Xâu (`str`), định nghĩa độ dài lớn nhất, nhỏ nhất. |
|||
* Số (`int`, `float`) với các giá trị lớn nhất, nhỏ nhất, etc. |
|||
|
|||
* Validation cho nhiều kiểu dữ liệu bên ngoài như: |
|||
* URL. |
|||
* Email. |
|||
* UUID. |
|||
* ...và nhiều cái khác. |
|||
|
|||
Tất cả validation được xử lí bằng những thiết lập tốt và mạnh mẽ của **Pydantic**. |
|||
|
|||
### Bảo mật và xác thực |
|||
|
|||
Bảo mật và xác thực đã tích hợp mà không làm tổn hại tới cơ sở dữ liệu hoặc data models. |
|||
|
|||
Tất cả cơ chế bảo mật định nghĩa trong OpenAPI, bao gồm: |
|||
|
|||
* HTTP Basic. |
|||
* **OAuth2** (với **JWT tokens**). Xem hướng dẫn [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. |
|||
* API keys in: |
|||
* Headers. |
|||
* Các tham số trong query string. |
|||
* Cookies, etc. |
|||
|
|||
Cộng với tất cả các tính năng bảo mật từ Starlette (bao gồm **session cookies**). |
|||
|
|||
Tất cả được xây dựng dưới dạng các công cụ và thành phần có thể tái sử dụng, dễ dàng tích hợp với hệ thống, kho lưu trữ dữ liệu, cơ sở dữ liệu quan hệ và NoSQL của bạn,... |
|||
|
|||
### Dependency Injection |
|||
|
|||
FastAPI bao gồm một hệ thống <abbr title='cũng biết đến như là "components", "resources", "services", "providers"'><strong>Dependency Injection</strong></abbr> vô cùng dễ sử dụng nhưng vô cùng mạnh mẽ. |
|||
|
|||
* Thậm chí, các dependency có thể có các dependency khác, tạo thành một phân cấp hoặc **"một đồ thị" của các dependency**. |
|||
* Tất cả **được xử lí tự động** bởi framework. |
|||
* Tất cả các dependency có thể yêu cầu dữ liệu từ request và **tăng cường các ràng buộc từ đường dẫn** và tự động tài liệu hóa. |
|||
* **Tự động hóa validation**, thậm chí với các tham số *đường dẫn* định nghĩa trong các dependency. |
|||
* Hỗ trợ hệ thống xác thực người dùng phức tạp, **các kết nối cơ sở dữ liệu**,... |
|||
* **Không làm tổn hại** cơ sở dữ liệu, frontends,... Nhưng dễ dàng tích hợp với tất cả chúng. |
|||
|
|||
### Không giới hạn "plug-ins" |
|||
|
|||
Hoặc theo một cách nào khác, không cần chúng, import và sử dụng code bạn cần. |
|||
|
|||
Bất kì tích hợp nào được thiết kế để sử dụng đơn giản (với các dependency), đến nỗi bạn có thể tạo một "plug-in" cho ứng dụng của mình trong 2 dòng code bằng cách sử dụng cùng một cấu trúc và cú pháp được sử dụng cho *path operations* của bạn. |
|||
|
|||
### Đã được kiểm thử |
|||
|
|||
* 100% <abbr title=" Lượng code đã được kiểm thử tự động">test coverage</abbr>. |
|||
* 100% <abbr title="Python type annotations, với điều này trình soạn thảo của bạn và các công cụ bên ngoài có thể hỗ trợ bạn tốt hơn">type annotated</abbr> code base. |
|||
* Được sử dụng cho các ứng dụng sản phẩm. |
|||
|
|||
## Tính năng của Starlette |
|||
|
|||
`FastAPI` is thực sự là một sub-class của `Starlette`. Do đó, nếu bạn đã biết hoặc đã sử dụng Starlette, đa số các chức năng sẽ làm việc giống như vậy. |
|||
|
|||
Với **FastAPI**, bạn có được tất cả những tính năng của **Starlette**: |
|||
|
|||
* Hiệu năng thực sự ấn tượng. Nó là <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">một trong nhưng framework Python nhanh nhất, khi so sánh với **NodeJS** và **Go**</a>. |
|||
* Hỗ trợ **WebSocket**. |
|||
* In-process background tasks. |
|||
* Startup and shutdown events. |
|||
* Client cho kiểm thử xây dựng trên HTTPX. |
|||
* **CORS**, GZip, Static Files, Streaming responses. |
|||
* Hỗ trợ **Session and Cookie**. |
|||
* 100% test coverage. |
|||
* 100% type annotated codebase. |
|||
|
|||
## Tính năng của Pydantic |
|||
|
|||
**FastAPI** tương thích đầy đủ với (và dựa trên) <a href="https://pydantic-docs.helpmanual.io" class="external-link" target="_blank"><strong>Pydantic</strong></a>. Do đó, bất kì code Pydantic nào bạn thêm vào cũng sẽ hoạt động. |
|||
|
|||
Bao gồm các thư viện bên ngoài cũng dựa trên Pydantic, như <abbr title="Object-Relational Mapper">ORM</abbr>s, <abbr title="Object-Document Mapper">ODM</abbr>s cho cơ sở dữ liệu. |
|||
|
|||
Nó cũng có nghĩa là trong nhiều trường hợp, bạn có thể truyền cùng object bạn có từ một request **trực tiếp cho cơ sở dữ liệu**, vì mọi thứ được validate tự động. |
|||
|
|||
Điều tương tự áp dụng cho các cách khác nhau, trong nhiều trường hợp, bạn có thể chỉ truyền object từ cơ sở dữ liêu **trực tiếp tới client**. |
|||
|
|||
Với **FastAPI**, bạn có tất cả những tính năng của **Pydantic** (FastAPI dựa trên Pydantic cho tất cả những xử lí về dữ liệu): |
|||
|
|||
* **Không gây rối não**: |
|||
* Không cần học ngôn ngữ mô tả cấu trúc mới. |
|||
* Nếu bạn biết kiểu dữ liệu Python, bạn biết cách sử dụng Pydantic. |
|||
* Sử dụng tốt với **<abbr title="Môi trường phát triển tích hợp, tương tự như một trình soạn thảo code">IDE</abbr>/<abbr title="Một chương trình kiểm tra code lỗi">linter</abbr>/não của bạn**: |
|||
|
|||
* Bởi vì các cấu trúc dữ liệu của Pydantic chỉ là các instances của class bạn định nghĩa; auto-completion, linting, mypy và trực giác của bạn nên làm việc riêng biệt với những dữ liệu mà bạn đã validate. |
|||
* Validate **các cấu trúc phức tạp**: |
|||
* Sử dụng các models Pydantic phân tầng, `List` và `Dict` của Python `typing`,... |
|||
* Và các validators cho phép các cấu trúc dữ liệu phức tạp trở nên rõ ràng và dễ dàng để định nghĩa, kiểm tra và tài liệu hóa thành JSON Schema. |
|||
* Bạn có thể có các object **JSON lồng nhau** và tất cả chúng đã validate và annotated. |
|||
* **Có khả năng mở rộng**: |
|||
* Pydantic cho phép bạn tùy chỉnh kiểu dữ liệu bằng việc định nghĩa hoặc bạn có thể mở rộng validation với các decorator trong model. |
|||
* 100% test coverage. |
@ -0,0 +1,472 @@ |
|||
<p align="center"> |
|||
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a> |
|||
</p> |
|||
<p align="center"> |
|||
<em>FastAPI framework, hiệu năng cao, dễ học, dễ code, sẵn sàng để tạo ra sản phẩm</em> |
|||
</p> |
|||
<p align="center"> |
|||
<a href="https://github.com/tiangolo/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank"> |
|||
<img src="https://github.com/tiangolo/fastapi/workflows/Test/badge.svg?event=push&branch=master" alt="Test"> |
|||
</a> |
|||
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/tiangolo/fastapi" target="_blank"> |
|||
<img src="https://coverage-badge.samuelcolvin.workers.dev/tiangolo/fastapi.svg" alt="Coverage"> |
|||
</a> |
|||
<a href="https://pypi.org/project/fastapi" target="_blank"> |
|||
<img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Package version"> |
|||
</a> |
|||
<a href="https://pypi.org/project/fastapi" target="_blank"> |
|||
<img src="https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058" alt="Supported Python versions"> |
|||
</a> |
|||
</p> |
|||
|
|||
--- |
|||
|
|||
**Tài liệu**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a> |
|||
|
|||
**Mã nguồn**: <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a> |
|||
|
|||
--- |
|||
|
|||
FastAPI là một web framework hiện đại, hiệu năng cao để xây dựng web APIs với Python 3.7+ dựa trên tiêu chuẩn Python type hints. |
|||
|
|||
Những tính năng như: |
|||
|
|||
* **Nhanh**: Hiệu năng rất cao khi so sánh với **NodeJS** và **Go** (cảm ơn Starlette và Pydantic). [Một trong những Python framework nhanh nhất](#performance). |
|||
* **Code nhanh**: Tăng tốc độ phát triển tính năng từ 200% tới 300%. * |
|||
* **Ít lỗi hơn**: Giảm khoảng 40% những lỗi phát sinh bởi con người (nhà phát triển). * |
|||
* **Trực giác tốt hơn**: Được các trình soạn thảo hỗ tuyệt vời. <abbr title="như auto-complete, autocompletion, IntelliSense">Completion</abbr> mọi nơi. Ít thời gian gỡ lỗi. |
|||
* **Dễ dàng**: Được thiết kế để dễ dàng học và sử dụng. Ít thời gian đọc tài liệu. |
|||
* **Ngắn**: Tối thiểu code bị trùng lặp. Nhiều tính năng được tích hợp khi định nghĩa tham số. Ít lỗi hơn. |
|||
* **Tăng tốc**: Có được sản phẩm cùng với tài liệu (được tự động tạo) có thể tương tác. |
|||
* **Được dựa trên các tiêu chuẩn**: Dựa trên (và hoàn toàn tương thích với) các tiêu chuẩn mở cho APIs : <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (trước đó được biết đến là Swagger) và <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>. |
|||
|
|||
<small>* ước tính được dựa trên những kiểm chứng trong nhóm phát triển nội bộ, xây dựng các ứng dụng sản phẩm.</small> |
|||
|
|||
## Nhà tài trợ |
|||
|
|||
<!-- sponsors --> |
|||
|
|||
{% if sponsors %} |
|||
{% for sponsor in sponsors.gold -%} |
|||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a> |
|||
{% endfor -%} |
|||
{%- for sponsor in sponsors.silver -%} |
|||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a> |
|||
{% endfor %} |
|||
{% endif %} |
|||
|
|||
<!-- /sponsors --> |
|||
|
|||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Những nhà tài trợ khác</a> |
|||
|
|||
## Ý kiến đánh giá |
|||
|
|||
"_[...] Tôi đang sử dụng **FastAPI** vô cùng nhiều vào những ngày này. [...] Tôi thực sự đang lên kế hoạch sử dụng nó cho tất cả các nhóm **dịch vụ ML tại Microsoft**. Một vài trong số đó đang tích hợp vào sản phẩm lõi của **Window** và một vài sản phẩm cho **Office**._" |
|||
|
|||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/tiangolo/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div> |
|||
|
|||
--- |
|||
|
|||
"_Chúng tôi tích hợp thư viện **FastAPI** để sinh ra một **REST** server, nó có thể được truy vấn để thu được những **dự đoán**._ [bởi Ludwid] " |
|||
|
|||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, và Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div> |
|||
|
|||
--- |
|||
|
|||
"_**Netflix** vui mừng thông báo việc phát hành framework mã nguồn mở của chúng tôi cho *quản lí khủng hoảng* tập trung: **Dispatch**! [xây dựng với **FastAPI**]_" |
|||
|
|||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div> |
|||
|
|||
--- |
|||
|
|||
"_Tôi vô cùng hào hứng về **FastAPI**. Nó rất thú vị_" |
|||
|
|||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div> |
|||
|
|||
--- |
|||
|
|||
"_Thành thật, những gì bạn đã xây dựng nhìn siêu chắc chắn và bóng bẩy. Theo nhiều cách, nó là những gì tôi đã muốn Hug trở thành - thật sự truyền cảm hứng để thấy ai đó xây dựng nó._" |
|||
|
|||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - người tạo ra <strong><a href="https://www.hug.rest/" target="_blank">Hug</a></strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div> |
|||
|
|||
--- |
|||
|
|||
"_Nếu bạn đang tìm kiếm một **framework hiện đại** để xây dựng một REST APIs, thử xem xét **FastAPI** [...] Nó nhanh, dễ dùng và dễ học [...]_" |
|||
|
|||
"_Chúng tôi đã chuyển qua **FastAPI cho **APIs** của chúng tôi [...] Tôi nghĩ bạn sẽ thích nó [...]_" |
|||
|
|||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div> |
|||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong>nhà sáng lập <a href="https://explosion.ai" target="_blank">Explosion AI</a> - người tạo ra <a href="https://spacy.io" target="_blank">spaCy</a></strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div> |
|||
|
|||
--- |
|||
|
|||
"_Nếu ai đó đang tìm cách xây dựng sản phẩm API bằng Python, tôi sẽ đề xuất **FastAPI**. Nó **được thiết kế đẹp đẽ**, **sử dụng đơn giản** và **có khả năng mở rộng cao**, nó đã trở thành một **thành phần quan trọng** trong chiến lược phát triển API của chúng tôi và đang thúc đẩy nhiều dịch vụ và mảng tự động hóa như Kỹ sư TAC ảo của chúng tôi._" |
|||
|
|||
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div> |
|||
|
|||
--- |
|||
|
|||
## **Typer**, giao diện dòng lệnh của FastAPI |
|||
|
|||
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a> |
|||
|
|||
Nếu bạn đang xây dựng một <abbr title="Giao diện dòng lệnh">CLI</abbr> - ứng dụng được sử dụng trong giao diện dòng lệnh, xem về <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>. |
|||
|
|||
**Typer** là một người anh em của FastAPI. Và nó được dự định trở thành **giao diện dòng lệnh cho FastAPI**. ⌨️ 🚀 |
|||
|
|||
## Yêu cầu |
|||
|
|||
Python 3.7+ |
|||
|
|||
FastAPI đứng trên vai những người khổng lồ: |
|||
|
|||
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> cho phần web. |
|||
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> cho phần data. |
|||
|
|||
## Cài đặt |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ pip install fastapi |
|||
|
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Bạn cũng sẽ cần một ASGI server cho production như <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> hoặc <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>. |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ pip install "uvicorn[standard]" |
|||
|
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
## Ví dụ |
|||
|
|||
### Khởi tạo |
|||
|
|||
* Tạo một tệp tin `main.py` như sau: |
|||
|
|||
```Python |
|||
from typing import Union |
|||
|
|||
from fastapi import FastAPI |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
@app.get("/") |
|||
def read_root(): |
|||
return {"Hello": "World"} |
|||
|
|||
|
|||
@app.get("/items/{item_id}") |
|||
def read_item(item_id: int, q: Union[str, None] = None): |
|||
return {"item_id": item_id, "q": q} |
|||
``` |
|||
|
|||
<details markdown="1"> |
|||
<summary>Hoặc sử dụng <code>async def</code>...</summary> |
|||
|
|||
Nếu code của bạn sử dụng `async` / `await`, hãy sử dụng `async def`: |
|||
|
|||
```Python hl_lines="9 14" |
|||
from typing import Union |
|||
|
|||
from fastapi import FastAPI |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
@app.get("/") |
|||
async def read_root(): |
|||
return {"Hello": "World"} |
|||
|
|||
|
|||
@app.get("/items/{item_id}") |
|||
async def read_item(item_id: int, q: Union[str, None] = None): |
|||
return {"item_id": item_id, "q": q} |
|||
``` |
|||
|
|||
**Lưu ý**: |
|||
|
|||
Nếu bạn không biết, xem phần _"In a hurry?"_ về <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` và `await` trong tài liệu này</a>. |
|||
|
|||
</details> |
|||
|
|||
### Chạy ứng dụng |
|||
|
|||
Chạy server như sau: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ uvicorn main:app --reload |
|||
|
|||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) |
|||
INFO: Started reloader process [28720] |
|||
INFO: Started server process [28722] |
|||
INFO: Waiting for application startup. |
|||
INFO: Application startup complete. |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
<details markdown="1"> |
|||
<summary>Về lệnh <code>uvicorn main:app --reload</code>...</summary> |
|||
|
|||
Lệnh `uvicorn main:app` tham chiếu tới những thành phần sau: |
|||
|
|||
* `main`: tệp tin `main.py` (một Python "module"). |
|||
* `app`: object được tạo trong tệp tin `main.py` tại dòng `app = FastAPI()`. |
|||
* `--reload`: chạy lại server sau khi code thay đổi. Chỉ sử dụng trong quá trình phát triển. |
|||
|
|||
</details> |
|||
|
|||
### Kiểm tra |
|||
|
|||
Mở trình duyệt của bạn tại <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>. |
|||
|
|||
Bạn sẽ thấy một JSON response: |
|||
|
|||
```JSON |
|||
{"item_id": 5, "q": "somequery"} |
|||
``` |
|||
|
|||
Bạn đã sẵn sàng để tạo một API như sau: |
|||
|
|||
* Nhận HTTP request với _đường dẫn_ `/` và `/items/{item_id}`. |
|||
* Cả hai _đường dẫn_ sử dụng <em>toán tử</em> `GET` (cũng đươc biết đến là _phương thức_ HTTP). |
|||
* _Đường dẫn_ `/items/{item_id}` có một _tham số đường dẫn_ `item_id`, nó là một tham số kiểu `int`. |
|||
* _Đường dẫn_ `/items/{item_id}` có một _tham số query string_ `q`, nó là một tham số tùy chọn kiểu `str`. |
|||
|
|||
### Tài liệu tương tác API |
|||
|
|||
Truy cập <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>. |
|||
|
|||
Bạn sẽ thấy tài liệu tương tác API được tạo tự động (cung cấp bởi <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>): |
|||
|
|||
 |
|||
|
|||
### Tài liệu API thay thế |
|||
|
|||
Và bây giờ, hãy truy cập tới <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>. |
|||
|
|||
Bạn sẽ thấy tài liệu được thay thế (cung cấp bởi <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>): |
|||
|
|||
 |
|||
|
|||
## Nâng cấp ví dụ |
|||
|
|||
Bây giờ sửa tệp tin `main.py` để nhận body từ một request `PUT`. |
|||
|
|||
Định nghĩa của body sử dụng kiểu dữ liệu chuẩn của Python, cảm ơn Pydantic. |
|||
|
|||
```Python hl_lines="4 9-12 25-27" |
|||
from typing import Union |
|||
|
|||
from fastapi import FastAPI |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class Item(BaseModel): |
|||
name: str |
|||
price: float |
|||
is_offer: Union[bool, None] = None |
|||
|
|||
|
|||
@app.get("/") |
|||
def read_root(): |
|||
return {"Hello": "World"} |
|||
|
|||
|
|||
@app.get("/items/{item_id}") |
|||
def read_item(item_id: int, q: Union[str, None] = None): |
|||
return {"item_id": item_id, "q": q} |
|||
|
|||
|
|||
@app.put("/items/{item_id}") |
|||
def update_item(item_id: int, item: Item): |
|||
return {"item_name": item.name, "item_id": item_id} |
|||
``` |
|||
|
|||
Server nên tự động chạy lại (bởi vì bạn đã thêm `--reload` trong lệnh `uvicorn` ở trên). |
|||
|
|||
### Nâng cấp tài liệu API |
|||
|
|||
Bây giờ truy cập tới <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>. |
|||
|
|||
* Tài liệu API sẽ được tự động cập nhật, bao gồm body mới: |
|||
|
|||
 |
|||
|
|||
* Click vào nút "Try it out", nó cho phép bạn điền những tham số và tương tác trực tiếp với API: |
|||
|
|||
 |
|||
|
|||
* Sau khi click vào nút "Execute", giao diện người dùng sẽ giao tiếp với API của bạn bao gồm: gửi các tham số, lấy kết quả và hiển thị chúng trên màn hình: |
|||
|
|||
 |
|||
|
|||
### Nâng cấp tài liệu API thay thế |
|||
|
|||
Và bây giờ truy cập tới <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>. |
|||
|
|||
* Tài liệu thay thế cũng sẽ phản ánh tham số và body mới: |
|||
|
|||
 |
|||
|
|||
### Tóm lại |
|||
|
|||
Bạn khai báo **một lần** kiểu dữ liệu của các tham số, body, etc là các tham số của hàm số. |
|||
|
|||
Bạn định nghĩa bằng cách sử dụng các kiểu dữ liệu chuẩn của Python. |
|||
|
|||
Bạn không phải học một cú pháp mới, các phương thức và class của một thư viện cụ thể nào. |
|||
|
|||
Chỉ cần sử dụng các chuẩn của **Python 3.7+**. |
|||
|
|||
Ví dụ, với một tham số kiểu `int`: |
|||
|
|||
```Python |
|||
item_id: int |
|||
``` |
|||
|
|||
hoặc với một model `Item` phức tạp hơn: |
|||
|
|||
```Python |
|||
item: Item |
|||
``` |
|||
|
|||
...và với định nghĩa đơn giản đó, bạn có được: |
|||
|
|||
* Sự hỗ trợ từ các trình soạn thảo, bao gồm: |
|||
* Completion. |
|||
* Kiểm tra kiểu dữ liệu. |
|||
* Kiểm tra kiểu dữ liệu: |
|||
* Tự động sinh lỗi rõ ràng khi dữ liệu không hợp lệ . |
|||
* Kiểm tra JSON lồng nhau . |
|||
* <abbr title="cũng được biết tới như: serialization, parsing, marshalling">Chuyển đổi</abbr> dữ liệu đầu vào: tới từ network sang dữ liệu kiểu Python. Đọc từ: |
|||
* JSON. |
|||
* Các tham số trong đường dẫn. |
|||
* Các tham số trong query string. |
|||
* Cookies. |
|||
* Headers. |
|||
* Forms. |
|||
* Files. |
|||
* <abbr title="cũng được biết tới như: serialization, parsing, marshalling">Chuyển đổi</abbr> dữ liệu đầu ra: chuyển đổi từ kiểu dữ liệu Python sang dữ liệu network (như JSON): |
|||
* Chuyển đổi kiểu dữ liệu Python (`str`, `int`, `float`, `bool`, `list`,...). |
|||
* `datetime` objects. |
|||
* `UUID` objects. |
|||
* Database models. |
|||
* ...và nhiều hơn thế. |
|||
* Tự động tạo tài liệu tương tác API, bao gồm 2 giao diện người dùng: |
|||
* Swagger UI. |
|||
* ReDoc. |
|||
|
|||
--- |
|||
|
|||
Quay trở lại ví dụ trước, **FastAPI** sẽ thực hiện: |
|||
|
|||
* Kiểm tra xem có một `item_id` trong đường dẫn với các request `GET` và `PUT` không? |
|||
* Kiểm tra xem `item_id` có phải là kiểu `int` trong các request `GET` và `PUT` không? |
|||
* Nếu không, client sẽ thấy một lỗi rõ ràng và hữu ích. |
|||
* Kiểm tra xem nếu có một tham số `q` trong query string (ví dụ như `http://127.0.0.1:8000/items/foo?q=somequery`) cho request `GET`. |
|||
* Tham số `q` được định nghĩa `= None`, nó là tùy chọn. |
|||
* Nếu không phải `None`, nó là bắt buộc (như body trong trường hợp của `PUT`). |
|||
* Với request `PUT` tới `/items/{item_id}`, đọc body như JSON: |
|||
* Kiểm tra xem nó có một thuộc tính bắt buộc kiểu `str` là `name` không? |
|||
* Kiểm tra xem nó có một thuộc tính bắt buộc kiểu `float` là `price` không? |
|||
* Kiểm tra xem nó có một thuộc tính tùy chọn là `is_offer` không? Nếu có, nó phải có kiểu `bool`. |
|||
* Tất cả những kiểm tra này cũng được áp dụng với các JSON lồng nhau. |
|||
* Chuyển đổi tự động các JSON object đến và JSON object đi. |
|||
* Tài liệu hóa mọi thứ với OpenAPI, tài liệu đó có thể được sử dụng bởi: |
|||
|
|||
* Các hệ thống tài liệu có thể tương tác. |
|||
* Hệ thống sinh code tự động, cho nhiều ngôn ngữ lập trình. |
|||
* Cung cấp trực tiếp 2 giao diện web cho tài liệu tương tác |
|||
|
|||
--- |
|||
|
|||
Chúng tôi chỉ trình bày những thứ cơ bản bên ngoài, nhưng bạn đã hiểu cách thức hoạt động của nó. |
|||
|
|||
Thử thay đổi dòng này: |
|||
|
|||
```Python |
|||
return {"item_name": item.name, "item_id": item_id} |
|||
``` |
|||
|
|||
...từ: |
|||
|
|||
```Python |
|||
... "item_name": item.name ... |
|||
``` |
|||
|
|||
...sang: |
|||
|
|||
```Python |
|||
... "item_price": item.price ... |
|||
``` |
|||
|
|||
...và thấy trình soạn thảo của bạn nhận biết kiểu dữ liệu và gợi ý hoàn thiện các thuộc tính. |
|||
|
|||
 |
|||
|
|||
Ví dụ hoàn chỉnh bao gồm nhiều tính năng hơn, xem <a href="https://fastapi.tiangolo.com/tutorial/">Tutorial - User Guide</a>. |
|||
|
|||
|
|||
**Cảnh báo tiết lỗ**: Tutorial - User Guide: |
|||
|
|||
* Định nghĩa **tham số** từ các nguồn khác nhau như: **headers**, **cookies**, **form fields** và **files**. |
|||
* Cách thiết lập **các ràng buộc cho validation** như `maximum_length` hoặc `regex`. |
|||
* Một hệ thống **<abbr title="cũng được biết đến như components, resources, providers, services, injectables">Dependency Injection</abbr> vô cùng mạnh mẽ và dễ dàng sử dụng. |
|||
* Bảo mật và xác thực, hỗ trợ **OAuth2**(với **JWT tokens**) và **HTTP Basic**. |
|||
* Những kĩ thuật nâng cao hơn (nhưng tương đối dễ) để định nghĩa **JSON models lồng nhau** (cảm ơn Pydantic). |
|||
* Tích hợp **GraphQL** với <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> và các thư viện khác. |
|||
* Nhiều tính năng mở rộng (cảm ơn Starlette) như: |
|||
* **WebSockets** |
|||
* kiểm thử vô cùng dễ dàng dựa trên HTTPX và `pytest` |
|||
* **CORS** |
|||
* **Cookie Sessions** |
|||
* ...và nhiều hơn thế. |
|||
|
|||
## Hiệu năng |
|||
|
|||
Independent TechEmpower benchmarks cho thấy các ứng dụng **FastAPI** chạy dưới Uvicorn là <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">một trong những Python framework nhanh nhất</a>, chỉ đứng sau Starlette và Uvicorn (được sử dụng bên trong FastAPI). (*) |
|||
|
|||
Để hiểu rõ hơn, xem phần <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>. |
|||
|
|||
## Các dependency tùy chọn |
|||
|
|||
Sử dụng bởi Pydantic: |
|||
|
|||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - <abbr title="chuyển dổi string từ HTTP request sang dữ liệu Python">"Parse"</abbr> JSON nhanh hơn. |
|||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - cho email validation. |
|||
|
|||
Sử dụng Starlette: |
|||
|
|||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Bắt buộc nếu bạn muốn sử dụng `TestClient`. |
|||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Bắt buộc nếu bạn muốn sử dụng cấu hình template engine mặc định. |
|||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Bắt buộc nếu bạn muốn hỗ trợ <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, form với `request.form()`. |
|||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Bắt buộc để hỗ trợ `SessionMiddleware`. |
|||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Bắt buộc để hỗ trợ `SchemaGenerator` cho Starlette (bạn có thể không cần nó trong FastAPI). |
|||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Bắt buộc nếu bạn muốn sử dụng `UJSONResponse`. |
|||
|
|||
Sử dụng bởi FastAPI / Starlette: |
|||
|
|||
* <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - Server để chạy ứng dụng của bạn. |
|||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Bắt buộc nếu bạn muốn sử dụng `ORJSONResponse`. |
|||
|
|||
Bạn có thể cài đặt tất cả những dependency trên với `pip install "fastapi[all]"`. |
|||
|
|||
## Giấy phép |
|||
|
|||
Dự án này được cấp phép dưới những điều lệ của giấy phép MIT. |
@ -0,0 +1 @@ |
|||
INHERIT: ../en/mkdocs.yml |
@ -0,0 +1,126 @@ |
|||
# 后台任务 |
|||
|
|||
你可以定义在返回响应后运行的后台任务。 |
|||
|
|||
这对需要在请求之后执行的操作很有用,但客户端不必在接收响应之前等待操作完成。 |
|||
|
|||
包括这些例子: |
|||
|
|||
* 执行操作后发送的电子邮件通知: |
|||
* 由于连接到电子邮件服务器并发送电子邮件往往很“慢”(几秒钟),您可以立即返回响应并在后台发送电子邮件通知。 |
|||
* 处理数据: |
|||
* 例如,假设您收到的文件必须经过一个缓慢的过程,您可以返回一个"Accepted"(HTTP 202)响应并在后台处理它。 |
|||
|
|||
## 使用 `BackgroundTasks` |
|||
|
|||
首先导入 `BackgroundTasks` 并在 *路径操作函数* 中使用类型声明 `BackgroundTasks` 定义一个参数: |
|||
|
|||
```Python hl_lines="1 13" |
|||
{!../../../docs_src/background_tasks/tutorial001.py!} |
|||
``` |
|||
|
|||
**FastAPI** 会创建一个 `BackgroundTasks` 类型的对象并作为该参数传入。 |
|||
|
|||
## 创建一个任务函数 |
|||
|
|||
创建要作为后台任务运行的函数。 |
|||
|
|||
它只是一个可以接收参数的标准函数。 |
|||
|
|||
它可以是 `async def` 或普通的 `def` 函数,**FastAPI** 知道如何正确处理。 |
|||
|
|||
在这种情况下,任务函数将写入一个文件(模拟发送电子邮件)。 |
|||
|
|||
由于写操作不使用 `async` 和 `await`,我们用普通的 `def` 定义函数: |
|||
|
|||
```Python hl_lines="6-9" |
|||
{!../../../docs_src/background_tasks/tutorial001.py!} |
|||
``` |
|||
|
|||
## 添加后台任务 |
|||
|
|||
在你的 *路径操作函数* 里,用 `.add_task()` 方法将任务函数传到 *后台任务* 对象中: |
|||
|
|||
```Python hl_lines="14" |
|||
{!../../../docs_src/background_tasks/tutorial001.py!} |
|||
``` |
|||
|
|||
`.add_task()` 接收以下参数: |
|||
|
|||
* 在后台运行的任务函数(`write_notification`)。 |
|||
* 应按顺序传递给任务函数的任意参数序列(`email`)。 |
|||
* 应传递给任务函数的任意关键字参数(`message="some notification"`)。 |
|||
|
|||
## 依赖注入 |
|||
|
|||
使用 `BackgroundTasks` 也适用于依赖注入系统,你可以在多个级别声明 `BackgroundTasks` 类型的参数:在 *路径操作函数* 里,在依赖中(可依赖),在子依赖中,等等。 |
|||
|
|||
**FastAPI** 知道在每种情况下该做什么以及如何复用同一对象,因此所有后台任务被合并在一起并且随后在后台运行: |
|||
|
|||
=== "Python 3.10+" |
|||
|
|||
```Python hl_lines="13 15 22 25" |
|||
{!> ../../../docs_src/background_tasks/tutorial002_an_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python hl_lines="13 15 22 25" |
|||
{!> ../../../docs_src/background_tasks/tutorial002_an_py39.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python hl_lines="14 16 23 26" |
|||
{!> ../../../docs_src/background_tasks/tutorial002_an.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10+ 没Annotated" |
|||
|
|||
!!! tip |
|||
尽可能选择使用 `Annotated` 的版本。 |
|||
|
|||
```Python hl_lines="11 13 20 23" |
|||
{!> ../../../docs_src/background_tasks/tutorial002_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+ 没Annotated" |
|||
|
|||
!!! tip |
|||
尽可能选择使用 `Annotated` 的版本。 |
|||
|
|||
```Python hl_lines="13 15 22 25" |
|||
{!> ../../../docs_src/background_tasks/tutorial002.py!} |
|||
``` |
|||
|
|||
该示例中,信息会在响应发出 *之后* 被写到 `log.txt` 文件。 |
|||
|
|||
如果请求中有查询,它将在后台任务中写入日志。 |
|||
|
|||
然后另一个在 *路径操作函数* 生成的后台任务会使用路径参数 `email` 写入一条信息。 |
|||
|
|||
## 技术细节 |
|||
|
|||
`BackgroundTasks` 类直接来自 <a href="https://www.starlette.io/background/" class="external-link" target="_blank">`starlette.background`</a>。 |
|||
|
|||
它被直接导入/包含到FastAPI以便你可以从 `fastapi` 导入,并避免意外从 `starlette.background` 导入备用的 `BackgroundTask` (后面没有 `s`)。 |
|||
|
|||
通过仅使用 `BackgroundTasks` (而不是 `BackgroundTask`),使得能将它作为 *路径操作函数* 的参数 ,并让**FastAPI**为您处理其余部分, 就像直接使用 `Request` 对象。 |
|||
|
|||
在FastAPI中仍然可以单独使用 `BackgroundTask`,但您必须在代码中创建对象,并返回包含它的Starlette `Response`。 |
|||
|
|||
更多细节查看 <a href="https://www.starlette.io/background/" class="external-link" target="_blank">Starlette's official docs for Background Tasks</a>. |
|||
|
|||
## 告诫 |
|||
|
|||
如果您需要执行繁重的后台计算,并且不一定需要由同一进程运行(例如,您不需要共享内存、变量等),那么使用其他更大的工具(如 <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>)可能更好。 |
|||
|
|||
它们往往需要更复杂的配置,即消息/作业队列管理器,如RabbitMQ或Redis,但它们允许您在多个进程中运行后台任务,甚至是在多个服务器中。 |
|||
|
|||
要查看示例,查阅 [Project Generators](../project-generation.md){.internal-link target=_blank},它们都包括已经配置的Celery。 |
|||
|
|||
但是,如果您需要从同一个**FastAPI**应用程序访问变量和对象,或者您需要执行小型后台任务(如发送电子邮件通知),您只需使用 `BackgroundTasks` 即可。 |
|||
|
|||
## 回顾 |
|||
|
|||
导入并使用 `BackgroundTasks` 通过 *路径操作函数* 中的参数和依赖项来添加后台任务。 |
Loading…
Reference in new issue